《算法通关村第一关——链表经典问题之两个链表的第一个公共子节点问题笔记》

news2025/1/16 21:15:46

《算法通关村第一关——链表经典问题之两个链表的第一个公共子节点问题笔记》

问题描述

输入两个链表,找出他们的第一个公共节点。

例如下面的两个链表

在这里插入图片描述

两个链表的头节点都是已知的,相交之后成为一个单链表,但是相交的位置未知,并且相交之前的节点数也是未知,请设计算法找到两个链表的合并点。

理解题目以及解法

理解两个图

在这里插入图片描述

在这里插入图片描述

上图中第一个图是满足要求的,第二个不满足,因为我们说链表是环环相扣的,核心是一个节点只能有一个后继,但不代表一个节点只能有一个被指向。

这里提供三种方法

暴力遍历

就是利用二重遍历,一个元素一个元素的比较,比较到一样的时候就返回一样的节点,如果没有,那么就返回空。

利用哈希和集合

先把一个链表全部存入到HashSet中,然后遍历另一个链表,判断集合中的元素是否含有遍历的节点,如果有的话返回该节点,如果遍历完后还没有就返回空,代表就是没有公共的节点。

利用栈

为什么可以利用栈,要抓住公共节点的特点,就是他们到了公共节点以后的元素都是相等的了,所以只要把两条链表的元素压入栈中,两个栈同时判断栈出口的元素是否相等,如果一开始就不相等,那么两条链表就没有公共元素,如果有的话,就可以通过返回第一个出现不相等元素的时候返回最后一个相等的元素。

在这里插入图片描述

上代码

三种方法代码:

package AlgorithmFirst;

import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

/**
 * 旨在解决两个链表的第一个公共节点
 * @author xwhking
 */
public class CommonNodeOfTwoLinkedList {
    /**
     * 通过遍历解决
     * @param one 第一个链表
     * @param two 第二个链表
     * @return 返回第一个公共节点
     */
    public static LinkedNode SolveByTraversal(LinkedNode one , LinkedNode two){
        while(one!=null){
            LinkedNode temp = two;
            while(temp!=null){
                if(one == temp){
                    return temp;
                }
                temp = temp.getNext();
            }
            one = one.getNext();
        }
        return null;
    }

    /**
     * 利用Hash 解决
     * @param one 第一个链表头
     * @param two 第二条链表头
     * @return
     */
    public static LinkedNode SolveByHash(LinkedNode one,LinkedNode two){
        Set<LinkedNode> nodeSet = new HashSet<>(LinkedNode.getListLength(one));
        while(one != null){
            nodeSet.add(one);
            one = one.getNext();
        }
        while(two != null){
            if(nodeSet.contains(two)){
                return two;
            }
            two = two.getNext();
        }
        return null;
    }

    public static LinkedNode SolveByStack(LinkedNode one, LinkedNode two){
        Stack<LinkedNode> stackA = new Stack<>();
        Stack<LinkedNode> stackB = new Stack<>();
        while(one != null){
            stackA.add(one);
            one = one.getNext();
        }
        while(two!=null){
            stackB.add(two) ;
            two = two.getNext();
        }
        LinkedNode cur = null;
        while(stackB.size() > 0 && stackA.size() > 0){
            if(stackB.peek() != stackA.peek()){
                System.out.println("不同节点");
                return cur;
            }
            cur = stackA.pop();
            stackB.pop();
        }
        System.out.println("到这里应该是出问题了");
        return null;
    }

    public static void main(String[] args) {
        LinkedNode commonLinked = new LinkedNode(100);
        commonLinked = LinkedNode.insertNode(commonLinked,new LinkedNode(101));
        commonLinked = LinkedNode.insertNode(commonLinked,new LinkedNode(102));
        commonLinked = LinkedNode.insertNode(commonLinked,new LinkedNode(103));
        LinkedNode aLinked = new LinkedNode(1 );
        aLinked = LinkedNode.insertNode(aLinked,new LinkedNode(2) );
        aLinked = LinkedNode.insertNode(aLinked,new LinkedNode(3) );
        aLinked = LinkedNode.insertNode(aLinked,new LinkedNode(4) );
        aLinked = LinkedNode.insertNode(aLinked,commonLinked);
        LinkedNode bLinked = new LinkedNode(-1);
        bLinked = LinkedNode.insertNode(bLinked,new LinkedNode(-2));
        bLinked = LinkedNode.insertNode(bLinked,commonLinked);
        System.out.println("打印a链表");
        LinkedNode.printLinkedList(aLinked);
        System.out.println("打印b链表");
        LinkedNode.printLinkedList(bLinked);
        System.out.println("打印一样的元素");
        LinkedNode result = SolveByTraversal(aLinked,bLinked);
        LinkedNode.printLinkedList(result);
        System.out.println("打印Hash结果:"  );
        LinkedNode result1 = SolveByHash(aLinked,bLinked);
        LinkedNode.printLinkedList(result1);
        System.out.println("打印栈结果:");
        LinkedNode result2 = SolveByStack(aLinked,bLinked);
        LinkedNode.printLinkedList(result2);
    }
}

