目录
1.题目
剑指offer 52:输入两个链表,找出它们的第一个公共节点。例如下面的两个链表:
两个链表的头结点都是已知的,相交之后成为一个单链表,但是相交的位置未知,并且相交之前的结点数也是未知的,请设计算法找到两个链表的合并点。
2.解题思路
如果无从下手可以先将常用数据结构和常用算法思想都想一遍,看看哪些能解决问题。
常用的数据结构:
数组、链表、队、栈、Hash、集合、树、堆。
常用的算法思想;
查找、排序、双指针、递归、迭代、分治、贪心、回溯和动态规划等等。
3.解题方式
3.1方式一:
3.1.1分析:
蛮力法,类似于冒泡排序的方式,将第一个链表中的每一个结点依次与第二个链表的进行比较,当出现相等的结点指针时,即为相交结点。虽然简单,但是时间复杂度高,不推荐!
3.1.2具体代码:
//list1 为 1 2 3 4 5
//list2 为 11 22 4 5
ListNode list1 = heads[0];
ListNode list2 = heads[1];
public static ListNode method1(ListNode list1, ListNode list2){
//非空判断
if (list1 == null || list2 == null){
return null;
}
//存放list2 的头节点,以便内循环使用
ListNode head = list2;
while (list1 != null){
while (list2 != null){
//第一个链表中的每一个结点依次与第二个链表的进行比较
if (list1 == list2){
return list1;
}
list2 = list2.next;
}
list2 = head;
list1 = list1.next;
}
return null;
}
3.2方式二:
3.2.1分析:
可以使用Hash,先将第一个链表元素全部存到Map里,然后一边遍历第二个链表,一边检测当前元素是否在Hash中,如果两个链表有交点,那就找到了。
3.2.2具体代码:
//list1 为 1 2 3 4 5
//list2 为 11 22 4 5
ListNode list1 = heads[0];
ListNode list2 = heads[1];
public static ListNode method2(ListNode list1, ListNode list2){
//非空判断
if (list1 == null || list2 == null){
return null;
}
//先将第一个链表元素全部存到Map里
HashMap<ListNode, Integer> map = new HashMap<>();
while (list1 != null){
map.put(list1, null);
list1 = list1.next;
}
//一边遍历第二个链表,一边检测当前元素是否在Hash中
while (list2 != null){
if (map.containsKey(list2))
return list2;
list2 = list2.next;
}
return null;
}
3.3方式三:
3.3.1分析:
既然Hash可以,那集合呢?和Hash一样用,也能解决。
先将第一个链表元素全部存到Set中,然后一边遍历第二个链表,一边检测当前元素是否在Set中,如果两个链表有交点,那就找到了。
3.3.2具体代码:
//list1 为 1 2 3 4 5
//list2 为 11 22 4 5
ListNode list1 = heads[0];
ListNode list2 = heads[1];
public static ListNode method3(ListNode list1, ListNode list2){
//非空判断
if (list1 == null || list2 == null){
return null;
}
//先将第一个链表元素全部存到Set里
HashSet<ListNode> set = new HashSet<>();
while (list1 != null){
set.add(list1);
list1 = list1.next;
}
//一边遍历第二个链表,一边检测当前元素是否在Set中
while (list2 != null){
if (set.contains(list2))
return list2;
list2 = list2.next;
}
return null;
}
3.4方式四:
3.4.1分析:
将两个链表分别压到两个栈里,之后一边同时出栈,一边比较出栈元素是否一致,如果一致则说明存在相交,然后继续找,最晚出栈的那组一致的节点就是要找的位置。
3.4.2具体代码:
//list1 为 1 2 3 4 5
//list2 为 11 22 4 5
ListNode list1 = heads[0];
ListNode list2 = heads[1];
public static ListNode method4(ListNode list1, ListNode list2){
//非空判断
if (list1 == null || list2 == null){
return null;
}
//先将两个链表全部压栈
Stack<ListNode> l1Stack = new Stack<>();
Stack<ListNode> l2Stack = new Stack<>();
while (list1 != null){
l1Stack.push(list1);
list1 = list1.next;
}
while (list2 != null){
l2Stack.push(list2);
list2 = list2.next;
}
//一边同时出栈,一边比较出栈元素是否一致,如果一致则说明存在相交,然后继续找
//记录最后一个出栈节点
ListNode result = null;
while (l1Stack != null && l2Stack != null){
if (l1Stack.peek() == l2Stack.peek()){
//出栈节点
result = l1Stack.pop();
l2Stack.pop();
continue;
}
return result;
}
return null;
}