链表题目之指定区间处理

news2024/10/6 6:43:49

前言

链表中有一些题目是需要知道并且记住对应的技巧的,有一些题目就是基本的链表技巧+手动模拟推演注意细节等。
对于需要知道并且记住对应技巧的题目会有专门的一栏进行讲解,此类题目主要有:相交链表、环形链表、回文链表等,这些必须要记住对应的破题的题眼。
本文主要是讲指定区间的链表,这类题目有一定的共性,而且常考变形题目也较多。

理论

此类题目大概是给你一个链表,让你按照某个条件,找到一个区间的开始位置,之后对这个区间一直处理直到这个区间的结束位置,当然一个链表中可能有多处这样的区间。这里涉及到的技巧在基本方法篇已经有讲,实际上就是构造、处理部分的各种组合,这里按照做题时的先后顺序归纳一下。

  1. 虚拟头:如果第一个节点会是区间开始位置,要用虚拟头
  2. 找区间开始位置,以及不符合条件时继续
  3. 小区间for循环处理:找到区间开始位置后,要用for循环小区间内一次性处理,直到这个区间结束
  4. 小区间内具体处理:重新做人法,即别用p了,直接用一个新的变量,进行赋值,避免乱,同时也能保留关键上下文。具体方案:删除(前任删除法)、反转(头插)
  5. 小区间处理完之后,要收摊子,要把处理的这部分接回去

基本框架流程如下

  1. 虚拟头
func solve(head *ListNode) *ListNode {
    dummyHead := &ListNode{Next:head}
    p := dummyHead


    return dummyHead.Next
}
  1. 找区间入口
  2. 找到区间出口
func solve(head *ListNode) *ListNode {
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    for p.Next != nil {
        if xx {
            
        }
        p = p.Next
    }
    return dummyHead.Next
}
  1. 小区间for循环处理
func solve(head *ListNode) *ListNode {
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    for p.Next != nil {
        if xx {
            // 找到区间入口了
            tmpP := p.Next // 重新做人
            for xx { // for 循环直到区间出口

            }
            
        }
        p = p.Next // 不符合条件 继续下一个
    }
    return dummyHead.Next
}
  1. 小区间处理完之后,要收摊子,要把处理的这部分接回去,注意之前的p以及p.Next指向的值,很关键
  2. 手动推演,即下一轮循环p的位置
func solve(head *ListNode) *ListNode {
    // 1.把框架复制进来,看一下 是否能行
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    for p.Next != nil {
        if xx { // 2. 根据题目要求写一下这个的入口条件和下面的出口条件
            // 找到区间入口了
            tmpP := p.Next // 重新做人
            // 3. 区间出口
            for xx { // for 循环直到区间出口 
                // 4.具体处理逻辑

            }
            // 5.接回去 具体根据题目分析,注意之前的p以及p.Next指向的值,很关键
            // 6.即下一轮循环p的位置:手动推演一下
        }
        p = p.Next // 不符合条件 继续下一个
    }
    return dummyHead.Next
}

实战

接下来会使用几个题目,根据上面的套路、模版进行编码

指定区间反转链表(92)

题目:92. 反转链表 II
代码中的1、2、3即为思考编码时候的步骤

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseBetween(head *ListNode, left int, right int) *ListNode {
    // 1.把框架复制进来,看一下 是否能行,这里是可行的
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    index := 0
    for p.Next != nil {
        index++
        if index==left { // 2. 根据题目要求写一下这个的入口条件和下面的出口条件,看来得用Index记录一下
            // 找到区间入口了
            // 4. 是想让我们反转,那就头插,基本套路写上
            var newHead *ListNode
            tmpP := p.Next // 重新做人
            for index<=right { // for 循环直到区间出口
                index++ // 3. 区间出口,这里肯定要++ ,具体是<=还是=可以用推演确定
                cur := tmpP
                tmpP = tmpP.Next
                cur.Next = newHead
                newHead = cur
            }
            // 接回去 具体根据题目分析,注意之前的p以及p.Next指向的值,很关键
            // 5.手动推演以及p的信息,可以知道当前p是1,p.Next是2,newHead是4,tmpP是5,对应接上即可
            // 要注意顺序
            p.Next.Next = tmpP
            p.Next = newHead
            // 6.这里其实可以break了
            break
        }
        p = p.Next // 不符合条件 继续下一个
    }
    return dummyHead.Next
}

删除排序链表中的重复元素2(82)

题目:82. 删除排序链表中的重复元素 II

