算法训练营Day4:链表相关2
力扣24:两辆交换链表中节点
题目描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
解题思路
- 思路上相对比较简单;需要注意的是代码实现的操作过程中,注意丢失节点,不要导致访问不到。核心要点是:链表是链式存储,头节点是访问链表的唯一入口,上一个节点是访问下一个节点的必要入口。
其二就是在判断终止的边界条件时,如果想不好怎么写边界条件,可以进行举例,如果是空怎么办,如果只有一个节点怎么办,如果只有两点节点怎么办。
完整代码
/** * Definition for singly-linked list. * 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* swapPairs(ListNode* head) { ListNode *dummyHead = new ListNode(0); //新建虚拟头节点 dummyHead->next = head; //将虚拟头节点放在头节点前面 ListNode *cur = dummyHead; //定义用来实际操作的节点,防止丢失头节点 //开始遍历交换操作 while(cur->next != nullptr && cur->next->next != nullptr){ ListNode *tmp = cur->next; //保存头节点 ListNode *tmp1 = cur->next->next->next; //保存第三个节点 cur->next = cur->next->next; //下面开始操作 cur->next->next = tmp; cur->next->next->next = tmp1; cur = cur->next->next; } return dummyHead->next; } };
力扣19:删除链表中倒数第N个节点
题目描述
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
解题思路
- 最初未看题解的时候考虑的是:目标是将cur移动到待删除节点的前一个节点;具体实现思路是先通过while循环计算链表的长度,然后使用链表的长度和n的值来移动cur节点。
- 但是看了快慢指针之后,发现使用快慢指针的解法更加优雅。核心思想是先将快指针向前移动n+1步,之后再将快指针和慢指针同步移动。这种思路就不用管链表的长度了,优雅!
完整代码
第一种思路解法:
/**
* Definition for singly-linked list.
* 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 *cur = dummyHead;
ListNode *cur1 = dummyHead;
int size = 0; //初始化链表长度
//求解链表长度
while(cur1->next != nullptr){
size++;
cur1 = cur1->next;
}
//移动cur节点到待删除的节点的前一个
int num = size - n;
while(num){
ListNode *tmp = cur->next;
cur = cur->next;
num--;
}
//进行删除处理
ListNode *tmp1 = cur->next;
cur->next = cur->next->next;
delete tmp1;
return dummyHead->next;
}
};
双指针解法代码实现,如果有不明确的地方,在纸上勾勾画画就知道了。在写代码时,除非自己对这个流程很熟悉,不然就先在纸上把伪代码写好,整理好自己的逻辑,再落实为具体的代码。
/**
* Definition for singly-linked list.
* 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 *dummpHead = new ListNode(0);
dummpHead->next = head;
ListNode *fast = dummpHead;
ListNode *slow = dummpHead;
n ++;
//先移动fast指针
while(n-- && fast != nullptr){
fast = fast->next;
}
//同时移动快指针和慢指针
while(fast != nullptr){
slow = slow->next;
fast = fast->next;
}
//删除指定节点
ListNode *tmp = slow->next;
slow->next = slow->next->next;
delete tmp;
return dummpHead->next;
}
};
力扣02.07: 链表相交
题目描述
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
图示两个链表在节点 c1
开始相交
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
解题思路
这题重点要理解:当链表相等时,后面的链表值也必定相等;所以核心思路是:将两个链表尾对其,对其之后从开始对其的节点进行比较,判断是否相等,如果是则返回该节点,如果不是则返回空。
- 计算两个链表长度
- 尾对其两个链表(移动较长的那个链表)
进行比较,判断是否符合条件,并作出响应。
完整代码
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode *curA = headA; ListNode *curB = headB; int sizeA = 0; int sizeB = 0; //统计链表长度 while(curA != NULL){ curA = curA->next; sizeA++; } while(curB != NULL){ curB = curB->next; sizeB++; } //要注意还原curA和curB链表 curA = headA; curB = headB; //确保sizeA的值是最大的 if(sizeA < sizeB){ swap (sizeA, sizeB); swap (curA, curB); } //开始尾对其两个链表 int gap = sizeA - sizeB; while(gap--){ curA = curA->next; } //开始进行比较 while(curA != NULL){ if(curA == curB){ return curA; } curA = curA->next; curB = curB->next; } return NULL; } };
力扣142: 环形链表
题目描述
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 _如果链表无环,则返回 null
。_
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
解题思路
使用快慢指针来解决问题。
核心问题有两个:
第一:找到快慢指针相遇的位置。
第二:找到进入循环的位置。
完整代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
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;
if(fast == slow){
ListNode *index1 = fast;
ListNode *index2 = head;
while(index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
今日小结
日渐消瘦、日渐熟练这种思维模式。
评论区(暂无评论)