双指针:剑指 Offer 52. 两个链表的第一个公共节点

个人总结,可以考虑用双指针的地方

1.链式结构

2.可以通过一个指针遍历整个表,存入扩展存储空间中,然后再依次取出或者取出某特定的一个

比如返回链表的倒数第k个节点,可以让一个指针先走k步,然后两个指针一起走,前面的指针到尽头之后,后面的指针停在倒数第k个上

3.存在两个节点之间比较的情况

4.涉及有序链表,迭代

比如把两个有序排列的链表合并成一个有序的,或者把一个有序链表或者顺序表按某种规则拆成两部分

分类很多,比如两个链表平行指针,在一个链表同步移动但一前一后的指针,一个负责遍历一个负责指示当前操作位置的双指针,两个指针分别位于两端向中间移动直到相遇的碰撞指针,还有两个指针同时移动但每次移动步数不同的快慢指针

有些题目可以用多种方式,比如快速排序可以左右两个指针向中间移动直到碰撞,可以一个指针去遍历整个表寻找小于基准的数,另一个指针指向下一个小于基准的数应该存放的位置

同时移动但移动步数不同的快慢指针,我目前只了解到找链表环路这一个用法

输入两个链表,找出它们的第一个公共节点。

找公共节点这个题,挺难想到的,一般方法都是要额外存储,或者时间复杂度很高

1、最暴力的查找就不提了

2、遍历链表a并用HashSet存储,遍历链表b并依次尝试存入,如果.add()返回值为false,说明这个值已经在表中,直接将其返回,程序结束

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

        Set<ListNode> set = new HashSet<>();
        while(headA != null){
        set.add(headA);
        headA = headA.next;
        }

        while(headB != null){
            if( set.add(headB)== false) return headB;
            headB = headB.next;
        }
        return null;

    }
}

3.反向思考,不是找第一个相同的节点,而是找第一个不相同的节点

两个链表合一之后,后面就只有一个链了,遍历链表A和B,分别把每个节点都存入Stack中,然后倒着pop()出来并且比较,直到某一次pop(),A和B的节点不相同,在这的前一个,就是所要的节点

4、双指针,不知道什么样的脑袋才想得出来这种解法,我人都看傻了

为了写起来省事,用小写a和b表示A和B的长度,c表示A和B合并后剩下的长度

所以用一个指针遍历链表a,总长a+c,用一个指针遍历链表b,总长b+c

那么,如果让一个指针遍历A结束后转去指向B的head节点,遍历链表到结束

同时,另一个指针从B开始遍历,到尽头后转到A,再次遍历链表到结束

在这个过程中,指针会路过两次我们要找的【第一个相同节点】,找这两个时分别走了多少路呢?

A链表:第一次:a,第二次:a+c+b

B链表:第一次:b,第二次:b+c+a

也就是说,两个指针同步向后移动的话

如果A和B有交点,会在走了a+b+c的路程之后同时位于那个交点的位置

如果A和B没有交点,两个指针都会走a+b+2c的总路程,然后同时指向null

那么代码的逻辑是这样的:

1.如果A和B任一为空,直接返回null

2.A和B均不为空,进入循环,建立两个指针a和b

2.1 循环跳出条件是两个指针相等,a=b,这个节点就是要找的

2.2 a和b同时向后移动一位,即指向它的next节点

2.3 如果a和b同时为空,说明这两个链表没有交点,返回null

2.4 如果a和b有一个为空,那么将其指向另一个链表的head

我这个是循环外面不用写return的,符合条件都是循环内直接return,有些地方可能会报错。。。或者进入无限循环超时,还死活找不到哪里出错。。。

如果你笔试的系统不是很靠谱,还是老老实实最后再return比较好

/**
 * 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) {
        if(headA == null || headB == null) return null;

      ListNode a = headA;
      ListNode b = headB;


      while(true){

        if(a == b) return a;

          a = a.next;
          b = b.next;
          if(a == null && b == null )return null;
        

          if(a == null){
              a = headB;
          }
          if(b == null){
              b = headA;
          }

   
      }
      //return null;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值