算法通关村第二关——指定区间反战问题解析

大家好,我是怒码少年小码。

新的一天,新的考验😉。今天是反转链表的一个拓展,说真的有点意思~

指定区间反转

LeetCode92:给单链表的头指针head和两个整数left和right,其中left <= right。反转left位置到right位置的链表结点,返回反转后的链表。

示例:

  • 输入:head=[9,7,2,5,4,3,6],left=3,right=6
  • 输出:[9,7,3,4,5,2,6]

1.头插法

什么是头插法可以看我前面的文章:反转链表的两种方法

主要思想是在需要反转的区间里遍历所有结点,让所有结点插到反转部分的起始位置:

直接上代码:

LinkNode* reverseBetween(LinkNode* head, int left,int right){

	LinkNode* dummyNode = new LinkNode;
	dummyNode->next = head;
	LinkNode* pre = dummyNode;

	//找到反转区间头的前一个结点
	for (int i = 0; i < left - 1; i++) {
		pre = pre->next;
	}

	//指向要反转的第一个结点
	LinkNode* cur = pre->next;
	LinkNode* next;

	for (int i = 0; i < right - left; i++) {
		//保存下一个要反转的结点
		next = cur->next;
		//cur结点练到下一个结点的后一个结点,
		cur->next = next->next;
		//next结点接到pre后
		next->next = pre->next;
		//pre后连接next
		pre->next = next;

		//cur结点换到原来的后一个结点,原来的后一个结点跳到pre后面
	}

	LinkNode* newHead = dummyNode->next;
	free(dummyNode);

	return newHead;
}

pre 指向虚拟链表反转区间的前一个结点,所以需要从虚拟结点开始,这样哪怕left = 1从第一个结点开始反转都不怕。

2.穿针引线法

这个方法比较好理解一些。这题无非就是反转的地方有限制罢了,何不我先把要反转的部分断开来当作一个新链表,直接反转新链表😎,然后在接回去呢。

  1. 需要断开一个新链表,我们需要根据left和right形参位置定义新链表的头尾指针leftNoderightNode
  2. 需要断开和接回去新链表,所以我们需要记录left位置前一个结点和right位置后一个结点,这里是presucc,方便断开、接回。
  3. 反转新链表这个已经是我们很熟悉的东西,我们直接在定义一个函数reverseList用于反转某一链表就行了。

整个过程示意图如下(蓝色为新链表):

反转前

反转后

单独用于反转链表的函数:

void reverseList(LinkNode* head) {
	LinkNode* pre = nullptr;
	LinkNode* cur = head;
	while (cur != nullptr) {
		LinkNode* next = cur->next;
		cur->next = pre;
		pre = cur;
		cur = next;
	}
}

区间反转方法:

LinkNode* reverseBetween02(LinkNode* head, int left, int right) {
	//创建虚拟头结点
	LinkNode* dummyNode = new LinkNode;
	dummyNode->next = head;
	LinkNode* pre = dummyNode;

	//从虚拟头结点开始走到要反转区间的前一个结点
	for (int i = 0; i < left - 1; i++) {
		pre = pre->next;
	}

	//rightNode指向right位置的结点
	LinkNode* rightNode = pre;
	for (int i = 0; i < right - left + 1; i++) {
		rightNode = rightNode->next;
	}

	//leftNofe指向left位置的结点
	LinkNode* leftNode = pre->next;
	LinkNode* succ = rightNode->next;

	//断开链表
	pre->next = nullptr;
	rightNode->next = nullptr;
  	//新链表的头结点是leftNode,反转它!
	reverseList(leftNode);
  	//接回原链表中
	pre->next = rightNode;
	leftNode->next = succ;

	return dummyNode->next;
}

这里要注意⭐的是:新链表反转完后的新头结点是rightNode所指的结点,所以是pre->next = rightNode;leftNode->next = succ;

END

如果考虑代码的健壮性,其实还可以加入很多,比如:判断链表是否为空/只有一个结点、形参left一定要小于right且两者都要合法(不能超出链表长度/为负数)等等🥱,这里为了代码简洁好看我就不加上去了哈。

伙计们,我们下篇再见✌️!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值