func deleteDuplicates(head *ListNode) *ListNode {
    // 删除所有重复的元素,使每个元素只出现一次
    // 1.把框架复制进来,看一下 是否能行
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    for p.Next != nil {
        if p.Next.Next != nil && p.Next.Val == p.Next.Next.Val { // 2. 根据题目要求写一下这个的入口条件和下面的出口条件
            // 2. 这里就是下一个节点和下下个节点的值一样,用到了NN,额外判断nil
            // 找到区间入口了
            tmpP := p.Next // 重新做人
            // 3. 区间出口 这里其实和if条件里的是一样的条件
            for tmpP.Next != nil && tmpP.Val == tmpP.Next.Val {
                // 4.具体处理逻辑,得手动推演了,
                // 4.1 0 1 1 2,当前tmpP是1,最开始是符合,然后tmpP到第二个1,然后就不符合了,退出区间
                tmpP = tmpP.Next // 4.2 相等就往后走
            }
            // 此时tmpP指向了第二个1,题目要求每个保留一次,那就只保留最后一个,
            // 5.接回去 具体根据题目分析,注意之前的p以及p.Next指向的值,很关键
            // 5.1 此时p是0,tmpP是第二个1,中间的不要了(算是删除了)
            p.Next = tmpP
            // 6.这里需要考虑要不要break或者Continue,手动推演一下
        }
        p = p.Next // 不符合条件 继续下一个
    }
    return dummyHead.Next
}

删除排序链表中的重复元素(83)

题目:83. 删除排序链表中的重复元素

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func deleteDuplicates(head *ListNode) *ListNode {
	// 删除原始链表中所有重复数字的节点,只留下不同的数字
    // 1.把框架复制进来,看一下 是否能行
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    for p.Next != nil {
        if p.Next.Next != nil && p.Next.Val == p.Next.Next.Val { // 2. 根据题目要求写一下这个的入口条件和下面的出口条件
        	// 2.1 这里的入口就是有重复的
            // 找到区间入口了
            tmpP := p.Next // 重新做人
            // 3. 区间出口,这里就是按入口的条件一直执行到不符合要求,即为出口
            for tmpP.Next != nil && tmpP.Val == tmpP.Next.Val { // for 循环直到区间出口 
                // 4.具体处理逻辑,不断往后走,直到找到最后一个重复的
                tmpP = tmpP.Next
            }
            // 5.接回去 具体根据题目分析,注意之前的p以及p.Next指向的值,很关键.手动推演,注意这里是一个不留
            // 以 0 [1,1,1,2,3] 为例,走到这里的时候 p指向0,p.Next指向第一个1,tmpP指向的是最后一个1,最终结论是 一个不留
            p.Next = tmpP.Next
            // 6.这里需要考虑要不要break或者Continue,即p要不要移动,这里不能移动
            continue
        }
        p = p.Next // 不符合条件 继续下一个
    }
    return dummyHead.Next
}

两两交换链表中的节点(24)

题目:24. 两两交换链表中的节点
下面这个其实写废了,想写一个支持N=任意数的,但是忽略了本题的隐藏条件,不足N个不进行调整
以及另一个重要条件,N=任意数实际上对应K个一组翻转链表这个题目,难度是Hard。

func swapPairs(head *ListNode) *ListNode {
    // 1.把框架复制进来,看一下 是否能行
    dummyHead := &ListNode{Next:head}
    p := dummyHead
    index:=0
    count := 2
    for p.Next != nil {
        index++
        if index == 1 { // 2. 根据题目要求写一下这个的入口条件和下面的出口条件
            // 2.1 这里得用一个Index记录,index可以每次置0,也可以每次求余数,这里置0
            // 2.2 这里判断index == 1实际上是有点废话。可以结合下面的for循环进行优化。其实还好
            // 找到区间入口了
            tmpP := p.Next // 重新做人
            var newHead *ListNode
            // 3. 区间出口,这里同时要把Index增加的代码写上,避免忘啦
            for index <= count && tmpP.Next != nil { // for 循环直到区间出口 
                // !!! 不足的情况没考虑啊,比如1个,或者3个
                // !!! 本题 隐藏条件,不足x个不进行调整
                index++
                // 4.具体处理逻辑,这不就是链表逆序?!
                cur := tmpP
                tmpP = tmpP.Next
                cur.Next = newHead
                newHead = cur
            }
            // 5.接回去 具体根据题目分析,注意之前的p以及p.Next指向的值,很关键
            // 5. 对于0 - 1 2 3 4 --> 0 - 2 1 3 4,此时 p指向0,p.Next是1,tmpP是3,
            p.Next.Next = tmpP
            p.Next = newHead
            // 6.这里需要考虑要不要break或者Continue,手动推演一下,即能不能执行p = p.Next
            // 6.手动推演,避免空想。 0 - 2 1 3 4 此时p是0,需要让P=1
            p = p.Next.Next
            index=0
            continue
        }
        // 其实不需要这个了,写了也永远走不到 p = p.Next // 不符合条件 继续下一个
    }
    return dummyHead.Next
}

