Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/fi…
二、思路分析:
开始看到这题以为蛮简单的,只要我把对应的数字,放到对应的位置,当有重复的时候就说明该数字就是重复的数字,时间复杂度O(n),空间复杂度O(1),可是后面一句把我整不会了,不能改变原数组,哦豁,这下可麻烦了。遇到困难睡大觉,我心中就剩下二分查找这种方法,时间复杂度应该为nlogn,空间复杂度为O(1),应该就是最优解了吧。
首先由于数中有重复值,假设我们随意去一个a,如果小于这个数的量严格大于我的a,那么重复的数就在小于a的那边查找,否则则是在大的那边查找。
写完美滋滋的看下搞笑评论区,哦豁第一条竟然不是抱怨的(还是有说这题脱裤子放屁的),我看到了一种O(n)时间复杂度,O(1)空间复杂度的题解循环链表解法,看完真的是妙啊!
快慢指针思想, fast 和 slow 是指针, nums[slow] 表示取指针对应的元素注意 nums 数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),因为有重复数字的出现, 所以这个游走必然是成环的, 环的入口就是重复的元素, 即按照寻找链表环入口的思路来做。
三、AC 代码:
代码一:
/**
* @param {number[]} nums
* @return {number}
*/
var findDuplicate = function(nums) {
let left=1,right=nums.length-1;
while(left<=right){
let mid=Math.floor((left+right)/2);
let cnt=0;
for(let i=0;i<nums.length;i++){
if(nums[i]<=mid){
cnt++;
}
}
if(cnt>mid){
right=mid-1;
}else{
left=mid+1;
}
}
return left;
};
代码二:
/**
* @param {number[]} nums
* @return {number}
*/
var findDuplicate = function(nums) {
let fast=0,slow=0;
while(true){
fast=nums[nums[fast]];
slow=nums[slow];
if(slow===fast){
fast=0;
while(nums[slow]!==nums[fast]){
fast=nums[fast];
slow=nums[slow];
}
return nums[slow];
}
}
};
四、总结:
题目做完还是多看下评论区,不仅搞笑解压,还可以收获很多不同的思想。