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

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

问题描述

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

例如下面的两个链表

在这里插入图片描述

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

理解题目以及解法

理解两个图

在这里插入图片描述

在这里插入图片描述

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

这里提供三种方法

暴力遍历

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

利用哈希和集合

先把一个链表全部存入到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;
        if (head == null) {
            return insertNode;
        }
        while (temp != null) {
            if (count == size) {
                temp.next = insertNode;
                temp = null;
            } else {
                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 和大厂嘉宾交流答疑,也希望能对大家有帮助,扫 ⬇️ 二维码即可加入。

在这里插入图片描述

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xwhking

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值