leetcode解题思路分析(四)22-28题

淡淡的烟草味﹌ 2023-06-24 10:21 100阅读 0赞
  1. 括号生成
    给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

很容易想到采用回溯法解决该题,通过画出树分析递归规律可得如下代码

  1. class Solution {
  2. public:
  3. void backtrace(int left, int right, int n, string& s, vector<string>& res) {
  4. if (left == n && right == n) {
  5. res.push_back(s);
  6. return;
  7. }
  8. if (left < n) {
  9. s += "(";
  10. backtrace(left + 1, right, n, s, res);
  11. s.pop_back();
  12. }
  13. if (right < left) {
  14. s += ")";
  15. backtrace(left, right + 1, n, s, res);
  16. s.pop_back();
  17. }
  18. }
  19. vector<string> generateParenthesis(int n) {
  20. vector<string> res;
  21. string s;
  22. backtrace(0, 0, n, s, res);
  23. return res;
  24. }
  25. };
  1. 合并k个排序链表
    合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

本题在做过合并2个链表之后就变得很简单:采用二分法逐个合并直至剩下一个即可

  1. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
  2. class Solution {
  3. public:
  4. ListNode* mergeKLists(vector<ListNode*>& lists) {
  5. int size = lists.size();
  6. if (size == 0) {
  7. return nullptr;
  8. }
  9. if (size == 1) {
  10. return lists[0];
  11. }
  12. while (size > 1)
  13. {
  14. for (int i = 0; i < size / 2; i++)
  15. {
  16. lists[i] = mergeTwoLists(lists[i], lists[i + size / 2]);
  17. }
  18. if (size % 2)
  19. {
  20. lists[size / 2] = lists[size - 1];
  21. size = size / 2 + 1;
  22. }
  23. else
  24. {
  25. size = size / 2;
  26. }
  27. }
  28. return lists[0];
  29. }
  30. ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
  31. ListNode *preHead, *ptr;
  32. preHead = new ListNode(-1);
  33. ptr = preHead;
  34. while (l1 != NULL && l2 != NULL)
  35. {
  36. if (l1->val <= l2->val)
  37. {
  38. ptr->next = l1;
  39. l1 = l1->next;
  40. }
  41. else
  42. {
  43. ptr->next = l2;
  44. l2 = l2->next;
  45. }
  46. ptr = ptr->next;
  47. }
  48. ptr->next = (l1 == NULL? l2 : l1);
  49. return preHead->next;
  50. }
  51. };
  1. 两两交换链表中的节点
    给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
    你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

非常简单的链表操作题

  1. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
  2. class Solution {
  3. public:
  4. ListNode* swapPairs(ListNode* head) {
  5. ListNode *preHead = new ListNode(-1);
  6. ListNode *tmp, *ahead;
  7. preHead->next = head;
  8. ahead = preHead;
  9. while (head != NULL && head->next != NULL)
  10. {
  11. tmp = head->next;
  12. ahead->next = tmp;
  13. head->next = tmp->next;
  14. tmp->next = head;
  15. ahead = head;
  16. head = head->next;
  17. }
  18. return preHead->next;
  19. }
  20. };
  1. K 个一组翻转链表
    给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
    k 是一个正整数,它的值小于或等于链表的长度。
    如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

本题是24题的提高,为了翻转K个一组,则需要遍历k个,让每一个指针指向前一个节点,然后最前面的节点指向下一组的开始。因此考虑迭代解决

  1. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
  2. class Solution {
  3. public:
  4. ListNode* reverseKGroup(ListNode* head, int k) {
  5. int d = 0;
  6. auto node = head;
  7. while (node != NULL) {
  8. if (++d >= k) break;
  9. node = node->next;
  10. }
  11. if (d < k) return head;
  12. ListNode* prev = NULL;
  13. ListNode* curr = head;
  14. for (int i = 0; i < k; ++i) {
  15. auto node = curr->next;
  16. curr->next = prev;
  17. prev = curr;
  18. curr = node;
  19. }
  20. head->next = reverseKGroup(curr, k);
  21. return prev;
  22. }
  23. };
  1. 删除排序数组中的重复项
    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
    不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

