两个链表的第一个公共结点

本文介绍了四种寻找两个链表第一个公共节点的方法,包括朴素枚举、栈、集合以及差值和等值法,详细阐述了每种方法的思路并提供了相应的代码实现。
摘要由CSDN通过智能技术生成

朴素解法

一个朴素的解法自然是两层枚举,逐个检查哪个节点相同。

代码:

1

2

3

4

5

6

7

8

9

10

public class Solution {

    public ListNode FindFirstCommonNode(ListNode a, ListNode b) {

        for (ListNode h1 = a; h1 != null ; h1 = h1.next) {

            for (ListNode h2 = b; h2 != null ; h2 = h2.next) {

                if (h1 == h2) return h1;

            }

        }

        return null;

    }

}


栈解法

这是一种「从后往前」找的方式。

将两条链表分别压入两个栈中,然后循环比较两个栈的栈顶元素,同时记录上一位栈顶元素。

当遇到第一个不同的节点时,结束循环,上一位栈顶元素即是答案。

代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import java.util.*;

public class Solution {

    public ListNode FindFirstCommonNode(ListNode a, ListNode b) {

        Deque<ListNode> d1 = new ArrayDeque<>(), d2 = new ArrayDeque<>();

        while (a != null) {

            d1.add(a);

            a = a.next;

        }

        while (b != null) {

            d2.add(b);

            b = b.next;

        }

        ListNode ans = null;

        while (!d1.isEmpty() && !d2.isEmpty() && d1.peekLast() == d2.peekLast()) {

            ans = d1.pollLast();

            d2.pollLast();

        }

        return ans;

    }

}


Set 解法

这是一种「从前往后」找的方式。

使用 Set 数据结构,先对某一条链表进行遍历,同时记录下来所有的节点。

然后在对第二链条进行遍历时,检查当前节点是否在 Set 中出现过,第一个在 Set 出现过的节点即是交点。

代码:

1

2

3

4

5

6

7

8

9

10

11

12

import java.util.*;

public class Solution {

    public ListNode FindFirstCommonNode(ListNode a, ListNode b) {

        Set<ListNode> set = new HashSet<>();

        while (a != null) {

            set.add(a);

            a = a.next;

        }

        while (b != null && !set.contains(b)) b = b.next;

        return b;

    }

}


差值法

由于两条链表在相交节点后面的部分完全相同,因此我们可以先对两条链表进行遍历,分别得到两条链表的长度,并计算差值 d

让长度较长的链表先走 d 步,然后两条链表同时走,第一个相同的节点即是节点。

代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

import java.util.*;

public class Solution {

    public ListNode FindFirstCommonNode(ListNode a, ListNode b) {

        int c1 = 0, c2 = 0;

        ListNode ta = a, tb = b;

        while (ta != null && c1++ >= 0) ta = ta.next;

        while (tb != null && c2++ >= 0) tb = tb.next;

        int d = c1 - c2;

        if (d > 0) {

            while (d-- > 0) a = a.next;

        } else if (d < 0) {

            d = -d;

            while (d-- > 0) b = b.next;

        }

        while (a != b) {

            a = a.next;

            b = b.next;

        }

        return a;

    }

}


等值法

这是「差值法」的另外一种实现形式,原理同样利用「两条链表在相交节点后面的部分完全相同」。

我们令第一条链表相交节点之前的长度为 a,第二条链表相交节点之前的长度为 b,相交节点后的公共长度为 c(注意 c 可能为 ,即不存在相交节点)。

分别对两条链表进行遍历:

  • 当第一条链表遍历完,移动到第二条链表的头部进行遍历;
  • 当第二条链表遍历完,移动到第一条链表的头部进行遍历。

如果存在交点:**第一条链表首次到达「第一个相交节点」的充要条件是第一条链表走了 步,由于两条链表同时出发,并且步长相等,因此当第一条链表走了 步时,第二条链表同样也是走了 步,即 第二条同样停在「第一个相交节点」的位置。**

如果不存在交点:**两者会在走完 之后同时变为 ,退出循环。**

代码:

1

2

3

4

5

6

7

8

9

10

11

import java.util.*;

public class Solution {

    public ListNode FindFirstCommonNode(ListNode a, ListNode b) {

        ListNode ta = a, tb = b;

        while (ta != tb) {

            ta = ta == null ? b : ta.next;

            tb = tb == null ? a : tb.next;

        }

        return ta;

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值