Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Note:
O(n2)
.加入忽略题目对时间复杂度(less than O(N^2))和空间复杂度(O(1))的要求,可以想到有以下几种方法:
(1)直接搜索法
时间复杂度O(N^2),空间复杂度O(1).针对每个元素,向后寻找是否存在其重复元素。
(2)哈希表法
时间复杂度O(N),空间复杂度O(N).
用一个集合/map记录已经遍历过的数,如果已经有了说明是重复数字。(集合中元素不可重复,map中key不可重复)
public int findDuplicate(int[] nums){ Map<Integer,Integer> myMap = new HashMap<Integer,Integer>(); //Set<Integer> mySet = new HashSet<Integer>(); for(int num:nums){ if(myMap.containsKey(num)) return num; myMap.put(num, 1); /* * if(mySet.contains(num)) return num; * mySet.add(num); */ } return 0; }
时间复杂度O(N*logN),空间复杂度O(1)/O(N). (如果不复制数组,则空间复杂度为O(1),但是排序时会改变原数组;复制数组则空间复杂度为O(N)).
public int findDuplicateBySort(int[] nums){ Arrays.sort(nums); for(int i=1;i<nums.length;i++){ if(nums[i] == nums[i-1]) return nums[i]; } return 0; } public int findDuplicateBySortAndCopy(int[] nums){ int[] newArr = Arrays.copyOf(nums, nums.length); Arrays.sort(newArr); for(int i=1;i<nums.length;i++){ if(newArr[i] == newArr[i-1]) return newArr[i]; } return 0; }
然后看了网上的一些参考答案,寻找到一些符合题目要求的算法:
(1)二分法
由于这n+1个数字介于1~n之间,首先用二分法选择n/2作为比较对象,当整个数组中小于等于n/2的数字超过n/2,说明1~n/2之间肯定有重复数字,否则n/2~n之间肯定有重复数字,下次在有重复数字的区间内再次使用二分法。
public class Solution { public int findDuplicate(int[] nums) { int min = 0, max = nums.length-1; while(min<=max){ int mid = (max-min)/2+min; int count = 0; for(int i=0;i<nums.length;i++) if(nums[i]<=mid) count++; if(count<=mid) min = mid+1;//后半部分有重复 else max = mid-1; //前半部分有重复 } return min; } }(2)寻找环路法
https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare
有时间多看看==