Tuesday, May 31, 2016

Contains Duplicate III -- LeetCode

[Question]
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.

[Analysis]
If using brute force, going through each nums[i] and checking whether any of nums[i+1],..., nums[i+k] values are within the range of [ nums[i]-t, nums[i]+t ], the time complexity is O( K^2 * N ).

Making a BST for the sub-array { nums[i+1],..., nums[i+k] }, and find if any values in the BST fall into [ nums[i]-t, nums[i]+t ], the time complexity is O(log K * N).

The interesting part of the C++ code below is, how to use "multiset" as a BST and fulfill the above logic in just a few lines.

Update: Using bucket sort is a better solution. The time complexity is O(N).

[Solution]
class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        if (nums.empty() || k<=0 || t<0) return false;

        multiset<int> bst (nums.begin(), nums.begin()+k);
        for (int i=0; i<nums.size(); i++) {
            bst.erase(bst.find(nums[i]) );
            if (i+k<nums.size()) bst.insert(nums[i+k]);
         
            // -- make sure the boundary condition --
            if (bst.find(nums[i]+t)!=bst.end() || bst.find(nums[i]-t)!=bst.end() ) return true;

            if (bst.upper_bound(nums[i]+t) != bst.upper_bound(nums[i]-t)) return true;
        }
        return false;
    }
};

//-- Bucket Sort --
class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        if (k<1 || t<0) return false;
        int min_elem = *min_element(nums.begin(), nums.end());
     
        unordered_map<long, long> buckets;
        for(int i=0; i<nums.size(); i++) {
            long key = (nums[i]-min_elem) / (t+1);
            if (buckets.count(key)>0) return true;
            if (buckets.count(key-1)>0 && abs(nums[i]-buckets[key-1]) <= t
                || buckets.count(key+1)>0 && abs(nums[i]-buckets[key+1]) <=t)
                return true;
            buckets[key] = (long)nums[i];
         
            if (i>=k) buckets.erase( (nums[i-k]-min_elem)/(t+1) );
        }
        return false;
    }
};

No comments:

Post a Comment