24. 两两交换链表中的节点
一、做题感受&第一想法
使用双指针+虚拟头结点,成功ac。
struct ListNode* swapPairs(struct ListNode* head) {
struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
dummyHead->next = head;
struct ListNode* p = head, *pre = dummyHead;
while(p != NULL && p->next != NULL){
pre->next = p->next;
p->next = pre->next->next;
pre->next->next = p;
pre = p;
p = p->next;
}
return dummyHead->next;
}
19.删除链表的倒数第N个节点
一、做题感受&第一想法
可以算是“暴力解法”:首先遍历链表,求出链表长度,然后再寻找需要删除的位置,删除节点即可。使用了虚拟头结点。
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
int cnt = 0, i = 0;
struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode)), *p = head, *temp = NULL;
dummyHead -> next = head;
while( p != NULL ){
cnt++;
p = p->next;
}
for(i = 0, p = dummyHead; i < cnt-n ; i++){
p = p->next;
}
temp = p->next;
p->next = p->next->next;
free(temp);
return dummyHead->next;
}
二、学习文章后收获
1.删除删除链表的倒数第N个节点:“快慢指针”经典应用
注意点:快指针比慢指针多走几步?(n+1)步。
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
dummyHead->next = head;
struct ListNode* fast = dummyHead, *slow = dummyHead;
for(int i = 0; i <= n; i++){ //fast先走(n+1)步
fast = fast->next;
}
while(fast != NULL){ //快慢指针一起向后移动
fast = fast->next;
slow = slow->next;
}
//删除节点
fast = slow->next;
slow->next = slow->next->next;
free(fast);
return dummyHead->next;
}
2.大胆用dummyHead吧,太好用了,literally
三、过程中遇到的问题
一开始写成了”快指针先走n步“,导致出现了访问空指针的报错。
面试题 02.07. 链表相交
一、做题感受&第一想法
①要看清楚题目:本题的交点是”指针值“相等,而不是“数值”val相等。
②对“链表相交“的经典解法:让长链表先走几步,统一二者的剩余链表长度,再遍历,判断指针是否相等。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
int lengthA = 0, lengthB = 0;
struct ListNode *pa = headA, *pb = headB, *target = NULL;
while(pa != NULL){ //求链表A的长度
lengthA++;
pa = pa->next;
}
while(pb != NULL){ //求链表B的长度
lengthB++;
pb = pb->next;
}
pa = headA; pb = headB;
//让长链表先走几步,以统一剩余链表长度。
if(lengthA > lengthB){
for(int i = 0; i < lengthA - lengthB ; i++){
pa = pa->next;
}
}
if(lengthA < lengthB){
for(int i = 0; i < lengthB - lengthA ; i++){
pb = pb->next;
}
}
//统一剩余长度后,pa和pb主簿后移,直到找到pa==pb的位置,即指针相等,链表相交。
while(pa != NULL && pb != NULL){
if(pa == pb && target == NULL){
target = pa;
}
pa = pa->next;
pb = pb->next;
}
return target;
}
142.环形链表II
一、做题感受&第一想法
没什么太好的思路。
二、学习文章后收获
1.思路
详见“文章讲解”。此处说明几个注意点:
- 总体思路:①判断有无环:快慢指针,快指针每次后移两个,慢指针每次后移一个,如果相遇则有环,如果快指针到null了则无环。②寻找环入口:证明请看文章讲解。最终结论是,从快慢指针相遇点到环入口的距离,和从链表开头到环入口的距离,相等。
- 注意无环时判断返回的条件:
if((fast == NULL) || (fast->next == NULL)){
return NULL;
}
2.代码
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *slow = head, *fast = head, *meet = NULL;
//【一:判断有无环】
while( fast != NULL && fast->next != NULL ){
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
break;
}
}
if((fast == NULL) || (fast->next == NULL)){
return NULL;
}
//【二:寻找环入口】
slow = head;
while( slow != fast ){
slow = slow->next;
fast = fast->next;
}
return slow;
}