链表:

package AlgorithmFirst;

public class LinkedNode {
    private int data;
    private LinkedNode next;
    public LinkedNode(int data){
        this.data = data;
    }

    /**
     * 获取数据
     * @return 数据值
     */
    public int getData(){
        return this.data;
    }

    /**
     * 设置数据的值
     * @param data 数据
     */
    public void setData(int data){
        this.data = data;
    }

    /**
     * 获取下一个节点
     * @return 当前节点的下一个几点
     */
    public LinkedNode getNext(){
        return this.next;
    }

    /**
     * 设置下一个节点的值
     * @param next 下一个节点
     */
    public void setNext(LinkedNode next){
        this.next = next;
    }

    /**
     * 获取链表长度
     * @param head 头节点
     * @return
     */
    public static int getListLength(LinkedNode head){
        int length = 0 ;
        LinkedNode node = head;
        while(node != null){
            length ++ ;
            node = node.next;
        }
        return length;
    }

    /**
     * 缺省位置,直接在最后插入
     * @param head 头节点
     * @param insertNode 插入节点
     * @return 头节点
     */
    public static LinkedNode insertNode(LinkedNode head,LinkedNode insertNode){
        int size = getListLength(head);
        // return insertNode(head,insertNode,size+1); 修改一下,以便insertNode后面的元素能够全部插入进来。
        int count = 1;
        LinkedNode temp = head;
        while(temp != null){
            if(count == size ){
                temp.next = insertNode;
            }
            temp = temp.next;
            count++;
        }
        return head;
    }

    /**
     * 指定位置插入
     * @param head 头节点
     * @param nodeInsert 插入节点
     * @param position 插入位置,从1开始
     * @return 返回头节点
     */
    public static LinkedNode insertNode(LinkedNode head , LinkedNode nodeInsert, int position){
        if (head == null ){
            // 如果head == null 表示当前链表为空,可以直接返回当前节点,或者报异常,这里直接把它当作头节点。
            return nodeInsert;
        }
        // 已经存在的元素的个数
        int size = getListLength(head);
        if(position > size + 1 || position < 1 ){
            System.out.println("位置参数越界");
            return head;
        }

        // 表头插入
        if(position == 1 ){
            nodeInsert.next = head;
            // 这里可以直接 return nodeInsert
            head = nodeInsert;
            return head;
        }

        LinkedNode pNode = head;
        int count = 1;
        // 这里position 被上面的size限制住了,不用考虑pNode = null
        while(count < position -1){
            pNode = pNode.next;
            count ++ ;
        }
        nodeInsert.next = pNode.next;
        pNode.next = nodeInsert;
        return head;
    }

    /**
     * 缺省参数的删除最后一个节点
     * @param head 链表头节点
     * @return 返回新链表头节点
     */
    public static LinkedNode deleteNode(LinkedNode head){
        int size = getListLength(head);
        return deleteNode(head,size);
    }

    /**
     * 根据位置删除节点
     * @param head 链表头节点
     * @param position 位置从1开始,最大链表大小 超出不删除,返回原头节点。
     * @return 新链表头节点
     */
    public static LinkedNode deleteNode(LinkedNode head , int position){
        if(head == null) {
            // 链表为空,无法删除
            return null ;
        }
        int size = getListLength(head);
        if(position > size || position < 1 ){
            System.out.println("输入参数有误" );
            return head;
        }
        if( position == 1){
            return head.next;
        }else{
            LinkedNode cur = head;
            int count = 1;
            while(count<position-1){
                cur = cur.next;
                count ++;
            }
            LinkedNode curNode = cur.next;
            cur.next = curNode.next;
            //上面两行可以简化成 : cur.next = cur.next.next
        }
        return head;
    }

