可以修改数组找出数组中重复的数字
给定一个长度为 n+1 的数组nums,数组中所有的数均在 1∼n 的范围内,其中 n≥1。
请找出数组中任意一个重复的数,但不能修改输入的数组。
样例
给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。
返回 2 或 3。
要求 如果只能使用 O(1) 的额外空间和使用o(n)的时间来解决
思路
寻找重复的元素很容易想到用hash表进行遍历如果存hash表中存在这个元素说明找到了重复的元素这种方法可以在o(n)的时间内解决问题但是用到了o(n)的额外空间复杂度不符合要求。
题目中所有的数字都在[0,n-1]的区间范围内因此hash表的大小为n因此我们实际要做的就是对n个范围为0到n-1的数进行哈希,而哈希表的大小刚好为n
对排序算法比较熟悉的同学不难发现这与一种经典的排序算法(基数排序)非常类似。而基数排序的时间空间复杂度刚好符合题目要求。因此尝试使用基数排序来解这道面试题。
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
for(auto x:nums)
{
if(x<0||x>=nums.size()) return -1;
}
for(int i=0;i<nums.size(); )
{
if(nums[i]!=i)
{
if(nums[i]==nums[nums[i]])
return nums[i];
else
swap(nums[i],nums[nums[i]]);
}
else
i++;
}
return -1;
}
};
第二种代码
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
for(auto x:nums)
{
if(x<0||x>=nums.size()) return -1;
}
for(int i=0;i<nums.size();i++ )
{
while (nums[nums[i]] != nums[i]) swap(nums[i], nums[nums[i]]);
if (nums[i] != i && nums[nums[i]] == nums[i]) return nums[i];
}
return -1;
}
};
不修改数组找出重复的数字
给定一个长度为 n+1 的数组nums,数组中所有的数均在 1∼n 的范围内,其中 n≥1。
请找出数组中任意一个重复的数,但不能修改输入的数组。
样例
给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。
返回 2 或 3。
如果只能使用 O(1) 的额外空间时间复杂度没有限制
思路
分治,抽屉原理) O(nlogn)O(nlogn)
这道题目主要应用了抽屉原理和分治的思想。
抽屉原理:n+1 个苹果放在 n 个抽屉里,那么至少有一个抽屉中会放两个苹果。
思路是将这个数组的按数值进行二分分为[1,n/2]和[n/2+1,n]然后遍历数组统计在这个区间里的出现的数的个数
如果出现了重复的数那么它的这个区间里数的个数肯定超过了区间的长度然后依次减半直到找到重复的数
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int l=1,r=nums.size()-1;//这里是用的数字的值的取值范围做的二分不是数组下标所以l=1
while(l<r)
{
int mid=(l+r)>>1;
int s=0;
for(auto x :nums) s+=(x>=l&&x<=mid);
if(s>mid-l+1)
r=mid;
else
l=mid+1;
}
return r;
}
};