LeetCode分类刷题----链表篇

news2024/11/21 1:32:17

链表

    • 链表
      • 1.移除链表元素
        • 203.移除链表元素
        • 707.设计链表
      • 2.反转链表
        • 206.反转链表
      • 3.两两交换链表中的节点
        • 24.两两交换链表中的节点
      • 4.删除链表中的倒数第N个节点
        • 19.删除链表的倒数第N个节点
      • 5.链表相交
        • 07.链表相交
      • 6.环形链表
        • 141.环形链表
        • 142.环形链表II

链表

1.移除链表元素

203.移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

思路1:原链表删除
要考虑两种情况,
如果要删除的元素是头节点,那么需要将头节点指向下一个。如果头节点不是目标元素。要想删除一个节点,必须知道这个节点的上一个节点,然后跳跃删除。

  public ListNode removeElements1(ListNode head, int val) {
           while(head!=null&&head.val==val) {
        	   head=head.next;
           }
           ListNode cur=head;
           while(cur!=null) {
        	   while(cur.next!=null&&cur.next.val==val) {
        		   cur.next=cur.next.next;
        	   }
        	   cur=cur.next;
           }
           return head;
	 
	  }

思路2:虚拟头节点
为链表新建一个头节点,这样就不用考虑头节点是不是要删除的元素了,直接进行跳跃删除。

 public ListNode removeElements(ListNode head, int val) {
         if(head==null) {
        	 return head;
         }
         ListNode dummy=new ListNode(-1,head);
         ListNode pre=dummy;
         ListNode cur=head;
         while(cur!=null) {
        	 if(cur.val==val) {
        		 pre.next=cur.next;
        	 }else {
        		 pre=cur;
        	 }
        	 cur=cur.next;
         }
         return dummy.next;
	 
	  }

707.设计链表

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

思路:
这道题实现的功能就比较多了,要注意控制节点的位置时要新声明一个节点,不能用head来操作,否则链表位置会乱套。思想是挺简单的,但是实现起来还是有很多坑的。

class ListNode { //定义一个链表结构,包括数值域,指针域
	int val;
	ListNode next;

	ListNode() {
	}

	ListNode(int val) {
		this.val = val;

	}

	ListNode(int val, ListNode next) {
		this.val = val;
		this.next = next;
	}
}

public class MyLinkedList {
	int size;
	ListNode head;

	public MyLinkedList() {//链表初始化,注意这里声明了一个头节点,和没有头节点的操作就大不相同
		head = new ListNode(0);
		size = 0;

	}

	public int get(int index) {
		ListNode cur = head;  //遍历位置信息时要新声明一个节点,不能直接操作head
		if (index < 0 || index > size - 1) {
			return -1;
		}
		while (index != 0) {
			cur = cur.next;
			index--;
		}
		return cur.next.val;

	}

	public void addAtHead(int val) { //在头部添加一个节点

		ListNode newNode = new ListNode(val);
		newNode.next = head.next;
		head.next = newNode;
		size++;

	}

	public void addAtTail(int val) { //在尾部添加一个节点,只要按顺序找到最后一个指针就行了 
		ListNode newNode = new ListNode(val);
		ListNode cur = head;
		while (cur.next != null) {
			cur = cur.next;
		}
		cur.next = newNode;
		size++;

	}

	public void addAtIndex(int index, int val) {
		if (index > size) {
			return;
		}
		ListNode newNode = new ListNode(val);
		if (index <= 0) {  //在头节点增加
			newNode.next = head.next;
			head.next = newNode;
			size++;
		} else {
			ListNode cur = head;
			while (index >= 1) { //在其他的位置增加,记好数就ok了
				cur = cur.next;
				index--;
			}
			newNode.next = cur.next;
			cur.next = newNode;
			size++;
		}

	}

	public void deleteAtIndex(int index) {
		ListNode cur = head;

		if (index < 0 || index > size - 1) {
			return;
		}
		if (index == 0) {
			head = head.next;
		}
		while (index >= 1) {  
			cur = cur.next;
			index--;
		}

		cur.next = cur.next.next; //找到目标位置直接跳步删除即可
		size--;
	}

	public static void main(String[] args) {
		MyLinkedList myLinkedList = new MyLinkedList();
		myLinkedList.addAtHead(2);

		// myLinkedList.addAtTail(3);
		myLinkedList.addAtIndex(0, 1);

		System.out.println(myLinkedList.get(1));
		// myLinkedList.deleteAtIndex(1);
		// System.out.println(myLinkedList.get(1));
	}
}

2.反转链表

206.反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:
在这里插入图片描述

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