    public static void  printLinkedList(LinkedNode head){
        int count = 0;
        while(head != null){
            System.out.println("第 "+ ++count +" 个:"+ head.data);
            head = head.next;
        }
    }

    public static void main(String[] args) {
        LinkedNode head = new LinkedNode(0);
        for(int i = 0 ; i<10 ; i++){
            head = LinkedNode.insertNode(head,new LinkedNode(i+1));
        }
        System.out.println("origin:");
        printLinkedList(head);
        head = deleteNode(head,3);
        System.out.println("delete the third ");
        printLinkedList(head);
        head = deleteNode(head);
        System.out.println("delete the last one");
        printLinkedList(head);
        head = insertNode(head,new LinkedNode(11));
        System.out.println("insert one from last");
        printLinkedList(head);
        head = insertNode(head,new LinkedNode(22222),1);
        System.out.println("insert to first");
        printLinkedList(head);
    }

}

近期在自学 Java 做项目,加入了一个编程学习圈子,里面有编程学习路线和原创的项目教程,感觉非常不错。还可以 1 对 1 和大厂嘉宾交流答疑,也希望能对大家有帮助,扫 ⬇️ 二维码即可加入。

在这里插入图片描述

也可以点击链接:我正在「编程导航」和朋友们讨论有趣的话题,你⼀起来吧?

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

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

相关文章

leaflet地图线段和区域的回显

线段回显 searchLineArr: [], // 存放搜索到的路段或者道路的线段drawSearchLineArr(line) {/* 移除线段 */this.searchLineArr.forEach((polyline) > {polyline.remove();});this.searchLineArr []/* 移除线段 */this.map.panTo(JSON.parse(line)[0]); // 地图视图移动到线…

Java扫雷游戏总结 (小项目)

【尚学堂Java开发扫雷游戏项目】1个半小时做出java扫雷小游戏_java小游戏_Java游戏开发_Java练手项目_java项目实战_java初级项目_哔哩哔哩_bilibili 前言&#xff1a; 记录的是大致的写代码过程为了视觉上更清晰&#xff0c;下面只是放出了完成该功能的核心代码&#xff0c;把…

分享Java NET Python三大技术下AutojsPro7云控代码

引言 有图有真相&#xff0c;那短视频就更是真相了。下面是三大语言的短视频。 Java源码版云控示例&#xff1a; Java源码版云控示例在线视频 Net源码版云控示例&#xff1a; Net源码版云控示例在线视频亚丁号-知识付费平台 支付后可见 扫码付费可见 Python源码版云控示例&…

【容器】Docker(学习笔记)

一、初识Docker 1、Docker概述 Docker 是一个开源的应用容器擎。 诞生于 2013 年初&#xff0c;基于 Go 语言实现&#xff0c;dotcloud 公司出品&#xff08;后改名为Docker Inc&#xff09;。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&a…

【小黑嵌入式系统第三课】嵌入式系统硬件平台(一)——概述、总线、存储设备(RAMROMFLASH)

上一课&#xff1a; 【小黑嵌入式系统第二课】嵌入式系统的概述&#xff08;二&#xff09;——外围设备、处理器、ARM、操作系统 文章目录 一、概述二、总线1. 总线的概念1.1 总线结构1.2 总线类型1.2.1 数据总线1.2.2 程序总线1.2.3 数据地址总线1.2.4 程序地址总线 2. 总线协…

new Object()到底占用几个字节

Java内存模型 对象内存中可以分为三块区域&#xff1a;对象头(Header)&#xff0c;实例数据(Instance Data)和对齐填充(Padding)&#xff0c;以64位操作系统为例(未开启指针压缩的情况)Java对象布局 如下图所示&#xff1a; 其中对象头中的Mark Word中的详细信息在文章synchr…

地下水与饮用水提标处理树脂

随着饮用水和地下水污染物检测技术水平的不断提高&#xff0c;世界各国管理机构跟踪监测的水体污染数目也不断增加。近年来&#xff0c;针对砷、高氯酸盐和铀等水体污染物&#xff0c;新的强化控制措施不断的付诸实施。此外&#xff0c;用氯化物及其衍生物进行水体消毒会带来诸…

leetcode 1143. 最长公共子序列、1035. 不相交的线、53. 最大子数组和

1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…

【ajax】withCredentials

默认值&#xff1a;false。在获取同域资源时设置 withCredentials 没有影响。 true&#xff1a;在跨域请求时&#xff0c;会携带用户凭证 false&#xff1a;在跨域请求时&#xff0c;不会携带用户凭证&#xff1b;返回的 response 里也会忽略 cookie ajax中的作用 跨域请求时…

