zoukankan      html  css  js  c++  java
  • 快慢指针

    快慢指针可用于判断链表中是否有环。

    Floyd判圈算法(龟兔赛跑算法)

    假设乌龟和兔子在链表上跑步,兔子跑得快,乌龟跑的慢,如果链表中没有环,那么兔子将会一直在乌龟前面,直到终点;反之,如果链表中存在环,那么兔子一定会和乌龟再次相遇。

    我们可以设定两个指针,快指针fast指代兔子,慢指针slow指代乌龟,假设快指针一次走两步,慢指针一次走一步。

    初始化时有两种方法:

    1.fast = head.next , slow = head;用fast != slow当作循环条件

    2.fast = slow = head,使用do-while()循环。

    例题:

    1.环形链表(https://leetcode-cn.com/problems/linked-list-cycle/)

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

    思路:快慢指针模板题

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

    2.环形链表 II (https://leetcode-cn.com/problems/linked-list-cycle-ii/)

    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

    思路:跟上一题相比多了一个地方,需要找到入环点。我们设以下几个变量:

    a:表示头节点到入环点之间的距离

    b:慢指针在圈中所走的距离

    c:整圈距离减去b所走距离的剩余距离

    由此可以得到快慢指针相遇时,快指针所走距离:a+n*(a+c)+b(按第一种方法,快指针所走距离需要减1,因为fast=head->next),慢指针所走距离:a+b

    而快指针的速度是慢指针的两倍,故快指针所走距离也是慢指针所走距离的两倍

    a+n(b+c)+b = 2(a+b) => a = (n-1)b + nc

    由此我们可以得出,当慢指针从相遇得地方再走c个距离,就会走到入环点,我们另建一个指针ptr=head,当ptr == slow时,即为入环点

    class Solution {
    public:
        ListNode *detectCycle(ListNode *head) {
            if(head == nullptr || head->next == nullptr) return nullptr;
            ListNode * fast = head->next,*slow = head;
            while(slow != fast){
                if(fast == nullptr || fast->next == nullptr) return nullptr;
                slow = slow->next;
                fast = fast->next->next;
            }
            // cout<<"********
    ";
            ListNode* ptr = head;
            slow=slow->next; //使用方法一需要改的地方
            while(ptr != slow){
                ptr = ptr->next;
                slow = slow->next;
            }
            return ptr;
        }
    };
    

    3.快乐数(https://leetcode-cn.com/problems/happy-number/)

    编写一个算法来判断一个数 n 是不是快乐数。

    思路:通过模拟可以发现不管几位数最后都会小于243,然后结果不是归为1,就是会陷入一个循环当中。因此,我们可以使用快慢指针判断是否有环的存在

    class Solution {
    public:
        int getNum(int n){
            int sum = 0;
            while(n>0){
                int x = n%10;
                n /= 10;
                sum += (x*x);
            }
            return sum;
        }
        bool isHappy(int n) {
            if(n==1) return true;
            int slow = n;
            int fast = getNum(n);
            // cout<<fast<<endl;
            while(fast!=1 && slow != fast){
                slow = getNum(slow);
                fast = getNum(getNum(fast));
            }
            return fast==1;
        }
    };
    

    4.链表的中间结点(https://leetcode-cn.com/problems/middle-of-the-linked-list/)

    给定一个头结点为 head 的非空单链表,返回链表的中间结点。

    如果有两个中间结点,则返回第二个中间结点。

    思路:这是快慢指针最简单的应用场景了,当快指针到达终点时,慢指针刚好到达中点(终点中点不一样)

    class Solution {
    public:
        ListNode* middleNode(ListNode* head) {
            ListNode* fast = head;
            ListNode* slow = head;
            if(head->next == nullptr) return head;
            do{
                slow = slow->next;
                fast = fast->next->next;
                // cout<<slow->val<<' '<<fast->val<<endl;
            }while(fast != nullptr && fast->next != nullptr);
            // cout<<fast->val<<' '<<fast->next->val<<endl;
            return slow;
        }
    };
    
    
    七月在野,八月在宇,九月在户,十月蟋蟀入我床下
  • 相关阅读:
    你不一定懂的cpu显示信息
    WebService之nginx+(php-fpm)结构模型剖析及优化
    Linux企业运维人员最常用150个命令汇总
    企业级Tomcat部署实践及安全调优
    CentOS 7.X 系统安装及优化
    Linux Sysstat性能监控工具安装及常见8个命令使用例子
    Linux监控命令整理(top,free,vmstat,iostat,mpstat,sar,netstat)
    Tomcat+redis+nginx配置
    循环控制-链表删除结点
    循环控制-链表反转(与创建链表)
  • 原文地址:https://www.cnblogs.com/voids5/p/14361410.html
Copyright © 2011-2022 走看看