思路1:正常反转
先保存了头指针的下一个节点,然后让头指针指向pre,然后pre和头指针都往后移。第二次看这个链表反转有很大的收获,之前我一直以为反转是要重新建一条链表,现在再看,知识需要把head.next的指针指向前边就可以了。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode next=null;
        ListNode pre=null;
        while(head!=null){
            next=head.next;
            head.next=pre;
            pre=head;
            head=next;
        }
        return pre;

    }
}

思路2:递归反转
思路和正常反转一样,只不过是套了一个递归函数,把后边那个语句换成递归函数就可以了。

public ListNode reverseList(ListNode head) {
	       
	        return reverse(head , null);

	    }
	 
	 public ListNode reverse(ListNode head,ListNode pre) {
		 if(head==null) {
			 return pre ;
		 }
		 ListNode next=null;
		 next=head.next;
		 head.next=pre;
		return reverse(next,head);
		 
	 }

3.两两交换链表中的节点

24.两两交换链表中的节点

在这里插入图片描述
思路:
判断好结束条件,然后申请两个临时指针,分别保存好下面两个节点的元素,然后交换即可。

 public ListNode swapPairs(ListNode head) {

	   ListNode dummy=new ListNode(0);//创建一个虚拟头节点
	   dummy.next=head;
	   ListNode cur=dummy; //进行操作的指针
	   ListNode temp1;  //两个临时指针
	   ListNode temp2;
	   while(cur.next!=null&&cur.next.next!=null) {//判断结束条件,链表节点是奇数还是偶数的情况都包含进去了
		   
		    temp1=cur.next;//保存下一个节点的指针
		    temp2=cur.next.next;//保存第二个节点的指针
		   cur.next=temp2;
		   temp1.next=temp2.next;
		   temp2.next=temp1;
		   cur=temp1; //移动cur指针,保证它在要操作的节点的前一个节点
	   }
	   return dummy.next;
	 }

4.删除链表中的倒数第N个节点

19.删除链表的倒数第N个节点

在这里插入图片描述
思路:
设立两个快慢指针,先让快指针走n+步,当快指针指向链表尾节点的时候,此时慢指针恰好走到要删除节点的前一个节点,此时对慢指针进行删除即可。设立虚拟头节点的好处是,避免了空指针异常。

 public ListNode removeNthFromEnd(ListNode head, int n) {
		 ListNode dummy=new ListNode(0);
		 dummy.next=head;
          //设立快慢指针,先让快指针移动n+1不,然后快慢指针同时移动
		 ListNode  fast=dummy;
		 ListNode slow=dummy;
		 n++;
		 while(n--!=0&&fast!=null) {
			 fast=fast.next;
		 }
		 while(fast!=null) {
			 fast=fast.next;
			 slow=slow.next;
		 }
		 
		 slow.next=slow.next.next;
		 return dummy.next;
	   
	 }

5.链表相交

07.链表相交

在这里插入图片描述
思路:
两个指针,当着两个指针走向尽头时,然后转向另一个链表的头节点,直到这两个链表相遇,因为这两个节点都走了同样的长度。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
	       if(headA==null||headB==null) {
	    	   return null;
	       }
	       ListNode pA=headA;
	       ListNode pB=headB;
	       while(pA!=pB) {
	    	   pA=pA==null?headB:pA.next;
	    	   pB=pB==null?headA:pB.next;
	       }
	       return pA;
	   
	  }

6.环形链表

141.环形链表

在这里插入图片描述
思路:
一个快指针,一个慢指针,当快指针和慢指针相遇的话一定会有环。

  public boolean hasCycle(ListNode head) {
		  if(head==null) {
			  return false;
		  }
	        ListNode slow=head;
	        ListNode fast=head;
	        if(head.next!=null) {
	        	fast=head.next;
	        }
	        while(fast.next!=null&&fast.next.next!=null) {
	        	
	        	if(fast==slow) {
	        		return true;
	        	}
	        	slow=slow.next;
	        	fast=fast.next.next;
	        }
	        return false;
	    }

142.环形链表II

在这里插入图片描述
思路:
和第一个不同的是,这个要返回环形链表的交点了。
设头节点到成环节点的距离为x,设成环节点到相遇节点的距离为y,设相遇节点到成环节点的距离为z。慢指针移动的距离为x+y.快指针走的节点数为x+n(y+z)。
因为快指针速度是慢指针的二倍,所以有2(x+y)=x+n(y+z)
整理得x=n(y+z)-y=(n-1)(y+z)+z。

