leetcode链表题目练习(续)
1. 两两交换链表节点
两两交换的链表节点的注意事项:
- 交换的是节点不是值
- 要注意第一个节点的情况
- 定义一个虚拟头节点会更方便操作
我做错的原因:
- 节点的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* swapPairs(ListNode* head) {
ListNode *dummyhead =new ListNode(0);
ListNode *cur = dummyhead;
dummyhead->next = head;
while (cur->next != nullptr && cur->next->next != nullptr){
ListNode *tem = cur;
ListNode *tem1 = cur->next->next->next;
cur = cur->next->next;
cur->next = tem->next;
tem->next = cur;
cur->next->next = tem1;
cur = cur->next;
tem = nullptr;
tem1 = nullptr;
}
return dummyhead->next;
}
};
2. 删除链表的倒数第n个节点
思路:怎么先找到倒数第n个节点
- 思路第一条:一前一后双指针一格一格先到end再往后移动
不可行 - 思路第二条:
先把快指针和慢指针拉开n+1个距离
等快指针为NULL的时候就可以确定要删去节点的位置了
第二种方法我认为比较巧妙因为它相当于先将尺子长度固定再放上去量取,我们平时做题既要想到一前一后连着造短尺子一段一段量取也要想着直接固定长度再量取
代码如下:
/**
* 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);
ListNode* cur = head;
ListNode* pre = dummyhead;
dummyhead->next = head;
int size = 0;
while (pre->next != nullptr) {
pre = pre->next;
size++;
}
int location = size - n;
pre = dummyhead;
while (location--) {
cur = cur->next;
pre = pre->next;
}
pre->next = cur->next;
delete cur;
return dummyhead->next;
}
};
3. 链表相交
相交其实就是找两段他们开始相同的那个节点(注意不是val)
这个肯定要用到遍历,这是无法躲掉的,但是两段for循环是否有点笨拙?
解决方法:长链表的前几个元素肯定不能是相交的部分,不然不可能后面的节点一样
具体方案:
- int lane1
- int lane2
- gap = lane1 - lane2(注意要先把长的变成lane1)
- 进行遍历操作找交点
具体代码如下:
/**
* 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* cur1 = headA;
ListNode* cur2 = headB;
int lineA = 0;
int lineB = 0;
while (cur1 != nullptr){
cur1 = cur1->next;
lineA++;
}
while (cur2 != nullptr){
cur2 = cur2->next;
lineB++;
}
cur1 = headA;
cur2 = headB;
if (lineB > lineA){
swap(cur1,cur2);
swap(lineA,lineB);
}
int n =lineA - lineB;
while (n--){
cur1 = cur1->next;
}
while (lineB--){
if(cur1 == cur2){
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
return NULL;
}
};
4. 环形链表
这道题是我遇到链表里面最难的题目
首先这道题有两个难点
- 这是不是环形链表
- 这个环形链表的开始在哪里
这两问一个比一个难,首先判断是不是环形链表
可以用快慢指针判断,也就是说如果是环形链表那么快指针一定会绕着跑从后面追上慢指针从而判断是环形链表。
也就是慢指针的距离=x+y
快指针的运动距离=x+(y+z)*n
y+z是一圈的距离
从而判断是否是个环形链表
同时根据快慢指针可以知道:
慢指针的距离是快指针的二分之一
也就是:2(x+y)=x+(y+z)*n
那么不难得出:x = (n - 1) (y + z) + z
因为y+z是一圈的距离那么可以得出:z=x
那么这道题也就解完了,代码并不难,主要难在算法的设计
代码如下:
/**
* 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;
ListNode* index;
ListNode* index1 = head;
while (fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
index = fast;
while (index != index1){
index = index->next;
index1 = index1->next;
}
return index1;
}
}
return NULL;
}
};