题目1链接:https://leetcode.com/problems/find-all-duplicates-in-an-array/
题目2链接:https://leetcode.com/problems/find-the-duplicate-number/
这道题目在剑指offer面试题3 P39
先看题目一:
数组大小为n,数组元素A[i]在[1,n]中,里面有重复数字,找出所有重复数字
最朴素的思路一:哈希法
class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> ret=new LinkedList<Integer>();
HashSet<Integer> set=new HashSet<Integer>();
for(int i=0;i<nums.length;i++)
{
if(set.contains(nums[i]))
ret.add(nums[i]);
else
set.add(nums[i]);
}
return ret;
}
}
时间复杂度为:O(n)
空间复杂度:O(n)
思路二:先用快排,再遍历一遍数组
class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> ret=new LinkedList<Integer>();
Arrays.sort(nums);
for(int i=1;i<nums.length;i++)
{
if(nums[i]==nums[i-1])
ret.add(nums[i]);
}
return ret;
}
}
时间复杂度:O(nlogn)
空间复杂度:O(logn)
扫描二维码关注公众号,回复:
4220846 查看本文章
思路三:用一个长度为(n+1)的计数数组,代码如下:
class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> ret=new LinkedList<Integer>();
int[] counter=new int[nums.length+1];
for(int i=0;i<nums.length;i++)
counter[nums[i]]+=1;
for(int i=1;i<counter.length;i++)
if(counter[i]>1)
ret.add(i);
return ret;
}
}
时间复杂度为:O(n)
空间复杂度:O(n)
对于问题二,相较于问题一简单不少,(除了上述解法)但解法多样,非常有趣!
思路一:基于二分法,以1~n为搜索范围,遍历数组搜索小于等于mid的数字的个数count(计数),当count大于mid时,说明重复数字必然在[1,mid]间,缩小范围搜索;否则(count小于等于mid),在(mid,n]之间缩小范围搜索(注意遇见的开闭与二分搜索的写法)。
class Solution {
public static int findDuplicate(int[] nums) {
int left=1,right=nums.length-1;
int mid=0;
while(left<right)
{
int count=0;
mid=left+(right-left)/2;
for(int j=0;j<nums.length;j++)
if(nums[j]<mid+1)
count++;
if(count>mid)
right=mid;
else
left=mid+1;
}
return left;
}
}
思路二:基于Floyd龟兔赛跑算法,非常的tricky,具体原理证明参考https://blog.csdn.net/To_be_to_thought/article/details/83958314:
class Solution {
public int findDuplicate(int[] nums) {
int pFast=0,pSlow=0;
while(true)
{
pSlow=nums[pSlow];
pFast=nums[nums[pFast]];
if(pSlow==pFast)
{
pFast=0;
while(pFast!=pSlow)
{
pFast=nums[pFast];
pSlow=nums[pSlow];
}
return pFast;
}
}
}
}