- 首先给一个我之前写的双指针在链表类题中的妙用的link:双指针在链表中的妙用
tip1 来自“合并两个有序链表”
- 这道题注意的就是如果是要返回一个新链表的头结点,一定要新建一个头结点:
ListNode* prehead = new ListNode(-1);
- 之后再对prehead的next进行添加,而不是对传进来的参数节点(比如list1)进行遍历、或其他改变后,再直接返回参数节点(当list1遍历的时候指向了尾结点,这样就找不到开始的头结点了)!
- 代码如下
/**
* 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* prehead = new ListNode(-1); // 申请一片新的空间的办法
ListNode* pre = prehead; // 暂时指向这片区域,然后之后只更改next
while (list1 != nullptr && list2 != nullptr) {
if (list1->val > list2->val) {
pre->next = list2;
list2 = list2->next;
} else {
pre->next = list1;
list1 = list1->next;
}
pre = pre->next;
}
if (list1 != nullptr)
pre->next = list1;
else if (list2 != nullptr)
pre->next = list2;
return prehead->next;
}
};
跟上上一道题的方法,如果是新建节点怎么做?
- 用“双数相加”来说,题目链接:link
- 必须用的方法是,不能自己猜想链表结构写别的代码:
//j%10的位置写新的val
//然后插入下一个点
ListNode* temp = new ListNode(j % 10);
pre->next = temp;
- 题目的代码如下
/**
* 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* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* pre = preHead;
int j = 0;
// 模拟的思路
while (l1 != nullptr || l2 != nullptr || j != 0) {
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
j = j + n1 + n2;
// 插入新节点一定要用这种新建的方式
ListNode* temp = new ListNode(j % 10);
pre->next = temp;
j = j / 10;
pre = pre->next;
if (l1)
l1 = l1->next;
if (l2)
l2 = l2->next;
}
// 结束条件 l1加完了 或者l2加完了
return preHead->next;
}
};
另一道用快慢指针的题
- 所以head不能动,但是可以新建指针指向head,并移动新的指针!
题目链接
- 思路就是快慢指针,快指针比慢指针先走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) {
// 删除链表的倒数第n个节点
// 想保留头结点,就新建一个节点去动!
// head千万不能动,建立两个快慢指针!
ListNode* preHead = new ListNode(-1);
preHead->next = head;
ListNode* fast = preHead;
ListNode* slow = preHead;
if (!head->next && n == 1)
return nullptr;
int count = n - 1; // 先让fast
while (fast != nullptr && count) {
fast = fast->next;
count--;
}
// 直到fast 这个逻辑有点问题 改一下!
while (fast != nullptr && fast->next != nullptr &&
fast->next->next != nullptr) {
fast = fast->next;
slow = slow->next;
}
// 当前的fast指向倒数第二个节点
ListNode* slow2 = slow; // 1
slow2 = slow2->next; // 2
// fast=fast->next;
// 此时fast指向了最后一个节点;slow2这个点是要被去除的
slow->next = slow2->next; // 成功去除
return preHead->next;
}
};
指针只是指针
以下代码是k个一组翻转链表的代码,一道困难题,而我之前总是觉得head指针指错了,直到加了这个代码:
- 为什么这句话至关重要?因为slow指向了head 但是不代表更新slow就更新了head
if (slow->next == head)
head = p1;
题目链接是这个:题目链接
代码如下:
/**
* 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* reverseKGroup(ListNode* head, int k) {
if (k == 1)
return head;
ListNode* preHead = new ListNode(-1);
preHead->next = head;
ListNode* slow = preHead;
ListNode* fast = preHead;
int count = k;
ListNode* p1;
ListNode* p2;
ListNode* nxt;
fast = fast->next;
while (fast) {
while (count - 1) {
// 如果在移动过程中就遇到空了,其实已经可以return了
if (fast->next == nullptr)
return head;
fast = fast->next;
count--;
} // 让fast指向最后一个点 只是验证了还剩下这么多节点
fast = fast->next; // 移到下一个节点
p1 = slow->next;
p2 = slow->next->next;
while (p2 != fast) {
nxt = p2->next; // 存下来的
p2->next = p1;
p1 = p2;
p2 = nxt;
}
// 如果p2==next了
slow->next->next = fast;
// 至关重要
if (slow->next == head)
head = p1;
slow->next = p1;
while (slow->next != fast) {
slow = slow->next;
}
count = k;
}
return head;
}
};