编程导航算法通关村第 1关 | 两个链表的第一个公共节点

编程导航算法通关村第 1关 | 白银挑战

剑指 Offer 52. 两个链表的第一个公共节点

在这里插入图片描述

集合/map

  • 将headA中的链表,放在一个set集合中, 依次遍历headB, headB中第一个包含在set集合中的节点就是第一个公共子节点
ListNode getIntersectionNode(ListNode headA, ListNode headB) {// 将headA压入集合中Set<ListNode> statckA = new HashSet<>();ListNode temp = headA;while (temp != null) {statckA.add(temp);temp = temp.next;}ListNode tempB = headB;while (tempB != null) {if (statckA.contains(tempB)) {return tempB;}tempB = tempB.next;}return null;}

  • 将两个链表的节点分别压入栈中,然后同时出栈,当两个栈出栈的元素相等是,说明这个节点是公共子节点,当最后一个相等的元素出栈时,就是第一个公共子节点
 /*** 方法二:将两个链表的节点分别压入栈中,然后同时出栈,* 当两个栈出栈的元素相等是,* 说明这个节点是公共子节点,当最后一个相等的元素出栈时,就是第一个公共子节点*/ListNode getIntersectionNodeByStack(ListNode headA, ListNode headB) {//    同时压入两个栈中ListNode tempA = headA;ListNode tempB = headB;Stack<ListNode> stackA = new Stack<>();Stack<ListNode> stackB = new Stack<>();while (tempA != null) {stackA.push(tempA);tempA = tempA.next;}while (tempB != null) {stackB.push(tempB);tempB = tempB.next;}ListNode result = null;while (stackA.size() != 0 && stackB.size() != 0) {ListNode popA = stackA.pop();ListNode popB = stackB.pop();if (popA == popB) {result = popA;} else {break;}}return result;}

拼接两个字符串

在这里插入图片描述

 /*** 分别遍历两个链表* headA+headB;* headB+headA* 找到的第一个相等的点,就是两个的第一个公共子节点*/ListNode getIntersectionNodeByString(ListNode headA, ListNode headB) {ListNode tempA = headA;ListNode tempB = headB;//        考虑链表为空的情况if (headA == null) {return null;}if (headB == null) {return null;}while (tempA != tempB) {tempA = tempA.next;tempB = tempB.next;if (tempA != tempB) {if (tempA == null) {tempA = headB;}if (tempB == null) {tempB = headA;}}}return tempA;}

差和双指针

  • 先各自统计链表的长度
  • 计算长度的差值
  • 较长的链表移动差值距离
  • 同时向后移动,第一个相等节点便是第一个公共子节点
ListNode getIntersectionNodeBysubA(ListNode headA, ListNode headB) {ListNode tempA = headA;ListNode tempB = headB;//        考虑链表为空的情况if (headA == null) {return null;}if (headB == null) {return null;}
//       计算长度int lengthA = 0;int lengthB = 0;while (tempA != null) {tempA = tempA.next;lengthA++;}while (tempB != null) {tempB = tempB.next;lengthB++;}//        计算差值int sub = Math.abs(lengthA - lengthB);tempA = headA;tempB = headB;if (lengthA > lengthB) {int i = 0;while (i < sub) {tempA = tempA.next;i++;}} else if (lengthB > lengthA) {int i = 0;while (i < sub) {tempB = tempB.next;i++;}}
//        同时向后移动while (tempA != null && tempB != null) {if (tempA == tempB) {return tempA;}tempA = tempA.next;tempB = tempB.next;}return null;}

判断是否是回文序列

使用栈

  • 将链表中的元素全部压入栈中,遍历链表,与栈中弹出的元素是否相等,如何全部相等,则为回文序列
    public boolean isPalindrome(ListNode head) {Stack<ListNode> listNodes = new Stack<>();ListNode temp = head;while (temp != null) {listNodes.push(temp);temp = temp.next;}//temp = head;while (temp != null) {ListNode pop = listNodes.pop();if (temp.val != pop.val) {return false;}temp=temp.next;}return true;}

优化:只遍历一半,将前一半与后一半进行对比

    public boolean isPalindrome(ListNode head) {Stack<ListNode> listNodes = new Stack<>();ListNode temp = head;int length = 0;while (temp != null) {listNodes.push(temp);temp = temp.next;length++;}//
//        计算一半的值int cout = length / 2;temp = head;int i = 0;while (temp != null && i < cout) {ListNode pop = listNodes.pop();if (temp.val != pop.val) {return false;}temp = temp.next;i++;}return true;}

快慢指针+一半反转法

  • 首先,如果链表为空或者只有一个节点,那么它肯定是回文的,所以直接返回true。

  • 创建两个指针slow和fast,都指向链表的头部。slow指针每次移动一步,fast指针每次移动两步。这样,当fast指针到达链表的末尾时,slow指针就会在链表的中间。

  • 同时,我们还创建了pre和prepre两个指针,用于反转链表的前半部分。pre指针始终指向slow指针的前一个节点,prepre指针始终指向pre指针的前一个节点。在每次循环中,我们都将pre指针的next指向prepre,然后将prepre和pre分别更新为pre和slow,这样就可以反转链表的前半部分。

  • 如果链表的长度是奇数,那么fast指针会停在最后一个节点上,此时slow指针指向的是链表的中间节点,我们需要将slow指针向后移动一步,跳过中间节点。

  • 最后,我们同时遍历反转后的前半部分链表(从pre指针开始)和后半部分链表(从slow指针开始),如果发现有节点的值不相等,那么就返回false。如果所有节点的值都相等,那么就返回true。

  • 这个函数的时间复杂度是O(n),空间复杂度是O(1),其中n是链表的长度。

    public static boolean isPalindromeByFastAndSlow(ListNode head) {ListNode fast = head;ListNode slow = head;//        当fast到达末尾时,slow正好到达中间ListNode pre = null;while (fast != null && fast.next != null) {ListNode next = slow;fast = fast.next.next;slow = slow.next;//            进行翻转next.next = pre;pre = next;
//            next = slow;}System.out.println(pre.val);System.out.println(slow.val);if (fast != null) {slow = slow.next;}
//        此时pre就是翻转后链表的头结点,
//        slow是后半部分的头结点while (pre != null && slow != null) {if (pre.val != slow.val) {return false;}pre = pre.next;slow = slow.next;}return true;//}

删除倒数第N个元素

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

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

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

进阶:你能尝试使用一趟扫描实现吗?

Related Topics 链表 双指针 👍 2586 👎 0

public ListNode removeNthFromEnd(ListNode head, int n) {ListNode listNode = new ListNode(0);listNode.next = head;if (head == null) {return null;}//        if ( head.next == null &&  n == 1 ) {
//            return null;
//        }ListNode fast = head;ListNode slow = listNode;//int i = 0;while (i < n) {fast = fast.next;i++;}while (fast != null) {fast = fast.next;slow = slow.next;}
//        slow.ne//        删除slow 下一个节点的位置slow.next = slow.next.next;return listNode.next;}

删除重复元素

  • 设置虚拟头结点,防止出现删除head节点的情况
  • 保留重复的值,直接删除
 /**** 删除重复元素* */public ListNode deleteDuplicatesNo(ListNode head) {ListNode doumoNode = new ListNode(0);doumoNode.next = head;ListNode temp = doumoNode;while (temp != null && temp.next != null && temp.next.next != null) {if (temp.next.val == temp.next.next.val) {int x = temp.next.val;while (temp.next != null && temp.next.val == x) {temp.next = temp.next.next;}} else {temp = temp.next;}}return doumoNode.next;}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WireShark

文章目录 IP协议部分协议对应协议号路由器IP分片IP分片的缺点 TCP协议[TCP MSS](https://blog.csdn.net/meihualing/article/details/113739693) UDP协议ARP ICMPDHCPDNSFTP wireshark可以学习网络协议&#xff0c;解决一些问题 IP协议 IP指网际互连协议&#xff0c;Internet P…

ROS节点通信Demo

0 开始之前 确保你已经安装了ROS (Robot Operating System)。 1 第一步&#xff1a; 创建一个ROS包 在开始编程前&#xff0c;我们首先创建一个新的ROS包(package)。移动到你的catkin workspace的 src 文件夹下&#xff0c;然后运行以下命令&#xff1a; cd ~/catkin_ws/sr…

Sentinel整合OpenFegin

之前学习了openFeign的使用&#xff0c;我是超链接 现在学习通过Sentinel来进行整合OpenFegin。 引入OpenFegin 我们需要在当前的8084项目中引入对应的依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sta…

Spring:表达式语言

Spring EL 概述使用概述 Spring 表达式(Spring EL) 是一种功能强大的表达式语言,以 #{ 表达式 } 作为定界符,用于在运行时对对象进行访问和操作。通过使用 Spring 表达式达到简化开发、减少逻辑或配置的编写的目的。 使用 Spring EL 主要可以引用 bean ,调用其属性和方…

基于PyQt5的桌面图像调试仿真平台开发(13)图像边缘显示

系列文章目录 基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)…

ES系列--es初探

一、前言 一般传统数据库&#xff0c;全文检索都实现的很鸡肋&#xff0c;因为一般也没人用数据库存文本字段。进 行全文检索需要扫描整个表&#xff0c;如果数据量大的话即使对 SQL 的语法优化&#xff0c;也收效甚微。建 立了索引&#xff0c;但是维护起来也很麻烦&#xff0…

深入学习 Redis - 常用数据类型,结构认识

目录 一、Redis数据类型 Redis 数据类型结构简单认识 每个数据类型具体的编码方式 1.string 2.hash 3.list 4.set 5.zset 典中典&#xff1a;记数字&#xff01;&#xff01;&#xff01; 6.查看 key 对应 value 的实际编码方式 如果本文有帮助到你&#xff0c;不…

分布式应用之存储(Ceph)

分布式应用之存储&#xff08;Ceph) 一、数据存储类型 存储类型说明典型代表块存储一对一&#xff0c;只能被一个主机挂载使用数据以块为单位进行存储硬盘文件存储一对多&#xff0c;能同时被多个主机挂载/传输使用&#xff0c;数据以文件的形式存储&#xff08;元数据和实际…

python开发项目基于语音识别的智能垃圾分类系统的设计与实现

博主介绍&#xff1a;擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例…

火焰图性能监测

准备工作——安装perf 我是在github的codespace上搞的&#xff0c;可以按下面的方式安装perf&#xff1a; sudo apt install linux-tools-generic sudo apt install linux-cloud-tools-azure参考在WSL2中使用perf性能剖析工具 测试程序——简单的C程序 弄一个无限循环的C程…

【网络安全带你练爬虫-100练】第13练:文件的创建、写入

目录 目标&#xff1a;将数据写入到文件中 网络安全O 目标&#xff1a;将数据写入到文件中 开干 &#xff08;始于颜值&#xff09;打开一个&#xff0c;没有就会创建 with open(data.csv, modew, newline) as file: &#xff08;忠于才华&#xff09;开始写入数据 writer cs…

Pytorch:搭建卷积神经网络完成MNIST分类任务:

2023.7.18 MNIST百科&#xff1a; MNIST数据集简介与使用_bwqiang的博客-CSDN博客 数据集官网&#xff1a;MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges MNIST数据集获取并转换成图片格式&#xff1a; 数据集将按以图片和文件夹名为标签的…