September LeetCoding Challenge, Day 2: Contains Duplicate III
September 3, 2020The problem for September 2 is Contains Duplicate III. The title of
the problem is a bit misleading, since the statement isn’t about finding
duplicates. Instead, we’re interested in finding, from an array of numbers
nums and integers k and t, whether there are two distinct indices i and
j such that the absolute difference of nums[i] and nums[j] is at most t
and the absolute difference between i and j is at most k.
One way to approach this problem is to, for each number in the array, check if
there is a number in the previous k numbers such that the absolute difference
between them is at most k. If we can keep a sorted list of k numbers at all
times, we should be able to do this in \(\mathcal{O}(n \times log(k))\), \(n\)
being the size of the nums array. The \(\mathcal{O}(n)\) part is due to the
fact that we have to iterate through all elements of nums. The
\(\mathcal{O}(log(k))\) part is due to the fact that, if we can keep a sorted
list of the previous k numbers, we can binary search for the element that
minimizes the absolute difference. A way to implement this in C++ is to use a
multiset (a simple set doesn’t work since there can be repeated elements in
nums). Elements in C++
multisets are sorted and
the interface provides both lower_bound and upper_bound methods to search
for elements in logarithmic time complexity. The following is an implementation
of that strategy:
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
if (nums.empty() || k == 0)
return false;
multiset<int> current;
current.insert(nums[0]);
int N = nums.size();
for (int i = 1; i < N; ++i) {
auto l_itr = current.lower_bound(nums[i]);
if (l_itr != current.end() &&
abs(((long long) *l_itr) - ((long long) nums[i])) <= t)
return true;
if (l_itr != current.begin() &&
abs(((long long) *(--l_itr)) - ((long long) nums[i])) <= t)
return true;
current.insert(nums[i]);
if (current.size() > k)
current.erase(current.find(nums[i - k]));
}
return false;
}
};We check two numbers in each iteration: the number returned by the lower_bound
method (which is going to be the first number that is larger than or equal to
nums[i]) and the number immediately before (the larger number that is smaller
than nums[i]). One of those is going to be the one producing the smallest
absolute difference. If the smallest absolute difference is not greater than
t, we have found a satisfying pair.
The casts to long long are necessary because, even though t is an int, the
absolute difference between two numbers in nums may not fit in an int
(consider \(|2147483647 - (-2147483648)|\) for example).