找出数组中一个重复的数字
数组大小为n+1,数组中数字大小为[1,n],只有一个重复
分析这个题发现有n+1个整数,数组下标在[0,n],数字大小在[1,n],也就是数组中最起码有一个重复的数,假设只有一个重复的值(记住这种时候比的是数组,下标用num[i]-1记录)
(1)在一个排序好的数组中找到重复的数字非常容易,排序的时间复杂度是O(nlogn)。
(2)然后也可以利用哈希表来解决这个问题,扫描到一个数字时利用O(1)的复杂度来看是否哈希表中中已经包含了该数字,这样的话只要遍历一遍就可以得到,但这样是以一个空间复杂度为O(n)的哈希表来为代价的。也就是遍历数组,并建立一个boolean数组记录这个数字是否遍历过(这里使用的最大原因是数组的内容长度在0到n-1范围内,否则可以利用一个map来记录),找到返回即可。
(3)所以最好想一个空间复杂度为O(1)也就是不用额外分配空间的算法。因为数组在1到n的范围内,所以如果没有重复,大小为i的数字排序好会出现在i-1的位置上,而且数字0是不会出现的,循环数组进行数组遍历,这个题肯定不会缺失数,所以比较i和arr[i]-1是否相等,相等则i++,不相等则交换arr[i]和arr[arr[i]],在交换之前要看会出现这两个值相等的情况,只要出现说明这个数字就是那个重复的数字。时间复杂度为O(n)。空间复杂度为O(1)。
(4)如果数组不允许更改,则使用partition算法。
class Solution {
public int findDuplicate(int[] nums) {
if(nums==null || nums.length==0) return 0;
int i=0;
int n=nums.length;
while(i<n){
int x=nums[i]-1;
if(x!=i){
if(nums[x]==nums[i]) return nums[i];
else{
nums[i]=nums[x];
nums[x]=x+1;
}
}else{
i++;
}
}
return n;
}
(4)如果不能修改数组,则可以使用partition思想来做
长度为n,数字在[0,n-1]中。不知道有几个重复了,求输出任意一个重复的数字。
分析可知这个数组的下标为[0,n-1],数字大小也为[0,n-1],所以如果没有重复,数字arr[i]会等于i。他现在是不知道有几个重复的值,随便输出一个就行。循环数组,此时可能会有缺的值,也可能会有重复值,所以在遍历过程中先判断i是否等于arr[i],若等于则i++,若不等于则再判断arr[i]和arr[arr[i]],不等于则要交换arr[i]和arr[arr[i]],如果相等则这两个值就是重复的值,输出即可。
class Solution {
public int findRepeatNumber(int[] nums) {
if(nums==null || nums.length==0) return -1;
int i=0;
int n=nums.length;
while(i<n){
int x=nums[i];
if(x!=i){
if(x==nums[x]){
return x;
}else{
nums[i]=nums[x];
nums[x]=x;
}
}else{
i++;
}
}
return -1;
}
}
如果要求输出第一个(牛客网)
这样会打乱求的顺序,所以应该换一种做法,比如说用哈希表
public boolean duplicate(int numbers[],int length,int [] duplication) {
if(numbers==null || numbers.length==0) return false;
boolean[] hash=new boolean[length];
for(int i=0;i<length;i++){
if(hash[numbers[i]]==false){
hash[numbers[i]]=true;
}else{
duplication[0]=numbers[i];
return true;
}
}
return false;
}
数组长度为n,元素为[1,n],有些元素出现一次有些元素出现两次。要找到所有的出现两次的元素。要求不用空间复杂度。
分析可知这个题无序数组,数组大小有限,下标为[0,n-1],而元素为1到n,所以如果所有元素出现1次就是下标为i的元素为i+1.现在不是这样,那利用循环排序来排好,这样各个元素都会在自己的位子上,不在自己位子上的就是多出来的。
import java.util.ArrayList;
class Solution {
public List<Integer> findDuplicates(int[] nums) {
List<Integer> res=new ArrayList<Integer>();
if(nums==null || nums.length==0)return res;
int i=0;
int n=nums.length;
while(i<n){
int x=nums[i]-1;
if(x!=i && nums[i]!=nums[x]){
nums[i]=nums[x];
nums[x]=x+1;
}else{
i++;
}
}
for(int j=0;j<n;j++){
if(nums[j]!=j+1){
res.add(nums[j]);
}
}
return res;
}
}