今天这题需要注意的其实就是边界条件。
大体来说三步:
摘链 处理 归还
我自己的处理步骤用的是新建一个节点使用头插法。但是不知道为什么指针好像没有处理好,提交溢出了。但是在编译器里面确实能够做对。
题解的方法就是普通的反转链表,比我自己写的会简洁一些,这里两个版本都会贴上:
C++反转链表(附带测试)头插法:
#include<iostream>
using namespace std;
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) {}
};
void display(ListNode* head){
head = head->next;
while(head!=nullptr){
cout<<head->val<<" ";
head = head->next;
}
cout<<"endl"<<endl;
}
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode *listhead = new ListNode(0,head);
ListNode *ptr = listhead;
for (int i = 0; i < left - 1; i++) {
ptr = ptr ->next;
}
ListNode *leftptr = ptr;//记录左边界
ListNode *rightptr = leftptr;//记录右边界
for (int i = 0; i < right - left + 1; i++) {
rightptr = rightptr->next;
}
ListNode *leftNode = leftptr->next;//保存摘链后的头
ListNode *curr = rightptr->next;//保存摘链前的最后一个节点
ListNode *suplist = new ListNode(0);//辅助头节点
ListNode *suptr1 = suplist;//辅助指针,记录ptr的下一个
ListNode *suptr2 = leftNode;//辅助指针,记录链表尾部元素
while(leftNode!=nullptr){//使用头插法
suptr1 = leftNode->next;
leftNode->next = suplist->next;
suplist->next = leftNode;
leftNode = suptr1;
}
//归还链表
leftptr->next = suplist->next;
suptr2->next = curr;
return listhead->next;
}
};
int main(){
int arr[5] = {1,2,3,4,5};
ListNode *head = new ListNode(0);
ListNode *ptr = head;//工作指针
for(int i=0;i<5;i++){
ListNode *p1 = new ListNode(arr[i]);
ptr->next = p1;
ptr = ptr->next;
}
display(head);
Solution solution;
head = solution.reverseBetween(head->next,1,5);
display(head);
}
普通的反转方法:
class Solution {
private:
void reverseLinkedList(ListNode *head) {
// 也可以使用递归反转一个链表
ListNode *pre = nullptr;
ListNode *cur = head;
while (cur != nullptr) {
ListNode *next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
}
public:
ListNode *reverseBetween(ListNode *head, int left, int right) {
// 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
ListNode *dummyNode = new ListNode(-1);
dummyNode->next = head;
ListNode *pre = dummyNode;
// 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
// 建议写在 for 循环里,语义清晰
for (int i = 0; i < left - 1; i++) {
pre = pre->next;
}
// 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
ListNode *rightNode = pre;
for (int i = 0; i < right - left + 1; i++) {
rightNode = rightNode->next;
}
// 第 3 步:切断出一个子链表(截取链表)
ListNode *leftNode = pre->next;
ListNode *curr = rightNode->next;
// 注意:切断链接
pre->next = nullptr;
rightNode->next = nullptr;
// 第 4 步:同第 206 题,反转链表的子区间
reverseLinkedList(leftNode);
// 第 5 步:接回到原来的链表中
pre->next = rightNode;
leftNode->next = curr;
return dummyNode->next;
}
};