Skip to content

Commit b28adf5

Browse files
contains duplicate III
1 parent 0291954 commit b28adf5

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package medium;
2+
3+
import java.util.TreeSet;
4+
5+
/**
6+
* 220. Contains Duplicate III QuestionEditorial Solution My Submissions Total Accepted: 33823 Total
7+
* Submissions: 176491 Difficulty: Medium Given an array of integers, find out whether there are two
8+
* distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at
9+
* most t and the difference between i and j is at most k.
10+
*/
11+
public class ContainsDuplicateIII {
12+
/**
13+
* TreeSet: per Java doc, is a NavigableSet implementation based on a TreeMap. The elements are ordered
14+
* using their natural ordering, or by a Comparator provided at set creation time, depending on
15+
* which constructor is used. This implementation provides guaranteed log(n) time cost for the
16+
* basic operations (add, remove and contains).
17+
*/
18+
19+
/**
20+
* TreeSet turns out to be a super handy data structure for this problem. It implements Set
21+
* interface and keeps elements in sorted order, plus it has two very handy APIs:
22+
*
23+
* https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html#ceiling(E): Returns the
24+
* least element in this set greater than or equal to the given element, or null if there is no
25+
* such element.
26+
*
27+
* https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html#floor(E): Returns the
28+
* greatest element in this set less than or equal to the given element, or null if there is no
29+
* such element.
30+
*
31+
* Idea: loop through this array, keep adding each element into the TreeSet, also keep an eye on
32+
* the size of the TreeSet, if it's greater than the required distance of k, then we remove the
33+
* left-most or oldest one from the set. For each element, we get the current floor and the
34+
* current ceiling and see if it works, if it does, then we return true immediately, otherwise,
35+
* we continue. Return false when we finished the loop.
36+
*/
37+
38+
//Really, computing is all about data structures! Cool! Learned the gist again!
39+
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
40+
TreeSet<Integer> set = new TreeSet<Integer>();
41+
for(int i = 0; i < nums.length; i++){
42+
Integer s = set.ceiling(nums[i]);//take the smallest greater number than nums[i] is there exists
43+
if(s != null && s - nums[i] <= t) return true;//it must be s - nums[i] here, otherwise, cases like [4,2] 2, 1 wont' pass, because we'll get 2-4 = -2 which is a negative number that for sure will be smaller than t
44+
Integer g = set.floor(nums[i]);//take the biggest smaller number than nums[i] if there exists
45+
if(g != null && (long) nums[i] - g <= t) return true;
46+
set.add(nums[i]);
47+
if(set.size() > k) set.remove(nums[i-k]);//set doesn't have indices and it's not ordered, we could only specify the element
48+
//that we want to remove, this element is nums[i-k]
49+
}
50+
return false;
51+
}
52+
53+
//My naive approach prior to looking on Discuss:
54+
//it must be a O(n^2), I cannot think of any algorithms that do better than this
55+
// as expected, this following algorithm made it to 29/31 test cases and failed by the last
56+
// extreme test case due to TLE.
57+
public boolean containsNearbyAlmostDuplicate_TLE(int[] nums, int k, int t) {
58+
for (int i = 0; i < nums.length; i++) {
59+
for (int j = i + 1; j < nums.length; j++) {
60+
long res = nums[j] - nums[i];// use long type to avoid overflow
61+
if (Math.abs(res) <= t && j - i <= k)
62+
return true;
63+
}
64+
}
65+
return false;
66+
}
67+
68+
/**
69+
* converting to (long) is essential, otherwise cases like this:
70+
*
71+
* [-1,2147483647]
72+
*
73+
* 1
74+
*
75+
* 2147483647
76+
*
77+
* will overflow, i.e. Integer in Java is 32 bit which means Integer.MAX_VALUE =2147483647 and
78+
* Integer.MIN_VALUE = -2147483648, thus 2147483647 -(-1) = 2147483647+1 =-2147483648 instead of
79+
* 2147483648 (Java Integer won’t have this number), causing this test case to fail.
80+
*/
81+
82+
public static void main(String... strings) {
83+
ContainsDuplicateIII test = new ContainsDuplicateIII();
84+
// int[] nums = new int[]{-1, -1};
85+
// int k = 1;
86+
// int t = 0;
87+
88+
// int[] nums = new int[] { 1, 2 };
89+
// int k = 0;
90+
// int t = 1;
91+
92+
int[] nums = new int[] { 4, 2 };
93+
int k = 2;
94+
int t = 1;
95+
96+
// int[] nums = new int[]{2, 2};
97+
// int k = 3;
98+
// int t = 0;
99+
100+
// int[] nums = new int[]{1};
101+
// int k = 1;
102+
// int t = 1;
103+
System.out.println(test.containsNearbyAlmostDuplicate(nums, k, t));
104+
}
105+
}

0 commit comments

Comments
 (0)