LeetCode题解——双指针(二)

青旅半醒 2023-06-09 03:57 86阅读 0赞

文章目录

      1. 合并两个有序数组
      • 直接插入
      • 双指针
      1. 环形链表
      • 双指针
      1. 通过删除字母匹配到字典里最长单词
      • 暴力匹配1
      • 暴力匹配2

88. 合并两个有序数组

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出: [1,2,2,3,5,6]

直接插入

从nums1中倒序找到nums2[i]的插入位置,然后插入,遍历所有nums2[i],即合并成功。
因为两个数组都是递增的,倒序找更快。不要小看这种方法,也是非常快的,而且空间复杂度为O(1).

  1. class Solution {
  2. public:
  3. void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
  4. int i = 0, j = m - 1;
  5. int n1 = j;
  6. while(i < n)
  7. {
  8. while(j >= 0) if(nums1[j] > nums2[i]) j--; else break;
  9. for(int k = n1; k >= j+1; k--)
  10. {
  11. nums1[k+1] = nums1[k];
  12. }
  13. nums1[j+1] = nums2[i];
  14. n1++;
  15. i++;
  16. j = n1;
  17. }
  18. }
  19. };

format_png

双指针

format_png 1

  1. class Solution {
  2. public:
  3. void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
  4. int p1 = m - 1, p2 = n - 1, p = m + n -1;
  5. while(p1 >= 0 && p2 >= 0)
  6. {
  7. nums1[p--] = (nums1[p1] < nums2[p2]) ? nums2[p2--] : nums1[p1--];
  8. }
  9. // nums2可能有剩余,将剩余的添加到nums1中。
  10. for(int i = 0; i <= p2; i++)
  11. nums1[i] = nums2[i];
  12. }
  13. };

format_png 2
从提交结果来看,第二种方法比第一种方法慢一点。

141. 环形链表

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

双指针

一快一慢指针,在有环的情况下,快指针会追上慢指针,反之无环。

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. */
  9. class Solution {
  10. public:
  11. bool hasCycle(ListNode *head) {
  12. if(head == NULL)
  13. return false;
  14. ListNode *p = head, *q = head;
  15. int flag = false;
  16. while(p->next != NULL && q->next != NULL)
  17. {
  18. p = p->next;
  19. if(q->next->next != NULL)
  20. q = q->next->next;
  21. else
  22. break;
  23. if(p == q)
  24. {
  25. flag = true;
  26. break;
  27. }
  28. }
  29. return flag;
  30. }
  31. };

524. 通过删除字母匹配到字典里最长单词

给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。

示例 1:

输入:
s = “abpcplea”, d = [“ale”,“apple”,“monkey”,“plea”]

输出:
“apple”
示例 2:

输入:
s = “abpcplea”, d = [“a”,“b”,“c”]

输出:
“a”
说明:

所有输入的字符串只包含小写字母。
字典的大小不会超过 1000。
所有输入的字符串长度不会超过 1000。

暴力匹配1

先对d按首字母大小排序,然后直接匹配,找到匹配成功字符串最长的那个。

  1. class Solution {
  2. public:
  3. string findLongestWord(string s, vector<string>& d) {
  4. sort(d.begin(), d.end());
  5. int max = 0, ans = -1, i = 0;
  6. for(i = 0; i < d.size(); ++i)
  7. {
  8. int j = 0, n = d[i].length(), k = 0, flag = 0;
  9. while(j < s.length() && k < n)
  10. {
  11. if(s[j] == d[i][k])
  12. j++, k++;
  13. else
  14. j++;
  15. if(k == n)
  16. flag = 1;
  17. }
  18. if(flag && max < n)
  19. max = n, ans = i;
  20. }
  21. return ans != -1 ? d[ans] : "";
  22. }
  23. };

暴力匹配2

不用排序,每次记录匹配成功的字符串,跟下一次比较取最长且首字母最小的那个。

  1. class Solution {
  2. public:
  3. bool is_seq(string a, string b) // 判断b是不是a的字符串
  4. {
  5. int j = 0;
  6. for(int i = 0; i < a.length() && j < b.length(); ++i)
  7. if(a[i] == b[j])
  8. j++;
  9. return j == b.length();
  10. }
  11. string findLongestWord(string s, vector<string>& d) {
  12. string max = "";
  13. for(string s1 : d)
  14. if(is_seq(s, s1) && (max.length() < s1.length() || (max.length() == s1.length() && max > s1)))
  15. max = s1;
  16. return max;
  17. }
  18. };

在这里插入图片描述

发表评论

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

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

相关阅读

    相关 【算法】指针题解

    双指针 算法解释:(直接照搬齐姐的了) 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多 个数组的多个指针。 若两个指针指向同一数组

    相关 leetcode指针(进阶)

    1. 删除排序链表中的重复元素 II 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现