Skip to content

Commit 774d4aa

Browse files
committed
287. Find the Duplicate Number
1 parent 66387f7 commit 774d4aa

File tree

3 files changed

+101
-0
lines changed

3 files changed

+101
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2016 Baidu Inc. All rights reserved.
2+
3+
package joshua.leetcode.array.binarysearch;
4+
5+
/**
6+
* 287. Find the Duplicate Number<br>
7+
* <p/>
8+
* <a href = "https://leetcode.com/problems/find-the-duplicate-number/">leetcode link</a>
9+
*
10+
* @author Jiang Yong ([email protected])
11+
*/
12+
public abstract class FindTheDuplicateNumber {
13+
14+
/**
15+
* 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.
16+
* <p/>
17+
* Note:<br/>
18+
* <ul>
19+
* <li>You must not modify the array (assume the array is read only).</li>
20+
* <li>You must use only constant, O(1) extra space.</li>
21+
* <li>Your runtime complexity should be less than O(n2).</li>
22+
* <li>There is only one duplicate number in the array, but it could be repeated more than once.</li>
23+
* </ul>
24+
*
25+
* @param nums the input array
26+
* @return the duplicated number
27+
*/
28+
public abstract int findDuplicate(int[] nums);
29+
30+
/**
31+
* Binary Search算法。
32+
*
33+
* 假设不出现重复数字的话,假设数组为 [1,2,3,4], n = 4, 那么在落在任意左开右闭区间(i,j]上的元素的个数即为:j-i个,
34+
* 如(2,3]区间上的元素为1个,即为:[3], (2,4]区间上的元素为2个,即为[3],[4]
35+
* 那么整体思路如下:
36+
* 对区间[1,n+1]不断二分,每次计算落在左半区间和右半区间的元素的个数,如果某个区间的元素个数比区间长度大,说明落在这个区间的存在重复元素。
37+
* 这样时间复杂度为o(logn*n)
38+
*
39+
*/
40+
public static class Solution1 extends FindTheDuplicateNumber {
41+
42+
@Override
43+
public int findDuplicate(int[] nums) {
44+
int low = 1;
45+
int high = nums.length - 1;
46+
while (low < high) {
47+
int mid = (low + high) / 2;
48+
int offset = high - mid;
49+
for (int num : nums) {
50+
if (num > mid && num <= high) {
51+
offset --;
52+
}
53+
}
54+
// 落在右半边的元素个数比有半边区间长度大,说明右半边有重复元素,窗口移到右半边
55+
if (offset < 0) {
56+
low = mid + 1;
57+
} else {
58+
high = mid;
59+
}
60+
}
61+
return low;
62+
}
63+
}
64+
65+
}

src/main/java/joshua/leetcode/array/greedy/RemoveDuplicateLetters.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public abstract class RemoveDuplicateLetters {
3333
static class Solution1 extends RemoveDuplicateLetters {
3434

3535
/**
36+
* 结果要求是按照字母顺序从小到大排列的。
37+
* 算法:
38+
*
3639
* 使用栈来保存最后的结果,并用额外空间保存所有的字母的出现次数。
3740
* 元素进栈时,和栈顶元素比较。
3841
* 同时需要保存该字母是否已经在结果中的信息。例如
@@ -58,8 +61,10 @@ public String removeDuplicateLetters(String s) {
5861
counters.put(ch, counters.get(ch) - 1);
5962
continue;
6063
}
64+
//为ch找一个最靠前的位置,只要栈顶字母比ch大,后面还会再出现元素,就会一直弹出栈顶元素。
6165
while (!result.isEmpty()) {
6266
char top = result.getLast();
67+
// 如果后面不会再出发top这个字母,则不能出栈了。
6368
if (counters.get(top) == 1)
6469
break;
6570
if (top >= ch) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package joshua.leetcode.array.binarysearch;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.util.Map;
6+
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
10+
import com.google.common.collect.Maps;
11+
12+
public class FindTheDuplicateNumberTest {
13+
14+
private Map<int[],Integer> cases = Maps.newHashMap();
15+
16+
@Before
17+
public void setUp() {
18+
int[] nums = new int[]{2, 2, 1, 3,2};
19+
cases.put(nums, 2);
20+
nums = new int[]{1, 1, 1, 3,2};
21+
cases.put(nums, 1);
22+
}
23+
24+
@Test
25+
public void testSolution1() {
26+
FindTheDuplicateNumber solution = new FindTheDuplicateNumber.Solution1();
27+
for(int[] nums : cases.keySet()) {
28+
assertEquals((int)cases.get(nums), solution.findDuplicate(nums));
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)