链表的题目,主要有两大要点,其一是思路,其二是编码。
LeetCode206:反转一个单链表
维护三个指针,prev, current, next,从前往后,以此反转
1 | public ListNode reverseList(ListNode head) { |
LeetCode24:两两交换链表中的节点
思路1:维护三个指针,prev、next1、next2,以prev为遍历中心,操作prev、next1、next2、next3的指针。
1 | public ListNode swapPairs(ListNode head) { |
思路2:递归反转,维护next1,next2两个指针
1 | public ListNode swapPairs(ListNode head) { |
LeetCode160:相交链表
如上图,分为三部分 a\b\c。解题思想就是 a+c+b = b+c+a
也就是两个链表遍历,结束时从另一个链表的头继续遍历,直到相遇
1 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { |
LeetCode141:判断链表是否有环
思路1:Set存储遇到的每一个ListNode,从前往后遍历,直到结束或者遇到Set中存在的,返回。
思路2:快慢指针,龟兔赛跑。慢指针每次向前一步,快指针每次两步,如果有环,必然相遇!
1 | public boolean hasCycle(ListNode head) { |
LeetCode142:求链表中环的起点
求是否有环,用到了快慢指针,本题依然使用快慢指针。如上图所示,分为三部分。当快慢指针首次相遇于紫色点处时,
满指针走了a+b,快指针走了a+b+c+b,又因为快指针走的路长为慢指针的两倍。所以得出:
2(a+b) = a+b+c+b => a = c
so,首次相遇时,再加一个指针pointer指向链表的起点,慢指针走一步,pointer走一步,相遇时,就是环的起点!
1 | public ListNode detectCycle(ListNode head) { |
LeetCode234:回文链表
思路简单:快慢指针,慢指针移动的时候反转链表,并维护prev指针。快指针先行,遍历到null的时候说明慢指针到了中间。然后slow和prev向两边开始对比。
注意点:节点数为奇数时,慢指针刚好在中间;节点数为偶数时,慢指针为后一部分的第一个节点。
根据fast为null还是fast后面的第一个节点为null,区分节点总数是奇数还是偶数。
1 | public boolean isPalindrome(ListNode head) { |
思路2:递归判断是否回文。利用栈的特性,维护一个前置指针,递归栈里存放后置指针,递归到最深层时,不断弹栈,前置指针也不断后移,两相比较。这种不好,无法预知栈的深度!此处仅作为一种解题思想。
1 | ListNode front; |