题目:输入两个链表,找出它们的第一个公共节点。例如下面的两个链表:
思路1 蛮力法查找
类似冒泡排序,从第一个链表的第一个结点开始与第二个链表比较,若出现相同的结点指针则为公共点
优点:简单直接
缺点:时间复杂度高
这里我用数组来代替链表
public class BruteForceMethod {
public static void main(String[] args) {
int[] arr1 ={1,3,8,5,1,2};
int[] arr2 ={2,3,1,7,5,1,2};
int a= search(arr1,arr2);
System.out.println("公共结点为:"+a);
}
private static int search(int[] arr1, int[] arr2) {
for (int i = 0; i < arr1.length; i++) {
for (int j = arr2.length-arr1.length; j < arr2.length; j++) {
while (i == j-1 && arr1[i] == arr2[j]) {
return arr1[i];
}
}
}return 0;
}
}
思路2 通过Hash和Set查找
Hash
将第一个链表中的元素存到map中,一边遍历第二个链表,一边检测当前元素是否在Hash中,若存在则为公共点
public static ListNode findFirstCommonNodeByHash(ListNode headA,ListNode headB){
//判断链表表头是否为空
if (headA==null||headB==null){
return null;
}
//局部变量
ListNode current1 =headA;
ListNode current2 =headB;
HashMap<ListNode,Integer> hashMap = new HashMap<>();
while (current1!=null){
hashMap.put(current1,null);
current1=current1.next;
}
while (current2!=null){
if (hashMap.containsKey(current2)){
return current2;
}
current2=current2.next;
}
return null;
}
Set
将第一个链表中的元素存到Set中,一边遍历第二个链表,一边检测当前元素是否在Set中,若存在则为公共点
public static ListNode findFirstCommonNodeBySet(ListNode headA,ListNode headB){
Set<ListNode> set =new HashSet<>();
while (headA!=null){
set.add(headA);
headA=headA.next;
}
while (headB!=null){
if (set.contains(headB)){
return headB;
}
headB=headB.next;
}
return null;
}
思路3 使用栈查找
将两个链表结点压入两个栈,同时出栈,第一个元素相同则有公共点。继续出栈到没有相同元素为止,最晚出栈的元素即为公共点
public static ListNode findFirstCommonNodeByStack(ListNode la, ListNode lb) {
Stack<ListNode> stackA = new Stack<>();
Stack<ListNode> stackB = new Stack<>();
while (la !=null){
stackA.push(la);
la =la.next;
}
while (lb !=null){
stackB.push(lb);
lb =lb.next;
}
ListNode preNode =null;
while (stackB.size()>0 && stackA.size()>0){
if (stackA.peek()==stackB.peek()){
preNode=stackA.pop();
stackB.pop();
}else {
break;
}
}
return preNode;
}
思路4 通过序列拼接查找
通过分析我们能发现具有相同的公共子节点的后续结点都相同,所以我们可以以节点为中心将链表分为前后两个部分。即A链表的AL,AR和B链表的BL,BR,其中AR和BR是相同的。这时我们将AB链表拼接,同时遍历AB,BA,第一个相同的位置即为公共点
private static ListNode findFirstCommonNodeByCombine(ListNode la, ListNode lb) {
if (la == null || lb == null) {
return null;
}
ListNode p1 =la;
ListNode p2 =lb;
while (p1!=p2){
p1=p1.next;
p2=p2.next;
//若链表无公共点则进入死循环,需跳出循环
if (p1 !=p2){
if (p1==null){
p1=lb;
}
if (p2==null){
p2=la;
}
}
}return p1;
}
思路5 通过差值查找
设链表LA和LB,第一遍遍历得到表LA和LB的长度,记录长度差为|LA-LB|,第二次遍历让长度链表先走|LA-LB|,再同时遍历,相同的节点即为公共节点。
private static ListNode findFirstCommonNode(ListNode la, ListNode lb) {
if (la == null || lb == null) {
return null;
}
ListNode current1 = la;
ListNode current2 = lb;
int l1 =0, l2 =0;
//第一次遍历
while (current1!=null){
current1=current1.next;
l1++;
}
while (current2!=null){
current2=current2.next;
l2++;
}
current1=la;
current2=lb;
int sub=l1>l2 ? l1-l2 :l2-l1;
if (l1>l2){
int a =0;
while (a<sub){
current1=current1.next;
a++;
}
}
if (l1<l2){
int a =0;
while (a<sub){
current2=current2.next;
a++;
}
}
while (current1!=current2){
current1=current1.next;
current2=current2.next;
}
return current1;
}