算法通关村第一关-----查找两个链表的公共节点(白银挑战)

问题:

 如图,观察链表A和链表B,到C1节点开始相交,后面相交后成为一个单链表,已知头结点,相交位置未知,设计算法找到两个链表的合并点(即第一个相交点)

注意:

创建这连个链表时,不要像我一样,创建成这样,下图是错误的

 创建两个链表的代码:

 private static Node[] initLinkedList() {
        Node[] heads = new Node[2];
//        构造第一个链表交点之前的元素 1 ->2-> 3
        heads[0] = new Node(1);
        Node current1 = heads[0];
        current1.next = new Node(2);
        current1 = current1.next;
        current1.next = new Node(3);
        current1 = current1.next;
//        11->22
//        构造第二个链表交点之前的元素
        heads[1] = new Node(11);
        Node current2 = heads[1];
        current2.next = new Node(22);
        current2 = current2.next;
//        构造公共交点以及之后的元素

        Node node4 = new Node(4);
        current1.next = node4;
        current2.next = node4;
        Node node5 = new Node(5);
        node4.next = node5;


        Node node6 = new Node(6);
        node5.next = node6;

        return heads;
    }

方式一:双层循环判断

思路分析:

首先能想到的就是双层循环判断,一个节点一个节点比较,类似于冒泡排序,容易想到但是时间复杂度太高

方法二:使用hashSet和hashMap

思路分析:

使用hashSet或者hashMap,把链表A的每个节点都放入hashSet中,或者hashMap(key为节点,值为null)中,循环链表B的每个节点,并判断该节点是否在hashSet中,存在则return 该节点,后边的直接不判断了(因为找到就是第一个相交点)

代码实现:

 public static Node getCommonNode(Node nodeA, Node nodeB) {
        Set<Node> set = new HashSet<>();
        while (nodeA != null){
            set.add(nodeA);
            nodeA = nodeA.next;
        }
        while (nodeB != null){
            boolean isContains = set.contains(nodeB);
            if(isContains)
                return nodeB;

            nodeB = nodeB.next;
        }
        return null;
    }

方法三:

思路分析:

使用栈,把链表A和链表B的每个节点都分别放在stackA和stackB中,会把链表的第一个节点放在栈底,最后一个节点放在栈顶,当两个栈都不是空时,比较两个栈顶元素是否相等,相等就给赋值给commNode节点并都出栈,直到两个栈顶元素都不相同,即break退出循环,并return commNode节点

代码实现:

 public static Node getCommonNodeByStark(Node nodeA, Node nodeB) {
        if (nodeA == null || nodeB == null){
            return null;
        }
        Stack<Node> stackA = new Stack<>();
        Stack<Node> stackB = new Stack<>();
        while (nodeA != null){
            stackA.push(nodeA);
            nodeA = nodeA.next;
        }
        while (nodeB != null){
            stackB.push(nodeB);
            nodeB = nodeB.next;
        }
        Node commNode = null;
        while(!stackA.empty() && !stackB.empty()){
            if(stackA.peek() == stackB.peek()){
                commNode=stackA.pop();
                stackB.pop();
            }else{
                break;
            }
        }
        return commNode;
    }

方法四:链表相加

思路分析:

使用字符串拼接的方式

 优化:新建链表太麻烦,当链表A为null时,把链表B的头结点赋值给A ,就构成了链表AB,链表BA同理

思路分析:

什么时候链表AB会和链表BA相同

1、最后一个相交点

2、当两个链表没有相交点,链表AB和BA都循环结束,都为null时,也会相等,所以循环体中添加if(pNodeA != pNodeB)的判断,是为了防止无相交点时,出现死循环

代码实现:

public static Node getCommonNodeByStrTogether(Node nodeA, Node nodeB) {
        if (nodeA == null || nodeB == null){
            return null;
        }
        Node pNodeA = nodeA;
        Node pNodeB = nodeB;
        while(pNodeA !=pNodeB){
            pNodeA = pNodeA.next;
            pNodeB = pNodeB.next;
            if(pNodeA != pNodeB){ //是为了防止pNodeA和pNodeB都为null,还赋值
                if (pNodeA == null){
                    pNodeA = nodeB;
                }
                if (pNodeB == null){
                    pNodeB = nodeA;
                }

            }
        }
        return pNodeA;
    }

方式五:长的链表减去差值

思路分析:

长的链表减去两个链表之间的差值,这样就会使两个链表的长度相等,相等之后再在循环中判断哪个节点相同

代码实现:

  /**
     * 长的链表减去两个链表的差值,之后两个链表的长度就相等了
     * @param nodeA
     * @param nodeB
     * @return
     */
    public static Node getCommonNodeBySub(Node nodeA, Node nodeB) {
        if (nodeA == null || nodeB == null) {
            return null;
        }
        Node pNodeA = nodeA;
        Node pNodeB = nodeB;
        int lenA = 0;
        int lenB = 0;
        while (pNodeA != null) {
            lenA++;
            pNodeA = pNodeA.next;
        }
        while (pNodeB != null) {
            lenB++;
            pNodeB = pNodeB.next;
        }
        //注意,当遍历链表取长度时,pNodeA和pNodeB会为空,要重新赋值(指向头结点)
        pNodeA = nodeA;
        pNodeB = nodeB;
        int sub = lenA > lenB ? lenA - lenB : lenB - lenA;
        if(lenA > lenB){
            for (int i = 0; i < sub; i++) {
                pNodeA = pNodeA.next;
            }
        }
        if(lenB > lenA){
            for (int i = 0; i < sub; i++) {
                pNodeB = pNodeB.next;
            }
        }
        while (pNodeA != pNodeB){
            pNodeA = pNodeA.next;
            pNodeB = pNodeB.next;
        }
        return pNodeA;

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值