leetcode刷题笔记之快慢指针

138 阅读2分钟

例题1:141. 环形链表

这道题用快慢指针是最优解法,空间复杂度为O(1),且跑出来效率最高。

/** * Definition for singly-linked list. * class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { *         val = x; *         next = null; *     } * } */public class Solution {    public boolean hasCycle(ListNode head) {        if(head==null || head.next==null) return false;        if(head.next==head) return true;        ListNode fast=head.next;        ListNode slow=head;        while(fast!=null && fast.next!=null){            fast=fast.next.next;            slow=slow.next;            if(slow==fast) return true;        }        return false;    }}
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:40.2 MB, 在所有 Java 提交中击败了22.73%的用户

例题2:142. 环形链表 II

解法1:hashmap记录被走过的节点

/** * Definition for singly-linked list. * class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { *         val = x; *         next = null; *     } * } */public class Solution {    public ListNode detectCycle(ListNode head) {        if(head==null || head.next==null) return null;        if (head.next==head) return head;        Map<ListNode,Integer> map=new HashMap<>();        map.put(head,1);        while(head.next!=null){            head=head.next;            if(map.containsKey(head)) return head;            map.put(head,1);        }        return null;    }}

解法2:快慢指针法

这题的快慢指针法十分巧妙,具体分析见:leetcode-cn.com/problems/li…

/** * Definition for singly-linked list. * class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { *         val = x; *         next = null; *     } * } */public class Solution {    public ListNode detectCycle(ListNode head) {        if(head==null || head.next==null) return null;        if (head.next==head) return head;        ListNode fast=head;        ListNode slow=head;                while(fast!=null && fast.next!=null){            fast=fast.next.next;            slow=slow.next;            if(fast==slow) break;        }        if(fast==null || fast.next==null) return null;        fast=head;        while(fast.next!=null){            if(slow==fast) return fast;            fast=fast.next;            slow=slow.next;           }        return null;    }}

第二次循环的时候要注意先判断再往前走,因为当环形链表节点为head的时候,他们在head处已经相遇了,此后的每一步都是相遇的,会出现误判。

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:39.9 MB, 在所有 Java 提交中击败了52.49%的用户

例题3:202. 快乐数

用快慢指针答题首先要知道是哪条链子,这题需要证明如果没有到1的话,对一个数取它各位平方之和这一反复操作会在一个区间内,所以快慢指针势必会相遇,证明方法见 leetcode-cn.com/problems/ha…

class Solution {    public boolean isHappy(int n) {        if(n==1) return true;        int slow=getSum(n);        int fast=getSum(slow);        while(true){            fast=getSum(fast);            fast=getSum(fast);            slow=getSum(slow);                  if(fast==slow || fast==1) break;        }        return fast==1;            }    public int getSum(int n){        int sum=0;            while(n>0){                int temp=n%10;                n=n/10;                sum+=temp*temp;            }            return sum;        }}
执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36.8 MB, 在所有 Java 提交中击败了58.29%的用户

总结:快慢指针求解

1.首先需要找到一个链,并证明求取结果和链是否存在循环有关

2.快慢指针主要采用fast和slow的步长差距,判断是否存在循环和求取循环位置