day04
例题 leetcode 24. 两两交换链表中的节点
链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
思路:模拟链表两两交换的过程就能够通过本题目,对链表的操作一般使用虚拟头节点来进行会比较好,
因为这样子不需要针对头节点单独设置特殊的情况。交换步骤如下:
重点:想到模拟交换的过程并不难,但是步骤的先后会严重影响结果。需要保证按照该步骤进行节点指针的修改!
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode pre = null;
ListNode dummyhead = new ListNode();
dummyhead.next = head;
ListNode cur = dummyhead;
ListNode temp1;
ListNode temp2;
while(cur.next != null && cur.next.next != null){
temp1 = cur.next;
temp2 = cur.next.next;
ListNode temp = temp2.next;
cur.next = temp2;
temp2.next = temp1;
temp1.next = temp;
cur = temp1;
}
return dummyhead.next;
}
}
例题 leetcode 19.删除链表的倒数第N个节点
链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
思路:双指针法,让快指针先前进n步。之后,慢指针和快指针同时前进,那么当快指针走到链表末尾时,慢指针指向的下一个节点就是要删除的节点。
因为这样子就能够保证慢指针和链表末尾的间隔为n。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0, head);
ListNode slow = dummy;
ListNode fast = head;
int temp = n;
while(temp > 0){
fast = fast.next;
temp--;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
例题 leetcode 面试题 02.07. 链表相交
链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/
方法1:哈希表
首先遍历链表headA,并将链表headA中的每个节点加入哈希集合中。然后遍历链表headB,对于遍历到的每个节点,判断该节点是否在哈希集合中:
如果当前节点不在哈希集合中,则继续遍历下一个节点;
如果当前节点在哈希集合中,则后面的节点都在哈希集合中,即从当前节点开始的所有节点都在两个链表的相交部分,因此在链表 headB\textit{headB}headB 中遍历到的第一个在哈希集合中的节点就是两个链表相交的节点,返回该节点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> visited = new HashSet<ListNode>();
ListNode temp = headA;
while (temp != null) {
visited.add(temp);
temp = temp.next;
}
temp = headB;
while (temp != null) {
if (visited.contains(temp)) {
return temp;
}
temp = temp.next;
}
return null;
}
}
方法2:双指针法
设a为headA总长,b为headB总长,c为两链表的公共长度(若存在)
可得,a + c != b + c,但只需让a和b走过互相走过的路,即可到达同个结点,即a + c + b == b + c + a
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
源自:leetcode官方解答
例题 leetcode 142.环形链表II
链接:https://leetcode.cn/problems/linked-list-cycle-ii/
思路:这道题目本质上就是数学题目。设置快慢指针,刚开始都位于链表的头部。slow链表每次向后移动一位的同时,fast链表每次向后移动两位。
如果链表中没有环,则fast指针最终会为null。如果有环,则如下图:
由题意得,fast指针走过的距离设为a + n * (b + c)+ b。且该距离始终为slow指针的2倍。由此可得,a + (n + 1) b + nc = 2 (a + b)。
即a = (n - 1)(b + c) + c -->即 a = c。
由此,当slow指针和fast指针相遇的时候,设置一个从头节点开始前进的指针和slow节点同时前进,他们相遇的位置就是入环点。
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
if (fast == slow) {
ListNode temp = head;
while(temp != slow){
temp = temp.next;
slow = slow.next;
}
return temp;
}
}
return null;
}
}