剑指 Offer 52. 两个链表的第一个公共节点--leetcode刷题之路

问题描述

剑指 Offer 52. 两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共节点。

如下面的两个链表:

在这里插入图片描述

在节点 c1 开始相交。

示例 1:

在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:

在这里插入图片描述

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:
在这里插入图片描述

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。

注意:

如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

思路描述

两种思路:
1:直接使用两个栈存储从后往前比较,比较到不同,之所以使用栈这种结构是因为他后进先出的特性,这种方法也是最好想到的。
2:使用双指针,说实话这种方法我真没想到,看了题解才明白的,双指针的主要思想是:

  1. 将两个链表合并
  2. 创建两个指针
  3. 如果两个指针的值相同就输出该值,两个指针的值不同就继续循环
  4. 如果循环到两个指针同时为null那么没有共同节点

当然在实际做的时候只要将第一个链表循环结束时转移到第二个链表的头上就可以实现上述功能
在这里插入图片描述

代码

思路一代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
	    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
	    	
	    	//定义两个栈
	    	Stack<ListNode> s1=new Stack<>();
	    	Stack<ListNode> s2=new Stack<>();
	    	
            if(headA==null||headB==null){
                return null;
            }
	    	ListNode pA=headA,pB=headB;
	    	//将两个链表输入到栈中
	        while(pA!=null){
	        	s1.add(pA);
	        	pA=pA.next;
               
	        	
	        }
	        while(pB!=null){
	        	s2.add(pB);
	        	pB=pB.next;
	        	
	        }
	        //如果两个栈有一个是空的那么无论如何都不会有相交的输出null
            if(s1.isEmpty()||s2.isEmpty()){ 
                return null;

            }
            
            ListNode aa=s1.pop();//这一步的目的是防止只有一个数相交做一个备份
	        if(!aa.equals(s2.pop())){
	        	return null;
               
	        }
	        else{
	        
	        	ListNode num=aa; 
               
	        	while(!s1.isEmpty()&&!s2.isEmpty()){
	        		ListNode temp=s1.pop();
	        		//如果不相交了就终止循环,此时num的值还是上次循环产生的值
	        		if(!temp.equals(s2.pop())){
	        			break;
	        		}
	        		num=temp;
	        		
	        	}
	        	
	        	return num;
	        }
	        
	    }
	}

这种方法做出来的情况:

在这里插入图片描述
可以看出十分不理想主要原因是创建两个栈分别用了M和N的时间,后面的判定是否是相同的值用了i(相同数)的时间,所以时间复杂度为O(M+N+I)

思路二代码:

 public class Solution {
		    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
		        if(headA==null||headB==null){
		        	return null;
		        }
		        ListNode pA=headA,pB=headB;
		        while(pA!=null||pB!=null){
		        	if(pA==pB){
		        		return pA;
		        	}
		        	else{
		        		pA=(pA==null)?pA=headB:pA.next;
		        		pB=(pB==null)?pB=headA:pB.next;
		        	}
		        }
		        return null;
		    }
		}

在这里插入图片描述
由此可看出,的确是栈上面浪费了时间,双指针的方式的确比用栈的方式做更加简单。

写在最后

欢迎大神指正,我会听取并改正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值