这两天事情有点多,只记录了大致心得和思路。
19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
讨论:
直接在我脑海中出现的思路是建了vector,把每个节点的值都存进去,然后通过获取v.size() - n,一直访问到该节点并执行删除操作
这样的方式应该一定可行,但是perfermance肯定有很大的提升空间
学习代码随想录中的思路,可以通过快慢指针的思路,先让快指针向前进n+1个节点
然后在一个while loop中使快慢指针同时前进直到,快指针的next为空则循环停止
需要注意的是,在进行删除操作的时候我们需要确保执行删除操作的指针指向被删除节点的前一个
所以我们让快指针先前进n+1而不是n个节点,这样慢指针最后指向倒数n+1个节点
dummuyhead的一大好处是不需要对原先的头节点进行专门的boundary case判断操作
//Given the head of a linked list, remove the nth node from the end of the list and return its head.
//Input: head = [1, 2, 3, 4, 5], n = 2
//Output : [1, 2, 3, 5]
struct ListNode {
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* fast{ dummyhead };
ListNode* slow{ dummyhead };
int count = 0;
while (fast && n + 1 > count) {// count + because dummy_head is added
fast = fast->next;
count++;
}
//fast = fast->next;
while (fast) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummyhead->next;
}
};
24. 两两交换链表中的节点
讨论:学会了用dummy head去keep track of the list.
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(999);
dummyhead->next = head;
ListNode* curr = dummyhead;
while (curr->next && curr->next->next) {//next two node exsits
ListNode* temp1 = curr->next;
ListNode* temp2 = curr->next->next->next;
temp1->next->next = temp1;
curr->next = temp1->next;
temp1->next = temp2;
curr = curr->next->next;
}
return dummyhead->next;
}
};
142.环形链表II
题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
首先,让我们定义一些符号:
- 链表头到环入口的距离为 D
- 环入口到快慢指针相遇点的距离为 X
- 相遇点到环入口的距离为 Y
根据上面的定义,我们有:
- 环的长度为 X + Y
- 慢指针走过的距离为 D + X
- 快指针走过的距离为 D + X + n(X + Y),其中 n 是快指针在环内走过的圈数
因为快指针的速度是慢指针的两倍,所以我们可以得出等式:
2(D + X) = D + X + n(X + Y)
D + X = n(X + Y)
D = n(X + Y) - X
D = (n - 1)(X + Y) + Y
- 当快慢指针相遇时,我们知道慢指针走过的距离是 D + X。
- 此时,我们让慢指针(或另一个指针)从链表头重新开始走,快指针继续从相遇点走,但这次两个指针的速度都设为1。
- 当慢指针走到环入口时,它走过的距离正好是 D。根据上面的等式,此时快指针走过的距离是 (n - 1)(X + Y) + Y,也就是说,它在环内走了 (n - 1) 圈,然后又走了 Y 的距离。
- 注意到 Y 正好是相遇点到环入口的距离。这意味着,当慢指针到达环入口时,快指针也恰好到达环入口!
- 因此,我们只需要等待两个指针相遇,相遇点就是环的入口。
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
if (!head || !head->next) return nullptr;
ListNode* fast = head;
ListNode* slow = head;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) {
ListNode* ptr1 = head;
ListNode* ptr2 = fast;
while (ptr1 != ptr2) {
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}
return ptr1;
}
}
return nullptr;
}
};