例题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的步长差距,判断是否存在循环和求取循环位置