药物滥用第一篇介绍

AMP&#xff1a; Ampicillin&#xff0c;中文名氨苄青霉素&#xff0c;同义名氨苄西林&#xff0c;一种β-内酰胺类抗生素&#xff0c;属于青霉素家族的一员&#xff0c;化学式为C16H19N3O4S&#xff0c;可治疗多种细菌感染。 氨苄西林为半合成的广谱青霉素&#xff08;结构如上…

基于单片机设计的家用自来水水质监测装置

一、前言 本文介绍基于单片机设计的家用自来水水质监测装置。利用STM32F103ZET6作为主控芯片&#xff0c;结合水质传感器和ADC模块&#xff0c;实现对自来水水质的检测和监测功能。通过0.96寸OLED显示屏&#xff0c;将采集到的水质数据以直观的方式展示给用户。 随着人们对健…

Unity DOTS World Entity ArchType Component EntityManager System概述

最近DOTS终于发布了正式的版本, 我们来分享以下DOTS里面地几个关键概念&#xff0c;方便大家上手学习掌握Unity DOTS开发。 Unity DOTS 中所有的Entities 都是被放到World世界中。每个Entity在它所在的World里面有唯一不同的ID号来区分。DOTS项目中可以同时有多个World。每个W…

04 接口隔离原则

官方定义 <<代码整洁之道>>作者罗伯特 C马丁 为 “接口隔离原则” 的定义是&#xff1a;客户端不 应该被迫依赖于它不使用的方法&#xff08;Clients should not be forced to depend on methods they do not use&#xff09;。 该原则还有另外一个定义&#xff1…

【Proteus仿真】【STM32单片机】太阳能追光系统设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用LCD1602液晶、光敏传感器、PCF8591 ADC模块、按键模块、28BYJ48步进电机驱动模块、直流电机模块等。 主要功能&#xff1a; 系统运行后&#x…

网络工程师知识点6

91、3、IP ABC类私有地址和个数 A类私有地址1个&#xff1a;10.0.0.0/8 B类私有地址16个&#xff1a;172.16.0.0~172.31.0.0/16 C类私有地址256个&#xff1a;192.168.0.0~192.168.255.0/24 92、拥塞管理机制的实现过程分为哪两步&#xff1f; 第一步&#xff1a;将准备从一个…

MATLAB中sos2tf函数用法

目录 语法 说明 示例 二阶节系统的传递函数表示 sos2tf函数的功能是将数字滤波器的二阶节&#xff08;section&#xff09;数据转换为传递函数形式。 语法 [b,a] sos2tf(sos) [b,a] sos2tf(sos,g) 说明 [b, a] sos2tf(sos) 返回由 sos 描述的离散时间系统的传递函数系…

璟丰机电丨Parker派克江苏代理商 供应高品质驱动器和电机产品

苏州璟丰机电有限公司是一家专注于工业自动化领域的系统集成商&#xff0c;为客户提供非标自动化系统的设计研发、量身定做、批量生产等非标自动化解决方案&#xff0c;并代理这世界一流品牌的美国Parker派克。 派克Parker是全球领先的运动和控制技术与系统多元化制造商&#…

Minio 文件上传(后端处理同文件判断,同一文件秒传)

记录minio 文件上传 MinIO提供多个语言版本SDK的支持&#xff0c;下边找到java版本的文档&#xff1a; 地址&#xff1a;https://docs.min.io/docs/java-client-quickstart-guide.html maven依赖如下&#xff1a; XML <dependency><groupId>io.minio</groupId…

openHarmony新建项目及本地模拟机配置

新建项目 新建项目 选择空模板 选择一个非中文路径 在新建项目过程中可能会存在杀毒软件报病毒信息&#xff0c;建议退出退出杀毒软件 直到右侧窗口出现 Previewer预览选项&#xff0c;证明项目搭建完成 相关常用文件及文件夹解析 实时预览 调整预览设备类型 …

CSS3 渐变

CSS3 渐变可以让你在两个或多个指定的颜色之间显示平稳的过渡。 CSS3渐变有两种类型&#xff1a;线性渐变&#xff08;Linear Gradients&#xff09;和径向渐变&#xff08;Radial Gradients&#xff09;。 线性渐变&#xff08;Linear Gradients&#xff09;&#xff1a; 线性…