正确解法如下,实际上可以进一步化简,最外层的for其实可以和里面的if判断条件只保留一个。
手动推演部分这里给出画图示例,这个也是本题的复杂点,弄不好容易乱。同时需要注意 如果tmp1 := p.Next
这时候修改了tmp1.Next的值,实际上就是修改了p.Next的值,不要掩耳盗铃以为没有修改。
在这里插入图片描述

func swapPairs(head *ListNode) *ListNode {
	// 1.把框架复制进来,看一下 是否能行
	dummyHead := &ListNode{Next: head}
	p := dummyHead
	for p.Next != nil {
		if p.Next != nil && p.Next.Next != nil { // 2. 根据题目要求写一下这个的入口条件和下面的出口条件
			// 2.仅就本题而言,只需要判断 p.Next!=nil && p.Next.Next != nil 即可,之后要做的就是交换这两个
			// 找到区间入口了
			// 3.两个节点,一把处理了就行,不需要判断出口,
			// 4.交换这俩,手动推演一下 0 - 1 2 3--> 0 2 1 3,显然需要记录2,在纸上写一下
			// 5.这里交换的同时也接上去了
            tmp := p.Next.Next
            p.Next.Next = tmp.Next
            tmp.Next = p.Next
            p.Next = tmp
			
			// 6.看一下下一轮循环p的位置,
			p = p.Next.Next
			// // 3. 区间出口
			// for xx { // for 循环直到区间出口
			//     // 4.具体处理逻辑

			// }
			// 5.接回去 具体根据题目分析,注意之前的p以及p.Next指向的值,很关键
			// 6.即下一轮循环p的位置:手动推演一下
		} else {
			break // 没有需要操作的了,退出
		}
		// p = p.Next // 不符合条件 继续下一个,不需要了
	}
	return dummyHead.Next
}

K个一组翻转链表

题目:25. K 个一组翻转链表
这个是Hard类型的题目,会单独写一篇文章,详细介绍思考过程和编码过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1817609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络地图的发展历程

位置以及我们与位置的互动方式已在我们的生活中无处不在。我们的网络地图技术发展到今天这一步&#xff0c;涉及一系列个人、公司和想法&#xff0c;这些最终塑造了我们与世界的互动方式。这篇文章能帮助您了解我们是如何一步步走到今天的。即网络地图的发展历史! 制图学的简要…

笨蛋学算法之LeetCodeHot100_4_移动零(Java)

