206、反转链表
双指针法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = NULL;
while (cur != NULL){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
过程出现的问题:
- 返回值的问题:在完成链表反转后,它应该返回新的头节点(即原来的尾节点),而不是原来的头节点。
- 循环终止条件的问题:当
cur->next
为NULL时,循环就会终止,但实际上,这时cur
已经到了链表的最后一个节点。我们需要在循环条件中包括cur
,而不是cur->next
。
递归法
赶进度暂时跳过。
24. 两两交换链表中的节点
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy = new ListNode();
dummy->next = head;
ListNode*cur = dummy;
ListNode*tmp = NULL;
while (cur->next != NULL && cur->next->next!=NULL){
ListNode* first = cur->next;
ListNode* second = cur->next->next;
first->next = second->next;
second->next = first;
cur->next = second;
cur = cur->next->next;
}
return dummy->next;
}
};
出现的问题:
- 虚拟头节点的返回问题: 按当前代码,您在最后返回的是虚拟头节点
dummy
,这是不对的,应该返回dummy->next
,因为dummy
仅仅是起一个辅助作用,不是链表的实际头节点。 - 交换过程中的指针更新问题:对于成对节点的交换,涉及多个指针的操作,这里逻辑混乱并且没有更新虚拟头节点和前一对最后一个节点的下一个指针。
解释:
- 创建一个虚拟头节点
dummy
,其next
指向原链表的头节点。 - 使用一个指针
cur
,初始指向dummy
,用于进行成对交换操作。 - 在每次循环中,指向需要交换的两个节点
first
和second
。 - 进行节点交换,注意更新每个节点的
next
指针。 - 更新
cur
指针以处理下一对节点。 - 最后返回
dummy->next
,即新的头节点。
19.删除链表的倒数第N个节点
利用索引
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int i = 0;
ListNode* cur = head;
while (cur != NULL){
cur = cur->next;
i++;
}
if (n==i){
ListNode* newhead = head->next;
delete head;
return newhead;
}
int index = i - n;
cur = head;
ListNode* pre = NULL;
for (i = 0;i<index;i++){
pre = cur;
cur = cur->next;
}
pre->next = cur->next;
return head;
}
};
出现的问题:
1、索引不熟练
2、当删除的是头节点时:如果删除的是最后一个节点(即倒数第 N 个节点等于正数第一个节点),代码将无法处理这种情况。
解释:
- 第一次遍历:计算链表的长度。
- 检查是否删除头节点:如果需要删除的节点是头节点,直接返回新的头节点。
- 第二次遍历:找到倒数第 N 个节点的前一个节点。
- 删除节点:调整前一个节点的
next
指针,并删除目标节点。
双指针
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode();
dummy->next = head;
ListNode* f = dummy;
ListNode* sl = dummy;
ListNode* pre = NULL;
for (int fast = 0;fast<=n;fast++){
f = f->next;
}
while (f != NULL){
f = f->next;
sl = sl->next;
}
sl->next = sl->next->next;
return dummy->next;
}
};
巧妙的方法!
- 定义fast指针和slow指针,初始值为虚拟头结点,如图:
- fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)。
142、环形链表II
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast != NULL&& fast->next != NULL){
slow = slow->next;
fast = fast->next->next;
if (slow == fast){
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
出现的问题:
快慢指针为何会相遇?
一定会在环内相遇。
相遇之后如何找到环的起点?