首页 > 编程知识 正文

leetcode 快慢指针,双指针 leetcode

时间:2023-05-04 14:19:55 阅读:195038 作者:4353

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录 前言一、什么是快慢指针二、例题体现三、数组模拟链表总结


前言

在leetcode刷题经常会碰到快慢指针问题,本文将快慢指针的题目总结模板

一、什么是快慢指针

快慢指针其实就是定义两个指针 fast 和 slow 然后让fast每次都比slow走快一步。快慢指针常见在链表题目,快慢指针的出现让我们能更好的定位链表中的结点位置,也可以在一些特定数组中模拟成链表,简化题目难度。

二、例题体现

在leetcode中有这么一个题目,求环形链表的位置,题目链接环形链表II
这个题目就是典型的快慢指针题型,在这个题目中有两个难点,第一个就是判断链表有无环,在链表有无环判断就是用快慢指针,fast每次走两步,slow每次走一步,如果fast会与slow相遇,那么就证明链表中存环,第二个难点就是找到出现环路的结点。

那环路结点怎么求呢?让我们先来分析下在fast和slow在图中走的路线(图片来源leetcode官网),首先我们假设链表中环外部分的长度为 a。slow 指针进入环后,又走了 b 的距离与 fast 相遇,此时fast已经走了n圈了,所以slow走的距离是 a + b,fast走了 a + (n+1)b + nc 又因为,fast每次比slow多走一部,所以2slow==fast 则 我们可以推出 a + (n+1)b + nc == 2(a+b)

所以现在我们可以推出 a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c),下面图是这个推导过程

有了 a=c+(n-1)(b+c) 的等量关系,我们会发现:从相遇点到入环点的距离加上 n−1 圈的环长,恰好等于从链表头部到入环点的距离。
因此,当发现slow 与 fast 相遇时 ,只需要让fast = head ,让fast从头开始走,他们再次相遇的点就是环形结点。

class Solution {public: ListNode *detectCycle(ListNode *head) { ListNode *fast = head,*slow = head; do{ if(!fast||!fast->next) return NULL; fast = fast->next->next; slow = slow->next; }while(fast!=slow); fast = head; while(fast!=slow){ fast = fast->next; slow = slow->next; } return fast; }};

下面是一些类似题目,开始练手吧!!
环形链表I

class Solution {public: bool hasCycle(ListNode *head) { ListNode *fast = head,*slow = head; do{ if(!fast||!fast->next) return false; fast = fast->next->next; slow = slow->next; }while(fast!=slow); return true; }};

链表的中间结点

class Solution {public: ListNode* middleNode(ListNode* head) { ListNode *fast = head,*slow = head; while(fast&&fast->next){ fast = fast->next->next; slow = slow->next; } return slow; }};

剑指offer22.链表中倒数第k个结点

class Solution {public: ListNode* getKthFromEnd(ListNode* head, int k) { ListNode *fast = head,*slow = head; while(fast&&k--){ fast = fast->next; } while(fast){ fast = fast->next; slow = slow->next; } return slow; }};

快慢指针+反转链表

class Solution {public: ListNode *reverseList(ListNode *head){ ListNode *pre = NULL,*cur = head; while(cur) { ListNode *next = cur->next; cur->next = pre; pre = cur; cur = next; } return pre; } bool isPalindrome(ListNode* head) { if (head == NULL) { return true; } ListNode *fast = head,*slow = head; while(fast->next&&fast->next->next){ fast = fast->next->next; slow = slow->next; } ListNode *h = reverseList(slow->next); bool flag = true; ListNode* p1 = head,*p2 = h; while(flag&&p2){ if(p1->val != p2->val) flag = false; p1 = p1->next; p2 = p2->next; } slow->next = reverseList(h); return flag; }}; 三、数组模拟链表

寻找重复数

这个题目比较灵活,想要实现数组模拟链表的情况,必须满足数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),因为有重复数字的出现, 所以这个游走必然是成环的, 环的入口就是重复的元素。只是改变一下数据存储状态,思路和上面的例子完全一样。

class Solution {public: int findDuplicate(vector<int>& nums) { int fast = 0,slow = 0; while(1){ fast = nums[nums[fast]]; slow = nums[slow]; if(slow==fast){ fast = 0; while(nums[slow]!=nums[fast]){ fast = nums[fast]; slow = nums[slow]; } return nums[slow]; } } }}; 总结

本文总结了快慢指针的一些用法和延伸,希望能帮助到大家。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。