package com.lsy.leetcodehot100;public class _Hot4_移动零 {public static int[] moveZeroes(int[] nums){//判断数组是否为nullif(numsnull && nums.length0){return null;}/*** 初始化两个指针 i 和 noZero&#xff0c;其中 i 用于遍历数组&#xff0c;noZero 用于…

【讲解下Stylus入门方法】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

探索Facebook对世界各地文化的影响

随着数字化时代的到来&#xff0c;社交媒体已成为连接世界各地人们的重要平台之一。而在这个领域的巨头之一&#xff0c;Facebook不仅是人们沟通交流的场所&#xff0c;更是一座桥梁&#xff0c;将不同地域、文化的人们联系在一起。本文将探索Facebook对世界各地文化的影响&…

vue2.0和vue3.0获取当前文件夹下的所有vue文件区别

文章目录 vue2.0vue3.0当前文件夹下的所有vue文件区别 vue2.0 在Vue 2.0项目中&#xff0c;要获取当前文件夹下的所有.vue文件&#xff0c;你可以使用Node.js的文件系统模块&#xff08;fs&#xff09;和路径模块&#xff08;path&#xff09;来实现。以下是一个简单的示例&am…

IO流打印流

打印流 IO流打印流是Java中用来将数据打印到输出流的工具。打印流提供了方便的方法来格式化和输出数据&#xff0c;可以用于将数据输出到控制台、文件或网络连接。 分类:打印流一般是指:PrintStream&#xff0c;PrintWriter两个类 特点1:打印流只操作文件目的地&#xff0c;…

SwiftUI中自定义Shape与AnimateableData的使用

上一篇文章主要介绍了一下在SwiftUI中如何自定义Shape&#xff0c;本篇文章主要介绍Shape中的 一个关键的属性AnimatableData&#xff0c;它用于定义可以被动画化的数据。通过实现 Animatable 协议&#xff0c;可以让自定义视图或图形响应动画变化。 AnimatableData 是 Animata…

Github 2024-06-13 Go开源项目日报Top10

根据Github Trendings的统计,今日(2024-06-13统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目10TypeScript项目1Shell项目1多存储文件列表/WebDAV程序 创建周期:1265 天开发语言:Go协议类型:GNU Affero General Public License v…

【安装笔记-20240612-Linux-内网穿透服务之cpolar极点云】

安装笔记-系列文章目录 安装笔记-20240612-Linux-内网穿透服务之 cpolar 极点云 文章目录 安装笔记-系列文章目录安装笔记-20240612-Linux-内网穿透服务之 cpolar 极点云 前言一、软件介绍名称&#xff1a;cpolar极点云主页官方介绍 二、安装步骤测试版本&#xff1a;openwrt-…

.net8 blazor auto模式很爽(一)Blazor WebAssembly(WASM)与Server在.net8中的完美结合

我们在上一章中说到Blazor的WASM和Server模式各有优缺点。在.net8之前&#xff0c;这两种模式是独立的&#xff0c;你的项目只能选其中之一。但是.net8出现了一种叫自动模式&#xff0c;官方解释是&#xff1a;开发者在创建 Blazor 项目时不再显式区分是 Blazor Server 还是 Bl…

TIA博途Wincc与S7-1500 (V2.9) 或S7-1200 (V4.5) 及更高版本固件PLC通信失败的原因汇总

TIA博途Wincc与S7-1500 (V2.9) 或S7-1200 (V4.5) 及更高版本固件PLC通信失败的原因汇总 从TIA Portal V17开始,对于S7-1500PLC新增了V2.9的固件,S7-1200新增了V4.5的固件,PLC侧默认激活了“仅支持PG/PC和HMI的安全通信”, 注意事项1 如果PLC侧激活了“仅支持PG/PC和HMI的安…

java基础知识漏洞二

位移运算符 移位运算符是最基本的运算符之一&#xff0c;几乎每种编程语言都包含这一运算符。移位操作中&#xff0c;被操作的数据被视为二进制数&#xff0c;移位就是将其向左或向右移动若干位的运算。 移位运算符在各种框架以及 JDK 自身的源码中使用还是挺广泛的&#xff…

拼团+秒杀+优惠折扣+个人免签双端商城源码

源码说明 可用拼团秒杀优惠折扣个人免签双端商城源码&#xff0c;全功能完美双端&#xff0c;对接个人免签支付。 这款商城源码非常完整&#xff0c;整体也非常简洁&#xff0c;功能全面&#xff0c;没有那么多冗杂的多余页面和无用代码&#xff0c;拿到后优化了下整体代码&a…

学习grdecl文件格式之后的事情

学习了grdecl文件格式&#xff0c;搞地质的专业人士都知道&#xff0c;这是专门用在地质上的油藏软件&#xff08;个人感觉就是斯伦贝谢的Petrel的&#xff09;的一种文件格式&#xff0c;正好自己也在学习三维的开发&#xff0c;顺手写了一个简单的读取grdecl算法&#xff0c;…

HCIA11 网络安全之本地 AAA 配置实验

AAA 提供 Authentication&#xff08;认证&#xff09;、Authorization&#xff08;授权&#xff09;和 Accounting&#xff08;计费&#xff09;三种安全功能。 • 认证&#xff1a;验证用户是否可以获得网络访问权。 • 授权&#xff1a;授权用户可以使用哪些服务。 •…

DOM-获取元素

获取元素的方法&#xff1a; 方法一&#xff1a;根据id获取元素document.getElementById <div id"time">2024-6-4</div> 在script标签中&#xff1a;注意getElementById括号里面必须要有引号&#xff0c;获得的是对象类型 var timer document.getEle…

防火墙安全管理

大多数企业通过互联网传输关键数据&#xff0c;因此部署适当的网络安全措施是必要的&#xff0c;拥有足够的网络安全措施可以为网络基础设施提供大量的保护&#xff0c;防止黑客、恶意用户、病毒攻击和数据盗窃。 网络安全结合了多层保护来限制恶意用户&#xff0c;并仅允许授…

HTML静态网页成品作业(HTML+CSS)—— 家乡山西介绍网页(3个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有6个页面。 二、作品演示 三、代…

蒸汽加热产品时的热量计算

使用蒸汽加热产品时&#xff0c;蒸汽释放热量&#xff0c;热量被产品吸收&#xff0c;产品得以升温&#xff1b;蒸汽释放热量后&#xff0c;迅速冷凝&#xff0c;这个过程中&#xff0c;质量不发生改变&#xff0c;所以理论上&#xff0c;消耗多少蒸汽&#xff0c;就会产生多少…

20.1 JSON-JSON接口以及在Go语言中使用JSON

1. 简介 JSON即JavaScript对象表示法(JavaScript Object Notation)&#xff0c;是一种用于存储和交换数据的格式&#xff0c;是一种可供人类阅读和理解的纯文本格式。 JSON既可以键值对的形式&#xff0c;也可以数组的形式&#xff0c;表示数据。 JSON最初是JavaScript的一个…