力扣92. 反转链表 II(双指针、头插法)

力扣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;
	}

2.png

 

二、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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值