当n=1的时候有x=z。当n不等于1的时候,说明快指针在环里移动了好几圈,也不影响题目
此时代表index1指针在环里多转了n-1圈,才遇到的index2,相遇节点也是入环的初始位置。

  public ListNode detectCycle(ListNode head) {
		  if(head==null) {
			  return null;
		  }
		 
	        ListNode slow=head;
	        ListNode fast=head;
	        
	        
	        while(fast!=null&&fast.next!=null) {
	        	
	        	
	        	slow=slow.next;
	        	fast=fast.next.next;
	        	if(fast==slow) {
	        		ListNode index1=fast;
	        		ListNode index2=head;
	        		while(index1!=index2) {
	        			index1=index1.next;
	        			index2=index2.next;
	        		}
	        		return index1;
	        		
	        	}
	        }
	        return null;
	    
	  }

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

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

相关文章

成功解决VMware安装操作系统出现分辨率的问题

文章目录问题重现问题原因问题解决方法一&#xff1a;拓展&#xff1a;1. 电脑分辨率&#xff1a;2. xrandr命令3. 查询后如果没有合适的分辨率解决方案参考资料问题重现 如下图&#xff1a; 在VMware16上安装ubuntu操作系统的时候&#xff0c;出现分辨率问题&#xff0c; 导致…

如何录屏有声音?如何录制带声音的视频

平常我们会通过录屏的方式录制电脑画面&#xff0c;然后再保存下来。那您是不是遇到过这种情况&#xff1a;录制的录屏文件只有画面没有声音。没有声音的视频还能修复吗&#xff1f;如何录屏有声音&#xff1f;怎样才能录制带声音的视频&#xff1f;今天小编教大家如何在录屏的…

前端基础(十三)_定时器(间歇定时器、延迟定时器)

定时器 定时器共两种&#xff0c;setInterval及setTimeout&#xff1a; 1、setInterval&#xff1a;重复执行或者叫间歇执行&#xff0c;即隔某个时间就执行一次 2、setTimeout&#xff1a;延迟执行&#xff0c;延迟某个特定的时间开始执行&#xff0c;只执行一次 语法&#x…

代码随想录算法训练营第10天 232.用栈实现队列、225. 用队列实现栈

代码随想录算法训练营第10天 232.用栈实现队列、225. 用队列实现栈 用栈实现队列 力扣题目链接(opens new window) 使用栈实现队列的下列操作&#xff1a; push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() –…

十分好用的跨浏览器测试工具,建议收藏!!!

跨浏览器测试是确保web应用程序的功能在不同浏览器、浏览器版本和操作系统直接保持功能和质量一致的过程&#xff0c;可以为用户提供更好的用户体验&#xff0c;帮助企业通过更易访问的网站获得满意客户&#xff0c;可以使web应用程序在不同平台上兼容。在跨浏览器测试过程中&a…

Vulnhub靶机:DIGITALWORLD.LOCAL_ DEVELOPMENT

目录介绍信息收集主机发现主机信息探测网站探测SSH登录lshell绕过sudo提权介绍 系列&#xff1a;digitalworld.local&#xff08;此系列共9台&#xff09; 发布日期&#xff1a;2018 年 12 月 28 日 难度&#xff1a;中级 运行环境&#xff1a;Virtualbox运行失败&#xff0c;…

写作的“收益”超乎想象

十余年写作经验倾囊相授&#xff0c;全面提升你的技术写作能力&#xff01; 前言 技术从业人员普遍比较务实&#xff0c;也就是用心做好分配给自己的任务&#xff0c;努力担负起自己应尽的责任&#xff0c;因为大家都相信&#xff0c;付出必有回报&#xff0c;金字总会闪光。 …

【干货】普通单双面板的生产工艺流程(二)

衔接上文&#xff0c;继续为朋友们分享普通单双面板的生产工艺流程。 如图&#xff0c;第二道主流程为钻孔。 钻孔的目的为&#xff1a; 对PCB进行钻孔&#xff0c;便于后续识别、定位、插件及导通。 目前&#xff0c;行业内主流的PCB钻孔方式为&#xff1a;机械钻孔、激光钻…

引蜘蛛软件哪款有效果?多少钱怎么购买?

引蜘蛛软件哪款有效果?多少钱怎么购买?怎教你查看一个IP地址是不是搜索引擎官方蜘蛛的参考方法#IP地址#官方蜘蛛#搜索引擎官 大家好&#xff0c;今天给大家分享的是关于怎么查看一个 ip 地址是不是搜索引擎官方蜘蛛的参考方法。 很多做网站的小伙伴们肯定会用到这个方式。 有…

