Skip to content

Commit

Permalink
feat(C++): Add 220
Browse files Browse the repository at this point in the history
Interesting question. Learnt about the pitfalls of using
std::lower_bound on containers that do not provide random access
iterators.

Also, there is an O(n) solution for this. Should revisit.
  • Loading branch information
euchangxian committed Nov 4, 2024
1 parent f03496c commit f0e5c6c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
65 changes: 65 additions & 0 deletions C++/0220-ContainsDuplicateThree/Solution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <cstddef>
#include <cstdlib>
#include <set>
#include <vector>

using namespace std;
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums,
int indexDiff,
int valueDiff) {
// Unlike Contains Duplicate Two, which only has the distance constraint,
// this has a value constraint, i.e., there is no need for actual
// duplicates.
// Naively, check every neighbour that is in the range
// [nums[i] - k, nums[i] + k].
// Not viable, since k <= 10^9
// What about sorting? Wait. Pause, first, we should try to find nearby
// duplicates. Since |a - a| = 0 is always <= than any valueDiff
// requirements.
// If there are no duplicates, then?
// Ahhhhhh. What about using an ordered_map instead??
// We first go through to find duplicates. But this time, we maintain the
// size of the map to only indexDiff+1 elements. Then, we can check the
// smallest element stored in the map first. If it satisfies the valueDiff,
// then we found our pairs, since it must also satisfy the indexDiff given
// the size of the map.
const int capacity = indexDiff + 1;
std::set<int> window;

for (int r = 0; r < nums.size(); ++r) {
if (window.size() >= capacity) {
// erase the left of the window, since it wont satisfy indexDiff
window.erase(nums[r - capacity]);
}

// actually, checking the min/max of the ordered set wouldnt work.
// Consider the sequence [0, 1000, 10 000], valueDiff = 5, nums[r] = 1005.
// i.e., binary search is more appropriate to find the closest value?
// lower_bound to find first >= nums[r], take its previous to find the
// first < nums[r]
// WARNING: std::lower_bound would do a linear scan instead of the
// intended binary search on std::set. This is because std::set iterators
// are bidirectional iterators (a binary search tree underneath the hood),
// and not random access iterators like std::vectors, std::arrays etc.
// Therefore, std::set::lower_bound must be used instead.
auto iter = window.lower_bound(nums[r]);
if (iter != window.end() && std::abs(*iter - nums[r]) <= valueDiff) {
return true;
}

if (iter != window.begin()) {
--iter;

if (std::abs(*iter - nums[r]) <= valueDiff) {
return true;
}
}

// otherwise, push nums[r] in
window.insert(nums[r]);
}
return false;
}
};
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ Now solving in C++. Like it.
| 214 | ShortestPalindrome | [![C++](assets/c++.svg)](C++/0214-ShortestPalindrome/Solution.cpp) |
| 215 | KthLargestElementInAnArray | [![C++](assets/c++.svg)](C++/0215-KthLargestElementInAnArray/Solution.cpp) |
| 219 | ContainsDuplicateTwo | [![C++](assets/c++.svg)](C++/0219-ContainsDuplicateTwo/Solution.cpp) |
| 220 | ContainsDuplicateThree | [![C++](assets/c++.svg)](C++/0220-ContainsDuplicateThree/Solution.cpp) |
| 221 | MaximalSquare | [![C++](assets/c++.svg)](C++/0221-MaximalSquare/Solution.cpp) |
| 225 | ImplementStackUsingQueues | [![C++](assets/c++.svg)](C++/0225-ImplementStackUsingQueues/Solution.cpp) |
| 226 | InvertBinaryTree | [![C++](assets/c++.svg)](C++/0226-InvertBinaryTree/Solution.cpp) |
Expand Down

0 comments on commit f0e5c6c

Please sign in to comment.