LeetCode刷题记录及思路
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-duplicate-number
--------------------------------学无止境,道亦有道-----------------------------
时间:2020年5月26日 星期二
题目
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
- 要求
- 不能更改原数组(假设数组是只读的)。
- 只能使用额外的 O(1) 的空间。(仅可开辟一次内存,不能使用递归方式)
- 时间复杂度小于 O(n2) 。(两次循环)
- 数组中只有一个重复的数字,但它可能不止重复出现一次。
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])为例:
在 示例一 中,起点与终点都是 “2 ” 所以返回重复值——2;
同样,在示例二([3,1,3,4,2])中也可以将数组转化为图来观察:
由图可以看出,环出现在了 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。
乌龟和兔子均跑自己的值:
经过两次后找到相同数:
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