用 Python 制作空间数据可视化

大数据时代到来&#xff0c;随着智能设备与物联网技术的普及&#xff0c;人在社会生产活动中会产生大量的数据。在我们的日常活动中&#xff0c;手机会记录下我们到访过的地点&#xff1b;在使用城市公交IC卡、共享单车等服务时&#xff0c;服务供应商会知道这些出行需求产生的…

gdb相关知识

cdir和cwd 当我们用gdb的命令show dir的时候&#xff0c;显示源码搜寻目录&#xff1a; cdir: 代表编译路径&#xff0c;可以打个断点&#xff0c;然后用info source命令查看。 cwd: 代表当下调试的目录&#xff0c;直接用pwd就可以。 添加新的搜索路径 dir /opt/nmt搜索路…

Gemini撕DCG诉感情被骗,灰度百亿大饼持仓却不会爆雷?

插播&#xff1a;《刘教链比特币原理》音频课正在连载中。今天次条是第一章第2节“1-2 比特币的特点和使用”&#xff0c;推荐每一位读者学习。点击此处查看付费合集详情[链接]以及上一课“1-1 五分钟告诉你什么是比特币和区块链”[链接]。* * *比特币今晨突然急速上涨&#xf…

Qt OpenGL(09)在着色器中实现旋转的彩色正方体

文章目录在着色器中实现旋转的彩色正方体旋转矩阵沿x轴旋转&#xff1a;沿y轴旋转&#xff1a;沿z轴旋转&#xff1a;在顶点着色器中实现顶一个vec3的变量 theta计算余弦和正弦值定义3个旋转矩阵最终代码在着色器中实现旋转的彩色正方体 一直觉得用OpenGL 画一个立方体或者彩色…

黑马学ElasticSearch(八)

目录&#xff1a; &#xff08;1&#xff09;黑马旅游案例-搜素-分页 &#xff08;2&#xff09;黑马旅游案例-条件过滤 &#xff08;3&#xff09;黑马旅游案例-我附近的酒店 &#xff08;4&#xff09;黑马旅游案例-广告置顶 &#xff08;1&#xff09;黑马旅游案例-搜素…

C语言 自定义类型 之 【结构体】

文章目录前言结构体类型的声明结构的自引用结构体变量的定义和初始化定义初始化结构体内存对齐结构体传参结构体实现位段什么是位段&#xff1f;位段的内存分配位段的跨平台问题位段的应用写在最后前言 C语言中结构体是一种用户自定义的数据类型&#xff0c;它相当于一个小型的…

Python3 微信支付(小程序支付)V3接口

起因&#xff1a; 因公司项目需要网上充值功能&#xff0c;从而对接微信支付&#xff0c;目前也只对接了微信支付的小程序支付功能&#xff0c;在网上找到的都是对接微信支付V2版本接口,与我所对接的接口版本不一致&#xff0c;无法使用&#xff0c;特此记录下微信支付完成功能…

中缀表达式怎么转后缀表达式

对于中缀表达式&#xff1a;1 2 * 3 中缀表达式是相对于人来说的&#xff0c;因为我们人是会判断和*的运算优先级谁高谁低 但是计算机是不会判断的&#xff0c;因为计算机是默认从左向右读取数据&#xff0c;它先遇到 就会计算&#xff0c;其结果是不对的。它不会提前看到后面…

使用nvm实现多个Node.js版本之间切换

使用nvm实现多个Node.js版本之间切换1.先卸载掉本系统中原有的node版本。2.去github上下载nvm安装包3.安装node常用的一些nvm命令什么是nvm&#xff1f; nvm是一个简单的bash脚本&#xff0c;它是用来管理系统中多个已存的Node.js版本。这样做主要是我的vue项目对node的版本有…

6.3、动态主机配置协议 DHCP

1、DHCP的作用 如下所示&#xff0c;我们如何配置用户主机&#xff0c;才能是用户主机正常访问网络中的 Web 服务器 即&#xff1a;需要给网络中的各主机正确配置 IP 地址、子网掩码、默认网关、DNS 服务器等网络相关配置信息 例如&#xff1a;如下所示&#xff0c;手工配置的…

Wind X R2 蓝牙5.2双模热插拔PCB

键盘使用说明索引&#xff08;均为出厂默认值&#xff09;软件支持一些常见问题解答&#xff08;FAQ&#xff09;首次使用测试步骤蓝牙配对规则&#xff08;重要&#xff09;蓝牙和USB切换键盘默认层默认触发层0的FN键配置的功能默认功能层1配置的功能默认的快捷键蓝牙参数蓝牙…