力扣92. 反转链表 II(双指针、头插法)
https://leetcode-cn.com/problems/reverse-linked-list-ii/
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
一、迭代,双指针,头插法
//扫描一次
//时间复杂度O(n),空间复杂度O(1)
后抛实心球(在网上找了这个图来理解,很形象)
抛的物体?p的后一个指针(m位置的指针)
抛到哪里?g的后一个指针(m位置的前一个指针的后面)
//扫描一次
//迭代,双指针,头插法
//时间复杂度O(n),空间复杂度O(1)
ListNode* reverseBetween(ListNode* head, int m, int n)
{
if (head == nullptr)return head;
//哑结点,解决从一开始抛的问题
ListNode* result = new ListNode(0);
result->next = head;
ListNode* g = result;
ListNode* p = nullptr;
//找到头插法的头,即m-1
for (int i = 0; i <= m - 2; i++)
{
g = g->next;
}
//确定开始的位置g的下一个,即m,即p位置
p = g->next;
//抛m-n次,
for (int i = 1; i <= n - m; i++)
{
//记录抛的节点,p的下一个
ListNode* temp = p->next;
if (temp == nullptr)
{
break;
}
//跳过temp节点
p->next = p->next->next;
//抛到g的后面
temp->next = g->next;
g->next = temp;
}
return result->next;
}
二、vector翻转后再赋值
//vector翻转后再赋值
//扫描两次
//时间复杂度O(n),空间复杂度O(n)
//vector翻转后再赋值
//扫描两次
//时间复杂度O(n),空间复杂度O(n)
ListNode* reverseBetweenvector(ListNode* head, int m, int n)
{
vector<int>vec;
ListNode* cur = head;
while (cur != nullptr)
{
vec.push_back(cur->val);
cur = cur->next;
}
while (m < n)
{
swap(vec[m - 1], vec[n - 1]);
m++;
n--;
}
cur = head;
int i = 0;
while (cur != nullptr)
{
cur->val = vec[i];
cur = cur->next;
i++;
}
return head;
}
三、汇总
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution
{
public:
//vector翻转后再赋值
//扫描两次
//时间复杂度O(n),空间复杂度O(n)
ListNode* reverseBetweenvector(ListNode* head, int m, int n)
{
vector<int>vec;
ListNode* cur = head;
while (cur != nullptr)
{
vec.push_back(cur->val);
cur = cur->next;
}
while (m < n)
{
swap(vec[m - 1], vec[n - 1]);
m++;
n--;
}
cur = head;
int i = 0;
while (cur != nullptr)
{
cur->val = vec[i];
cur = cur->next;
i++;
}
return head;
}
//扫描一次
//迭代,双指针,头插法
//时间复杂度O(n),空间复杂度O(1)
ListNode* reverseBetween(ListNode* head, int m, int n)
{
if (head == nullptr)return head;
//哑结点,解决从一开始抛的问题
ListNode* result = new ListNode(0);
result->next = head;
ListNode* g = result;
ListNode* p = nullptr;
//找到头插法的头,即m-1
for (int i = 0; i <= m - 2; i++)
{
g = g->next;
}
//确定开始的位置g的下一个,即m,即p位置
p = g->next;
//抛m-n次,
for (int i = 1; i <= n - m; i++)
{
//记录抛的节点,p的下一个
ListNode* temp = p->next;
if (temp == nullptr)
{
break;
}
//跳过temp节点
p->next = p->next->next;
//抛到g的后面
temp->next = g->next;
g->next = temp;
}
return result->next;
}
};
int main()
{
Solution s;
ListNode head[5] = { 1,2,3,4,5 };
head[0].next = &head[1];
head[1].next = &head[2];
head[2].next = &head[3];
head[3].next = &head[4];
ListNode head1[5] = { 1,2,3,4,5 };
head1[0].next = &head1[1];
head1[1].next = &head1[2];
head1[2].next = &head1[3];
head1[3].next = &head1[4];
ListNode* out0 = head;
while (out0)
{
cout << out0->val << '\t';
out0 = out0->next;
}
cout << '\n';
cout << "扫描两次,vector翻转后再赋值:" << '\n';
auto result2 = s.reverseBetweenvector(head, 2, 4);
ListNode* out2 = result2;
while (out2)
{
cout << out2->val << '\t';
out2 = out2->next;
}
cout << '\n';
auto result1 = s.reverseBetween(head1, 2, 4);
ListNode* out1 = result1;
cout << "扫描一次,迭代,双指针,头插法:" << '\n';
while (out1)
{
cout << out1->val << '\t';
out1 = out1->next;
}
cout << '\n';
return 0;
}