问题描述:
一个比较经典的问题,判断两个链表是否相交,如果相交找出他们的交点。
思路:
1、碰到这个问题,第一印象是采用hash来判断,将两个链表的节点进行hash,然后判断出节点,这种想法当然是可以的。
2、当然采用暴力的方法也是可以的,遍历两个链表,在遍历的过程中进行比较,看节点是否相同。
3、第三种思路是比较奇特的,在编程之美上看到的。先遍历第一个链表到他的尾部,然后将尾部的next指针指向第二个链表(尾部指针的next本来指向的是null)。这样两个链表就合成了一个链表,判断原来的两个链表是否相交也就转变成了判断新的链表是否有环的问题了:即判断单链表是否有环?
这样进行转换后就可以从链表头部进行判断了,其实并不用。通过简单的了解我们就很容易知道,如果新链表是有环的,那么原来第二个链表的头部一定在环上。因此我们就可以从第二个链表的头部进行遍历的,从而减少了时间复杂度(减少的时间复杂度是第一个链表的长度)。
下图是一个简单的演示:
这种方法可以判断两个链表是否相交,但不太容易找出他们的交点。
4、仔细研究两个链表,如果他们相交的话,那么他们最后的一个节点一定是相同的,否则是不相交的。因此判断两个链表是否相交就很简单了,分别遍历到两个链表的尾部,然后判断他们是否相同,如果相同,则相交;否则不相交。示意图如下:
判断出两个链表相交后就是判断他们的交点了。假设第一个链表长度为len1,第二个问len2,然后找出长度较长的,让长度较长的链表指针向后移动|len1 - len2| (len1-len2的绝对值),然后在开始遍历两个链表,判断节点是否相同即可。
然后这里是我们主要的查找算法。
//查找两个单向链表的相交节点
public static Node findTheCrossNode(Node lhs, Node rhs){
int len_lhs = 0;
int len_rhs = 0;
Node tlhs = lhs;
Node trhs = rhs;
//计算链表一长度
while (tlhs.next != null){
len_lhs++;
tlhs = tlhs.next;
}
//计算链表二长度
while (trhs.next != null){
len_rhs++;
trhs = trhs.next;
}
//计算两个链表的长度差
int difference = Math.abs(len_lhs - len_rhs);
//先让长的一个链表走步长为difference的距离
//然后开始两个链表同步向前,如果有相交节点则会找到相同节点
//否则两个链表都到最后null
if(len_lhs > len_rhs){
for (int i = 0; i < difference; i++)
lhs = lhs.next;
}
else {
for (int i = 0; i < difference; i++)
rhs = rhs.next;
}
while(lhs != rhs){
System.out.println("node1 = " + lhs.data + " node2 = " + rhs.data);
lhs = lhs.next;
rhs = rhs.next;
}
return lhs;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
3.然后通过Main函数进行了测试,验证成功哈哈哈哈哈哈哈。在例子特地设置了相交节点值为2。
public static void main(String[] args) {
//两个单项链表为带空头结点的链表
Node<Integer> list1 = new Node<>(-1, null);
Node<Integer> list2 = new Node<>(-1, null);
Node cross = null;
Node lastNode = list1;
//构建链表一, 0->1->2->3->4
for (int i = 0; i < 5; i++){
lastNode.next = new Node<>(i, null);
if (i == 2) //相交节点为4
cross = lastNode.next;
lastNode = lastNode.next;
}
//构建链表二, 10->9->8->2->3->4
lastNode = list2;
for (int i = 10; i > 7; i--){
lastNode.next = new Node<>(i, null);
lastNode = lastNode.next;
}
lastNode.next = cross;
cross = findTheCrossNode(list1, list2);
if (cross != null)
System.out.println("相交节点值为: " + cross.data);
else
System.out.println("没有相交节点");
}