数组查询重复数——LeetCode

LeetCode刷题记录及思路

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-duplicate-number

--------------------------------学无止境,道亦有道-----------------------------

时间:2020年5月26日 星期二

题目

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

  • 要求
  1. 不能更改原数组(假设数组是只读的)。
  2. 只能使用额外的 O(1) 的空间。(仅可开辟一次内存,不能使用递归方式)
  3. 时间复杂度小于 O(n2) 。(两次循环)
  4. 数组中只有一个重复的数字,但它可能不止重复出现一次。

PS:即查找数组中的重复数。

测试案例

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

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

思路

方法一:逐个选取

用两个指针分别比较指向的数字,相同输出,不同移动指针。
逐个选取
如上图中所示,比较红色与绿色指针所指向的Value是否相等,相等返回红色或绿色指针的Value。若不相等,则先移动绿色指针,其步长为1。当绿色指针移动到数组末端时,红色指针步进1。绿色指针则移动到红色指针index+1的位置。
红色步进
以此类推,直到红色指针移动到 nums.length-1 或者红绿两指针所指向的Value相等时停止。
停止步进

方法二:判环方式

将不同数据想成一个节点,按照 nums[i] 的数组原有顺序进行连线,以示例一([1,3,4,2,2])为例:

1
2
3
4

示例一 中,起点与终点都是 “2 ” 所以返回重复值——2;
同样,在示例二([3,1,3,4,2])中也可以将数组转化为图来观察:

1
2
3
4

由图可以看出,环出现在了 1-3 间,起点和终点为3,所以返回重复值——3。

解题:

方法一解题:

PS:因为方法很简单就不对代码解释了

public int findDuplicate1(int[] nums) {
        //遍历数组
        for (int red = 0; red < nums.length; red++) {
            for (int green = red + 1; green < nums.length; green++) {
                if (nums[green] == nums[red]) {
                    return nums[red];
                }
            }
        }
        System.out.println("找不到重复数,返回0");
        return 0;
    }

优缺点:简单易懂,实现起来方便,但消耗系统资源较大。

方法二解题:

定义快指针——rabbit(兔子),慢指针——turtle(乌龟),两者均从 index = 0 开始跑。
起始样式
乌龟跑自己的值,兔子跑自己值的索引,即为乌龟跑了两次。开始时 turtle 的值为0;

索引为0时值为1 所以跑到索引为1的位置
0
1
rabbit索引
0
turtle索引

第一次循环结果:
第一次循环后结果
比较值后不相等继续跑:

索引为0时值为3 所以跑到索引为3的位置
第二阶段值为2 所以跑到索引为2的位置
1
2
3
rabbit索引
1
turtle索引

第二次循环结果:
第二次跑后结果
以此类推,在第五次循环后相遇,则把乌龟放到0处兔子继续跑,但同步跑,每次步长都为1。
相遇后
乌龟和兔子均跑自己的值:
相遇后第一次跑
经过两次后找到相同数:
找到相同数

public int findDuplicate1(int[] nums) {
        int rabbit;
        int turtle;

        //从0开始跑
        rabbit = turtle = 0;
        do {
            //兔子跑自己的值索引的值的索引(两次值),乌龟跑自己的值
            turtle = nums[turtle];
            rabbit = nums[nums[rabbit]];
        } while (rabbit != turtle);

        //相遇后,兔子从相遇点出发,乌龟从起点出发
        turtle = 0;
        while (rabbit != turtle) {
            rabbit = nums[rabbit];
            turtle = nums[turtle];
        }

        return rabbit;
    }

知识点

1、空间复杂度(Space Complexity)

空间复杂度是对一个算法在运行过程中临时占用(虚拟机中)存储空间大小的量度,记做S(n)=O(f(n))。

如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为O(log2n);当一个算法的空间复杂度与n成线性比例关系时,可表示为O(n).

2、时间复杂度;

时间复杂度又称为时间复杂度,一个算法的时间复杂度不单单是程序运行时间的值,而是一个函数,它定性描述该算法的运行时间。
以下内容整理自: Mars93的文章——o(1), o(n), o(logn), o(nlogn)

O(n),就代表数据量增大几倍,耗时也增大几倍。比如常见的 遍历算法

O(n2),就代表数据量增大n倍时,耗时增大n的平方倍,这是比线性更高的时间复杂度。比如冒泡排序,就是典型的O(n2)的算法,对n个数排序,需要扫描n×n次。

O(logN),就代表当数据增大n倍时,耗时增大logn倍(以2为底的对数函数,比如,当数据增大256倍时,耗时只增大8倍)。比如 二分查找(每找一次排除一半的可能,256个数据中查找只要找8次就可以找到目标)

O(nlogn),就是n乘以logn,当数据增大256倍时,耗时增大256*8=2048倍。这个复杂度高于线性低于平方。归并排序就是O(nlogn)的时间复杂度。

O(1),就是最低的时空复杂度, 耗时或空间输入数据大小 无关,无论输入数据增大多少倍,耗时/耗空间都不变。比如 哈希算法,无论数据规模多大,都可以在一次计算后找到目标。

程序运行状态(力扣提供)

  • 方法一:
    程序运行消耗系统资源:
    共耗时 348ms ,消耗内存 39.8MB
    程序消耗资源情况
  • 方法二:
    程序运行消耗系统资源:
    共耗时0ms(估计是官方出错了),消耗内存 39.9MB
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值