对已经排序好的数组,我们采取双指针法,检测到不同的元素再和相同元素第二位进行互换,然后指针前进即可

  1. class Solution {
  2. public:
  3. int removeDuplicates(vector<int>& nums) {
  4. if (nums.size() == 0)
  5. return 0;
  6. int i = 0;
  7. for (int j = 1; j < nums.size(); j++)
  8. {
  9. if (nums[j] != nums[i])
  10. {
  11. i++;
  12. nums[i] = nums[j];
  13. }
  14. }
  15. return i + 1;
  16. }
  17. };
  1. 移除元素
    给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
    元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

本题可以采取和上题类似的策略:对每个重复的元素则赋值给后面不同的元素。但是注意这里需要保证不会重复赋值,因此比较可行的方法是进行节点的交换

  1. class Solution {
  2. public:
  3. int removeElement(vector<int>& nums, int val) {
  4. int size = nums.size();
  5. if (size == 0)
  6. return 0;
  7. int ptr = 0;
  8. int end = 0;
  9. for (int i = 0; i < size; i++)
  10. {
  11. if (nums[i] == val)
  12. {
  13. if (end < i)
  14. end = i;
  15. if (end == size)
  16. return ptr;
  17. while (nums[end] == val)
  18. {
  19. end++;
  20. if (end == size)
  21. {
  22. return ptr;
  23. }
  24. }
  25. int tmp = nums[ptr];
  26. nums[ptr] = nums[end];
  27. nums[end] = tmp;
  28. end++;
  29. ptr++;
  30. }
  31. else
  32. {
  33. ptr++;
  34. }
  35. }
  36. return ptr;
  37. }
  38. };

但是上述做法的代码看起来颇为繁琐,其实可以更进一步的简化思想:我们只要每次把不同于val的值赋值在前列就可以完成了

  1. class Solution {
  2. public:
  3. int removeElement(vector<int>& nums, int val) {
  4. if (nums.size() == 0)
  5. return 0;
  6. int i = 0;
  7. for (int j = 0; j < nums.size(); j++)
  8. {
  9. if (nums[j] != val)
  10. {
  11. nums[i] = nums[j];
  12. i++;
  13. }
  14. }
  15. return i;
  16. }
  17. };

还有没有办法优化性能呢?是有的。上述方法存在一个普遍问题:对于检索过的val的值最后还会检查一遍。但是其实是不需要检查的:我们可以将重复的值替换为末尾的值, 并且不再检查它

  1. class Solution {
  2. public:
  3. int removeElement(vector<int>& nums, int val) {
  4. int i = 0;
  5. int n = nums.size();
  6. while (i < n) {
  7. if (nums[i] == val) {
  8. nums[i] = nums[n - 1];
  9. // reduce array size by one
  10. n--;
  11. } else {
  12. i++;
  13. }
  14. }
  15. return n;
  16. }
  17. };
  1. 实现 strStr()
    给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

本题采用暴力检索的方式:找到一个相同元素则开始继续后续检查,如果检查完不一样则继续向后检索

  1. class Solution {
  2. public:
  3. int strStr(string haystack, string needle) {
  4. int i = 0, j = 0;
  5. while(i < haystack.size() && j < needle.size())
  6. {
  7. if(haystack[i] == needle[j])
  8. {
  9. i++;
  10. j++;
  11. }
  12. else
  13. {
  14. i = i - j +1 ;
  15. j = 0;
  16. }
  17. }
  18. if(j == needle.size())
  19. return i - j;
  20. return -1;
  21. }
  22. };

发表评论

表情:
评论列表 (有 0 条评论,100人围观)

还没有评论,来说两句吧...

相关阅读