Leetcode之24. 两两交换链表中的节点
一、题目要求
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
二、解题思路
这里借用代码随想录的图片,这一题的关键是循环的终止条件和需要用临时的指针保存哪一个指针的问题。1、判断终止的条件:看cur每次走几步,以上面的图为例,玩成上面第一次的交换之后,根据每次走两步就可以判断。 2、是需要保存哪两个指针,显然,上图中被间接指到的1和3是需要被保存的(不临时保存的话会找不到!),接下来的交换就是正常写代码了。
三、代码实现
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; // cur移动两位,准备下一轮交换
}
return dummyHead->next;
}
};
Leetcode之19.删除链表的倒数第N个节点
一、题目要求
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] 示例 2:
输入:head = [1], n = 1 输出:[] 示例 3:
输入:head = [1,2], n = 1 输出:[1]
二、解题思路
此题一定要注意的是删除倒数的结点~!
主要的思路是用双指针实现的,要清楚指针的具体的指向,主要分成三个步骤
1、fast指针指向目标结点,一定要向前多走一步,把要删除的位置空出来
2、这个时候fast和slow同时运动,直到fast为空,这个时候fast和slow中间就隔了一个结点
3、完成删除操作!
三、代码实现
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyNode = new ListNode(0);
dummyNode ->next = head;
ListNode* slow = dummyNode;
ListNode* fast = dummyNode;
while ( n-- && fast!= NULL){ //fast 指向目标节点
fast = fast ->next;
}
fast = fast ->next; //fast多走一步
while(fast != NULL){
fast = fast -> next;
slow = slow ->next;
}
slow ->next = slow ->next ->next;
return dummyNode ->next;
}
};
Leetcode之160.链表相交
一、题目要求
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
二、解题思路
这题主要考察1、相交链表的定义(看题目)对齐考察链表长度的计算
2、指针相等的定义(
curA == curB
)
三、代码实现
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
Leetcode之142.环形链表II
一、题目要求
题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
二、解题思路
两个难点
1、判断是否有环
我们在设立两个快慢指针,一个走一步,一个走两步。在快的进入环之后,会不断的在环形里面绕圈子。最终它们会在某点相遇。为什么会相遇呢,设此点为p
设起点到入口为的长度为M, 入口到p的距离为P。环形的周长为c
此时 slow = M+P, fast=M+P+rc。(r为一个变量),也就是当rc = slow时,它们两个会相遇。
具体情况, 分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
2、怎么判断环的入口
- fast = 2slow
- slow = M+P
- fast = 2slow = M+P + slow = M+P+rc
所以slow = rc. M = rc - P = (r-1)c + (c- P), c - P 等于从相遇的p点再走回到环的起点。
因此,我们可以得出一个结论,当在用一个指针ptr,从0开始,走M步到入口时, slow和ptr同时出发,同样走M步((r-1)c + (c- P)) 也就是走(r-1)圈,然后在加上 c-p步,也就是从相遇到p点回到起点。正好可以和ptr在入口处相遇。
三、代码实现
class Solution { public: ListNode *detectCycle(ListNode *head) { ListNode* fast = head; ListNode* slow = head; while(fast != NULL && fast->next != NULL) { slow = slow->next; fast = fast->next->next; // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇 if (slow == fast) { ListNode* index1 = fast; ListNode* index2 = head; while (index1 != index2) { index1 = index1->next; index2 = index2->next; } return index2; // 返回环的入口 } } return NULL; } };