一.题目
力扣160:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
二.代码
public class LeetCode160 {
static class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null; // 修改这里,之前的构造函数尝试错误地设置next
}
}
static class Solution160 {
public ListNode getInterSectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode a = headA;
ListNode b = headB;
while (a != b) {
a = (a == null) ? headB : a.next;
b = (b == null) ? headA : b.next;
}
return a;
}
}
public static void main(String[] args) {
// 创建两个相交的链表示例
// 链表A: 1 -> 2 -> 3
// \
// 5 -> 6 -> 7
// /
// 链表B: 4 -> 5
ListNode common = new ListNode(5);
common.next = new ListNode(6);
common.next.next = new ListNode(7);
ListNode headA = new ListNode(1);
headA.next = new ListNode(2);
headA.next.next = new ListNode(3);
headA.next.next.next = common;
ListNode headB = new ListNode(4);
headB.next = common;
Solution160 solution160 = new Solution160();
// 方法调用时去除了类型声明
ListNode intersectionNode = solution160.getInterSectionNode(headA, headB);
if (intersectionNode != null) {
System.out.println("The intersection node's value is " + intersectionNode.val);
} else {
System.out.println("No intersection node.");
}
}
}
三.总结
三元运算符是一种条件运算符,它包含三个部分,格式为:
条件 ? 表达式1 : 表达式2
其工作原理如下:
条件:这是一个布尔表达式,其结果必须为 true 或 false。
表达式1:如果条件为 true,则计算并返回此表达式的结果。
表达式2:如果条件为 false,则计算并返回此表达式的结果。
三元运算符通常用于简化简单的条件语句,使代码更紧凑。它是 if-else 语句的一种简写形式。例如,考虑以下的 if-else 语句:
java
if (a > b) {
max = a;
} else {
max = b;
}
使用三元运算符,上面的代码可以被简化为:
java
max = (a > b) ? a : b;
这两段代码都是用来决定 max 应该被赋值为 a 还是 b,具体取决于 a 是否大于 b。三元运算符因其简洁性而受到欢迎,尤其是在赋值操作和简单逻辑决策中。然而,为了保持代码的可读性,建议在复杂的逻辑判断中使用传统的 if-else 语句,而不是嵌套多个三元运算符。
思路:
为了找到两个单链表相交的起始节点,我们可以使用两个指针分别遍历这两个链表。当一个指针到达链表末尾时,将它移到另一个链表的头部继续遍历;另一个指针也是如此。如果链表相交,那么这两个指针最终会在相交节点处相遇;如果链表不相交,这两个指针最终会同时为 null。
这个方法之所以有效,是因为两个指针会分别遍历两个链表的节点,其遍历的总长度相同,即两个链表的长度之和。这样,如果链表相交,它们就会在相交点相遇;如果不相交,它们会在列表末尾相遇(即都指向 null)。
设想两个链表,A 和 B。它们的长度分别是 a 和 b。假设从链表A的头到相交点的距离是 c,从链表B的头到相交点的距离是 d,相交点到链表末尾的长度为 e。因此,相交的情况下,链表A的长度为 a = c + e,链表B的长度为 b = d + e。
不相交的情形:
如果两个链表不相交,那么遍历完自己的链表后,两个指针分别遍历对方的链表,最终都会到达各自链表的末尾,即 null。这个过程中,每个指针遍历的总长度是 a + b,因此它们会同时到达末尾。
相交的情形:
假设链表相交。指针A开始时位于链表A的头部,指针B位于链表B的头部。
当指针A遍历完链表A(长度为 a)后,它跳到链表B的头部继续遍历;同样,指针B遍历完链表B(长度为 b)后,它跳到链表A的头部继续遍历。
当指针A进入链表B时,它已经遍历了长度 a,接下来它还需要遍历长度 d 才能到达相交点。
当指针B进入链表A时,它已经遍历了长度 b,接下来它还需要遍历长度 c 才能到达相交点。
因此,当指针A和指针B分别遍历了 a + d 和 b + c 后,它们会在相交点相遇。注意到 a + d = b + c(因为 a + d + e = b + c + e,即两个链表的总长度相等),这说明它们会同时到达相交点。
通过这种方式,无论两个链表是否相交,这个算法都能正确地找到相交的起始节点(如果存在的话),或者同时到达链表的末尾(null),表示两个链表不相交。这个方法的巧妙之处在于它利用了遍历长度相同的特性,确保了两个指针能够在相交点相遇,而不需要额外的空间复杂度。