链表题目之指定区间处理

前言

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

理论

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

  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类型的题目,会单独写一篇文章,详细介绍思考过程和编码过程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Adobe Photoshop cc快速抠图与精致抠图方法

一、背景 Photoshop cc绝对是最好用的抠图and修图软件&#xff0c;但是即使最简单的抠图&#xff0c;每次用时都忘记怎么做&#xff0c;然后再去B站搜&#xff0c;非常费时&#xff0c;下面记录一下抠图过程&#xff0c;方便查阅。 一、Adobe Photoshop快速抠图 选择——主体…

出现 Error creating bean with name xxx defined in class 的解决方法

目录 1. 问题所示2. 原理分析3. 解决方法4. Demo1. 问题所示 此类问题来自私信,本着探究问题的缘由,理性分析了下,让大家也学会分析Bug解决Bug 问题如下所示: Error creating bean with name xxx defined in class截图如下所示: 2. 原理分析 通用的原理进行分析 出现…

基于STM32和人工智能的智能家居监控系统

目录 引言环境准备智能家居监控系统基础代码实现&#xff1a;实现智能家居监控系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统4.4 用户界面与数据可视化应用场景&#xff1a;智能家居环境监控与管理问题解决方案与优化收尾与总结 1. 引言 随着智能家居技术的发展&…

Chrome/Edge浏览器视频画中画可拉动进度条插件

目录 前言 一、Separate Window 忽略插件安装&#xff0c;直接使用 注意事项 插件缺点 1 .无置顶功能 2.保留原网页&#xff0c;但会刷新原网页 3.窗口不够美观 二、弹幕画中画播放器 三、失败的尝试 三、Potplayer播放器 总结 前言 平时看一些视频的时候&#xff…

java实现文件的压缩及解压

一、起因 开发中需要实现文件的压缩及解压功能&#xff0c;以满足某些特定场景的下的需要&#xff0c;在此说下具体实现。 二、实现 1.定义一个工具类ZipUtils,实现文件的压缩及解压&#xff0c;代码如下&#xff1a; import java.io.*; import java.nio.charset.Charset; impo…

动手学操作系统(六、获取物理内存容量)

动手学操作系统&#xff08;六、获取物理内存容量&#xff09; 在上一节中&#xff0c;我们介绍了保护模式和实模式的区别&#xff0c;保护模式的最大特点是“大”&#xff0c;“大”是指寻址空间大&#xff0c;在进入保护模式之后&#xff0c;我们还将要接触虚拟内存、内存管…

迅狐跨境商城系统|全平台兼容|前端采用uni-app跨端框架,后端采用ThinkPHP5框架

高效实现全平台兼容的迅狐跨境商城系统 迅狐跨境商城系统是一款专为跨境电商企业设计的全平台兼容系统。其前端采用uni-app跨端框架&#xff0c;后端采用ThinkPHP5框架&#xff0c;旨在实现高效的开发和运营管理。 1. 全平台兼容的前端设计 迅狐跨境商城系统的前端采用uni-a…

C# WinForm —— 34 ToolStrip 工具栏 介绍

1. 简介 工具栏 ToolStrip&#xff0c;一般紧贴在菜单栏下面 2. 属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到Enabled控件是否启用Dock定义要绑定到容器的控件边框&#xff0c;默认是topAnchor定义某个控件绑定到的容器的边缘。当控件锚定到某个边缘时&a…

基于MCGS的双容水箱液位控制系统设计【MCGS+MATLAB+研华工控机】

摘 要 液位控制技术在众多工业领域中扮演着至关重要的角色。无论是化工、制药、食品加工还是水处理行业&#xff0c;对液位进行精确控制都是保证生产流程稳定、产品质量可靠的关键环节。因此基于实验平台设计了液位自动控制系统。首先&#xff0c;根据实际液位的控制需求&…

NHANES数据库及应用

NHANES数据库使用 NHANES - National Health and Nutrition Examination Survey Homepage (cdc.gov) 保姆级NHANES数据库使用教程 - 哔哩哔哩 (bilibili.com) 该数据库所涉及的参与者的死亡状况 &#xff1a;Data Access - National Death Index (cdc.gov) TyG对CVD的影响研…

简单的基于Transformer的滚动轴承故障诊断(Pytorch)

递归神经网络在很长一段时间内是序列转换任务的主导模型&#xff0c;其固有的序列本质阻碍了并行计算。因此&#xff0c;在2017年&#xff0c;谷歌的研究人员提出了一种新的用于序列转换任务的模型架构Transformer&#xff0c;它完全基于注意力机制建立输入与输出之间的全局依赖…

【JAVA】javadoc,如何生成标准的JAVA API文档

目录 1.什么是JAVA DOC 2.标签 3.命令 1.什么是JAVA DOC 当我们写完JAVA代码&#xff0c;别人要调用我们的代码的时候要是没有API文档是很痛苦的&#xff0c;只能跟进源码去一个个的看&#xff0c;一个个方法的猜&#xff0c;并且JAVA本来就不是一个重复造轮子的游戏&#…

javaWeb项目-ssm+vue网上租车系统功能介绍

本项目源码&#xff1a;java-基于ssmvue的网上租车系统源码说明文档资料资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、…

Python基础教程(十五):面向对象编程

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

Diffusers代码学习-SDXL

Stable Diffusion XL&#xff08;SDXL&#xff09;是一个强大的文本到图像生成模型&#xff0c;它以三种关键方式迭代以前的Stable Differsion模型&#xff1a; 1. UNet大3倍&#xff0c;SDXL将第二个文本编码器&#xff08;OpenCLIP-ViT-bigG/14&#xff09;与原始文本编码器…

Kubernetes 基础架构最佳实践:从架构设计到平台自动化

本文探讨了如何将DigitalOcean Kubernetes (DOKS)应用于生产环境&#xff0c;并提供实现生产准备&#xff08;production readiness&#xff09;的指导。 规划您的基础架构 Kubernetes 基础架构的规划至关重要&#xff0c;因为它为稳定且可扩展的应用部署平台奠定了基础。通过适…

Coze+Discord:打造你的免费AI助手(教您如何免费使用GPT-4o/Gemini等最新最强的大模型/Discord如何正确连接Coze)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 准备Discord📝 准备Coze🔌 连接💡 测试效果⚓️ 相关链接 ⚓️📖 介绍 📖 你是否想免费使用GPT-4o/Gemini等最新最强的大模型,但又不想花费高昂的费用?本文将教你如何通过Coze搭建Bot,并将其转发…

计算机网络(2) 网络层:IP服务模型

一.Internet Protocol在TCP/IP四层模型中的作用 第三层网络层负责数据包从哪里来到哪里去的问题。传输层的数据段提交给网络层后&#xff0c;网络层负责添加IP段&#xff0c;包含数据包源地址与目的地址。将添加IP段的数据包交由数据链路层添加链路头形成最终在各节点传输中所需…

YASKAWA机器人HW1171921-B电缆维修

安川机器人作为现代工业自动化的重要设备&#xff0c;其稳定运行对于生产线的连续性和效率至关重要。然而&#xff0c;随着使用时间的增长&#xff0c;可能会出现各种YASKAWA机器人本体线缆故障&#xff0c;如断线、短路、接触不良等。 一、安川工业机器人电缆维修前的准备 在进…

Java | Leetcode Java题解之第147题对链表进行插入排序

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode insertionSortList(ListNode head) {if (head null) {return head;}ListNode dummyHead new ListNode(0);dummyHead.next head;ListNode lastSorted head, curr head.next;while (curr ! null) {if (…