算法通关村第一关白银关--再次讨论公共子节点的问题

1.拼接两个字符串

先看下面的链表A和B:

A: 0-1-2-3-4-5

 B: a-b-4-5  

如果分别拼接成AB和BA会怎么样呢?

AB:0-1-2-3-4-5-a-b-4-5

BA:a-b-4-5-0-1-2-3-4-5

我们可以看出,A和B的公共节点也是AB和BA的公共节点

我们假定A和B有相交的位置,以交点为中心,可以将两个链表分别分为left_a和right_a,left_b和right_b这样四个部分,并且right_a和right_b是一样的,这时候我们拼接AB和BA就是这样的结构:代码如下:

    /**
     *拼接两个链表求公共节点
     * @param pHead1 需要求第一个公共子节点的链表头结点
     * @param pHead2 需要求第一个公共子节点的链表头结点
     * @return
     */
    //拼接两个字符串
    public listNode findFirstCommonNode1(listNode pHead1, listNode pHead2){
    if(pHead1==null||pHead2==null){
        return null;
    }
    listNode node1=pHead1;
    listNode node2=pHead2;
    while(node1!=node2){
        node1=node1.next;
        node2=node2.next;
        //注意node1!=node2的判断必须加,因为当没有公共节点时,会出现node1和node2同时是null的情况
        //而下面的对于node1和node2为空的判断导致在对while的条件判断时,node1和node2不可能为空,所以
        //需要另外加if(node1!=node2)的判断,以便于while循环判断时出现node1=node2=null的情况跳出循环
        if(node1!=node2){
            //一个链表访问完跳到另一个链表
            if(node1==null){
                node1=pHead2;
            }
            if(node2==null){
                node2=pHead1;
            }
        }
    }
    return node1;
    }

其中对于循环中if(node1!=node2)的判断的解释代码中注释已经提及

2.差和双指针

我们再看另一个使用差和双指针来解决问题的方法。假如公共子节点一定存在第一轮遍历,假设La长度为L1,Lb长度为L2.则|L2-L1|就是两个的差值。第二轮遍历,长的先走|L2-L1|,然后两个链表同时向前走,结点一样的时候就是公共结点了。

例如下图中,一条链表的长度为6,另一条的长度为5,差值为1,我们想要做的实际上是,让两个链表分别在a2和b1时同时走,此时它们距离第一个公共节点的距离相等,当第一次出现节点一样的情况时,该节点就是第一个公共节点

代码如下

    /**
     * 差和双指针法求两个链表的第一关公共节点
     * @param pHead1 一个链表的头指针
     * @param pHead2 另一个链表的头指针
     * @return
     */
    //差和双指针
    public listNode findFirstCommonNode2(listNode pHead1, listNode pHead2) {
    if(pHead1==null||pHead2==null){
        return null;
    }
    listNode node1=pHead1;
    listNode node2=pHead2;
    int length1=0,length2=0;
    //分别遍历两个链表求出长度
    while(node1!=null){
        node1=node1.next;
        length1++;
    }
    while(node2!=null){
        node2=node2.next;
        length2++;
    }
    node1=pHead1;
    node2=pHead2;
    if(length1>length2){
        for(int i=0;i<length1-length2;i++){
            node1=node1.next;
        }
    }else{
        for(int i=0;i<length2-length1;i++){
            node2=node2.next;
        }
    }
        while(node1!=null){
            if(node1==node2){
                return node1;
            }
            node1=node1.next;
            node2=node2.next;
        }
    return node1;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值