由力扣141、力扣142引发的力扣287寻找重复数的问题

1. 力扣141判断是否存在环

双指针,相当于跑步,一个跑的快A一个跑的慢B,当有环(环周长Q)的时候,肯定快的能再遇到慢的人,此时A比B多跑1-N圈的时候都能互相遇到,所以下面的算法很简单

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head ==null || head.next ==null){
            return false ;
        }  
    ListNode slow = head;
    ListNode fast = head.next;
    while (slow != fast) {
        if (fast == null || fast.next == null) {
            return false;
        }
        slow = slow.next;
        fast = fast.next.next;
    }
    return true;
 
        
        
    }
}

2. 判断环的入口

这个很难,先看图,就会发现规律:
在这里插入图片描述

起点为O,入环口为N,相遇点为:M
O到N的距离为a,N到M的距离为b,环的长度为Q
A、B两个人到达相遇点走过的距离分别是:
A:   a+b
//B和A相遇的时候,B可能已经走了N圈,因为可能A很长,但是环很小
B:  a+NQ+b
因为B的速度是A的两倍,相同的时间走的距离当然也是A的两倍,所以:
2(a+b)=a+NQ+b
所以:
a+b=NQ
所以
a=NQ-b

2.1 高能预警

a=NQ-b你有没有发现什么?

  1. 或者举例:当N=1的时候,a=Q-b 正是我们要找的环的入口,也就是如果现在能让A从起点O触发速度不变,B速度降低为原来的一半也就是A的速度,这个时候,大家以相同的速度走相同的时间,都能到达环的入口N点,我们就求出来了环的入口
  2. 或者上面还是不是很理解,我们假定N=6,也就是a的距离是6圈减去b的长度,这个时候还让A回到起点相同速度去找B,B以原来速度的一半在这个环上转圈,当它转到第6圈也就是走的长度为6Q-b的时候,他会发现A,为什么?
  3. 因为6Q-b=a,所以只要把A弄回起点,同时AB的速度保持一致,A去找B ,B在环上绕圈,当A到达环的入口的时候,AB必然会相遇

3. 解题

我们先判断是否有环,如果有环,那我们定义一个q=head相当于把q放回了起点,同时,我们判断有环的时候,相交点是p或者p2我们让q和p都同时继续走下去,相交的时候就是入口的位置

public class Solution {
    public ListNode detectCycle(ListNode head) {
 
        if (head == null || head.next == null) {
            return null;
        }
        ListNode p = head, p2 = head;
        boolean hasCycle = false;
        while (p2.next != null && p2.next.next != null) {
            p = p.next;
            p2 = p2.next.next;
            if (p == p2) {
                hasCycle = true;
                break;
            }
        }


        if (hasCycle) {
            ListNode q = head;
            while (p != q) {
                p = p.next;
                q = q.next;
            }
            return q;
        } else {
            return null;
        }
 
    }
}

4. 寻找重复数

4.1 题目

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),
可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

示例 1:

输入: [1,3,4,2,2]
输出: 2
示例 2:

输入: [3,1,3,4,2]
输出: 3
说明:

不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。
 

4.2 把数组转化成链表

注意两点,数组大小N+1,每个数都在1-N之间
说明了什么,必有一个数是重复的
所以下面这种初始化数组的方式肯定不对

 int arr []=new int[]{1,2,345,54,452,343,23};

比如我们new一个满足条件的数组并进行初始化

 int arr []=new int[]{2,7,5,3,0,1,2,4,3,8};

得到了下面的数据

类型
下标:0123456789
值:2753012438

所以我们用下标组成链表的话,肯定是有环的,不信我来试一下

刚开始用下标0来: 251740 251740
我们就发现了环的入口是2

我们的解决算法:

  public int findDuplicate(int[] nums) {
         int i = 0;
         //temp可以初始化为任何值
        int temp = -100;
        while (true) {
            if (nums[i] == -1) {
            //这次访问的元素之前那访问过,返回这次的 下标,
            //如果nums[i]==-1说明这个元素之前访问过,直接返回即可
                return temp;
            }
            temp = nums[i];
            //这里的值要和if条件里面的值保持一致
            nums[i] = -1;
            i = temp;
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值