Find the Duplicate number
Given an array nums containing n + 1 integers where each integer is between 1 and N (inclusive), prove that at least one D Uplicate number must exist. Assume that there are only one duplicate number, find the duplicate one.
Note:you must not modify the array (assume the array is read only). You must use only constant, O (1) Extra space. Your runtime complexity should is less than O (N2). There is a duplicate number in the array, but it could was repeated more than once.
The complexity of hash table method
Time O (n) space O (n)
Ideas
When iterating through an array, a collection is used to record the number that has been traversed, if the description is repeated in the collection. But this will be space, do not meet.
The complexity of violence law
Time O (n^2) space O (1)
Ideas
If you don't use space, the most straightforward way is to select a number and then traverse the entire array to see if there are numbers that are the same number.
Sorting method of Complexity
Time O (nlogn) space O (1)
Ideas
A more efficient method is to sort the array so that the same number of loops is repeated, but the original array is modified, and the requirements are not met.
The dichotomy of complexity
Time O (nlogn) space O (1)
Ideas
In fact, we can simplify the violence law just according to the drawer principle. We do not have to select the number in turn, and then see if there is a repetition of this number, we can use the dichotomy method to select N/2, according to the drawer principle, if the whole array is less than or equal to the number of N/2 is greater than N/2, indicating that 1 to n/2 this interval is sure to have duplicate numbers. For example, 6 drawers, if there are 7 socks to put in the drawer, there must be a drawer at least two socks. The drawer here is 1 to n/2 each number, and socks is the whole array of less than equal to the number of N/2. So that we can know the next choice of the number of the range, if there must be a repetition of 1 to N/2 interval, then the next time within the range of 1 to N/2, otherwise in the N/2 to n range. The next time you look, you still find half.
Attention
We compare, mid
notnums[mid]
Because mid is subscript, the judgment should be cnt > mid
, and finally returnmin
Code
PublicClass Solution {Publicint Findduplicate (Int[] nums) {IntMin =0,max = Nums.length-1;WhileMin <=Max) {Find the middle number.int mid =min + (max- min)/ 2; int cnt = 0; //Count the number of numbers in the group is less than or equal to the middle number for (int i = 0; i < nums.length; i++) { if (Nums[i] <= mid) {cnt++;}}
//if less than or equal to the number of intermediate numbers is greater than the middle number, the first half must have duplicate
if (cnt > mid) { max = mid- 1; //Otherwise the second half must be duplicated} else { min = mid + 1;}} return min;}}
Mapping the complexity of the ring-finding method
Time O (N) space O (1)
Ideas
Assuming that there are no duplicates in the array, we can do this by mapping the array's subscript to a one-to-one number from 1 to N. For example, if the array is 213
, the mapping relationship is 0->2, 1->1, 2->3
. Let's assume that this one-to-two mapping relationship is a function f (n), where n is subscript and f (n) is the number mapped to. If we start with subscript 0, a value is computed based on this function, with this value being the new subscript, then using this function to calculate, and so on, until the subscript is over bounds. You can actually produce a list-like sequence. For example, there are two subscript sequences in this example 0->2->3
.
However, if there are duplicates, there will be many pairs of mappings in the middle, such as arrays 2131
, then the mapping relationship is 0->2, {1,3}->1, 2->3
. Thus, the sequence we deduce is bound to have loops, where the sequence of subscripts is 0->2->3->1->1->1->1->...
, and the beginning of the loop is the number of repetitions.
So the problem is actually to find the beginning of the loop, and linked List Cycle II. We start with a speed of two subscript all starting from 0, quickly subscript each round mapping two times, slow down the map once per round, until two subscript again the same. This time to keep the subscript position unchanged, and then with a new subscript starting from 0, the two subscript will continue to map once per round, when the two subscript encounter, is the beginning of the ring, that is, the number of repetitions. For this algorithm does not understand the starting point, please refer to Floyd ' s algorithm.
Attention
The first time to find the speed of the hands meet with Do-while cycle
Code
PublicClass Solution {public int findduplicate (int[] nums) { int slow = 0; int fast = 0; //Find the place where the speed pointer meets do{slow = Nums[slow]; fast = Nums[nums[fast]];} while (slow! = fast); int find = 0; //start from scratch with a new pointer until the slow pointer encounters while (find = slow) {slow = Nums[slow]; find = nums[find];} return Find;}}
Algorithm-Find duplicate numbers (drawer, chain ring)