day4
1、leetcode24 两两交换链表中的节点
-
思路图解
![24.两两交换链表中的节点1]()
-
代码
class Solution { public ListNode swapPairs(ListNode head) { ListNode dummyHead = new ListNode(0); dummyHead.next = head; ListNode cur = dummyHead;//cur节点作为辅助变量,遍历原链表,一定要指向要进行交换操作节点的前一个节点,才能保证能够对后面进行操作 //当cur.next==null表示遍历到偶数个节点的最后一个; //当cur.next.next==null表示遍历奇数个节点中剩下最后一个节点 while(cur.next!=null && cur.next.next!=null){ //记录两个临时节点,防止交换操作中,节点指向改变,无法正确操作 ListNode temp = cur.next; ListNode temp1 = cur.next.next.next; cur.next = cur.next.next; //步骤一 cur.next.next = temp; //步骤二 temp.next = temp1; //步骤三 cur = cur.next.next; // cur移动两位,准备下一轮交换 } return dummyHead.next; } }
2、leetcode19 删除链表的倒数第N个节点
-
双指针法
-
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
- 注意:这里fast首先走n + 1步 ,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)
-
步骤
- 定义fast指针和slow指针,初始值为虚拟头结点
- fast首先走n + 1步
- fast和slow同时移动,直到fast指向末尾null
- 删除slow指向的下一个节点
-
代码实现
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummyHead =new ListNode(0); dummyHead.next = head; ListNode fast = dummyHead; ListNode slow = dummyHead; n++; //fast移动n+1步 while(n>0 && fast != null){ fast = fast.next; n--; } while(fast!=null){ fast = fast.next; slow = slow.next; } slow.next = slow.next.next; return dummyHead.next; } }
-
-
将删除倒数第N个节点 ,转换为删除顺数索引为index = size-n的节点的问题(index从0开始)
-
代码实现
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummyHead =new ListNode(0); dummyHead.next = head; ListNode cur = dummyHead.next; int size = 0; int index = 0; while(cur != null){ cur = cur.next; size++; } index = size - n; //index从0开始 cur = dummyHead; //cur要定位到要删除节点的前一个节点 while(index>0){ cur = cur.next; index--; } cur.next = cur.next.next; return dummyHead.next; } }
-
3、面试题 02.07. 链表相交
-
思路
-
注意:交点不是数值相等,而是指针相等。
-
求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置
![面试题02.07.链表相交_2]()
-
此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。否则循环退出返回空指针。
-
-
代码
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode curA = headA; ListNode curB = headB; int sizeA = 0; int sizeB = 0; //求出链表A的长度 while(curA != null){ curA = curA.next; sizeA++; } //求出链表B的长度 while(curB != null){ curB = curB.next; sizeB++; } curA = headA; curB = headB; //让较长链表的cur移动至,和较短链表的头节点对齐的位置【让curA和curB在同一起点上(末尾位置对齐)】 if(sizeA >= sizeB){ for(int i=0; i < sizeA-sizeB;i++){ curA = curA.next; } } else { for(int i=0; i < sizeB-sizeA;i++){ curB = curB.next; } } //比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。 while(curA != null){ if(curA == curB){ return curA; } curA = curA.next; curB = curB.next; } return null; } }
4、leetcode142 环形链表Ⅱ
-
如何判断链表是否有环?
- 采用快慢指针法。
- 分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
- 分析:
- fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,一定是快指针去追慢指针
- 因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow相遇。
- 采用快慢指针法。
-
已经有环存在,如何找到这个环的入口?
-
![img]()
-
相遇时,慢指针走过节点数2 = 快指针走过节点数,n为fast指针在环内走了n圈才遇到slow指针,n>=1
$$
(x+y)2 = x+y+n(y+z)
$$$$
x=(n-1)(y+z)+z, n>=1
$$当 n为1的时候,公式就化解为
x = z当n大于1时,就是fast指针在环形转n圈之后才遇到 slow指针。
其实这种情况和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。
-
从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。(x = z)
-
-
代码
public class Solution { public ListNode detectCycle(ListNode head) { ListNode fast = head; ListNode slow = head; while(fast != null && fast.next != null){ fast = fast.next.next; slow = slow.next; // 快慢指针相遇,说明有环,此时从head 和 相遇点,同时查找直至相遇 if(fast == slow){ ListNode index1 = fast; ListNode index2 = head; while(index1!=index2){ index1 = index1.next; index2 = index2.next; } return index1;// 返回环的入口 } } return null; } }




浙公网安备 33010602011771号