Saturday, February 29, 2020

Longest Substring with At Most K Distinct Characters

Given a string, find the length of the longest substring T that contains at most k distinct characters.
Example 1:
Input: s = "eceba", k = 2
Output: 3
Explanation: T is "ece" which its length is 3.
Example 2:
Input: s = "aa", k = 1
Output: 2
Explanation: T is "aa" which its length is 2.

class Solution {
public:
    int lengthOfLongestSubstringKDistinct(string s, int k) {
        vector<pair<char, int>> temp;
        int ans = 0;
        if (s.size() == 0 || k == 0) {
            return ans;
        }
        if (s.size() == 1) {
            return 1;
        }
       
        int count = 1;
        for (int i = 1; i < s.size(); i++) {
            if (s[i] == s[i - 1] ) {
                count++;
            } else {
                temp.push_back(make_pair(s[i-1], count));
                count = 1;
            }
        }
        temp.push_back(make_pair(s[s.size() - 1], count));
        int start = 0, end = 0;
        int kSum = 0;
        map<char, int> mp;
        while (end < temp.size()) {
            mp[temp[end].first] += temp[end].second;
            kSum += temp[end].second;
            while (mp.size() > k) {
                mp[temp[start].first] -= temp[start].second;
                kSum -= temp[start].second;
                if (mp[temp[start].first] == 0) {
                    mp.erase(temp[start].first);
                }
                start++;
            }
            ans = max(ans, kSum);
            end++;
        }
        return ans;
    }
};

============== Efficient one ======
int lengthOfLongestSubstringKDistinct(string s, int k) {
        int res = 0, left = 0;
        unordered_map<char, int> m;
        for (int i = 0; i < s.size(); ++i) {
            ++m[s[i]];
            while (m.size() > k) {
                if (--m[s[left]] == 0) m.erase(s[left]);
                ++left;
            }
            res = max(res, i - left + 1);
        }
        return res;
    }

34. Find First and Last Position of Element in Sorted Array

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm's runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans = {-1, -1};
        int start = 0, end = nums.size() - 1;
        if (nums.size() == 0) {
            return ans;
        }
       
        int left = -1;
        while (start <= end) {
            int mid = start + (end - start)/2;
            if (nums[mid] == target) {
                if (mid == start) {
                    left = start;
                    break;
                }
                if (nums[mid - 1] < target) {
                    left = mid;
                    break;
                } else {
                    end = mid - 1;
                }
            } else if (nums[mid] > target) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }
        int right = -1;
        start = 0;
        end = nums.size() - 1;
        while (start <= end) {
            int mid = start + (end - start)/2;
            if (nums[mid] == target) {
                if (mid == end) {
                    right = end;
                    break;
                }
                if (nums[mid + 1] > target) {
                    right = mid;
                    break;
                } else {
                    start = mid + 1;
                }
            } else if (nums[mid] > target) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }
       
        return vector<int>{left, right};
    }
};

767. Reorganize String

Given a string S, check if the letters can be rearranged so that two characters that are adjacent to each other are not the same.
If possible, output any possible result.  If not possible, return the empty string.
Example 1:
Input: S = "aab"
Output: "aba"
Example 2:
Input: S = "aaab"
Output: ""
Note:
  • S will consist of lowercase letters and have length in range [1, 500].

struct comp {
    bool operator()(pair<char, int>& first, pair<char, int>& second) {
        return first.second < second.second;
    }
};

class Solution {
public:
    string reorganizeString(string S) {
        string ans;
        if (S.size() == 0 || S.size() == 1) {
            return S;
        }
        // Similar to Task schedule problem with n = 1.
        map<char, int> mp;
        for (auto ch : S) {
            mp[ch]++;
        }
       
        priority_queue<pair<char, int>, vector<pair<char, int>>, comp> pq;
        for (auto entry : mp) {
            pq.push(entry);
        }
       
        while(!pq.empty()) {
            vector<pair<char, int>> remaining;
            for (int i = 0; i < 2; i++) {
                pair<char, int> entry = pq.top(); pq.pop();
                ans += entry.first;
                if(--entry.second > 0) {
                    remaining.push_back(entry);
                }
               
                if (pq.empty()) {
                    // No other char to insert after this one.
                    if (i == 0 && ans.size() != S.size()) {
                        return "";
                    }
                    break;
                }
            }
            for (auto entry : remaining) {
                pq.push(entry);
            }
        }
        return (ans.size() == S.size() ? ans : "");
    }
};

438. Find All Anagrams in a String

Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input:
s: "cbaebabacd" p: "abc"

Output:
[0, 6]

Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input:
s: "abab" p: "ab"

Output:
[0, 1, 2]

Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab".
The substring with start index = 1 is "ba", which is an anagram of "ab".
The substring with start index = 2 is "ab", which is an anagram of "ab".

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;
        if (s.empty() || p.empty()) {
            return ans;
        }
       
        map<char, int> mp;
        for (auto ch : p) {
            mp[ch]++;
        }
       
        int start = 0, end = 0;
        map<char, int>mp2;
        while (end < s.size()) {
            int len = end - start + 1;
            if (len > p.size()) {
                if (--mp2[s[start++]] == 0) {
                    mp2.erase(s[start - 1]);
                }
            }
            mp2[s[end]]++;
            if (mp2 == mp) {
                ans.push_back(start);
            }
            end++;
        }
        return ans;
    }
};

Add Strings

Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.
Note:
  1. The length of both num1 and num2 is < 5100.
  2. Both num1 and num2 contains only digits 0-9.
  3. Both num1 and num2 does not contain any leading zero.
  4. You must not use any built-in BigInteger library or convert the inputs to integerdirectly.

class Solution {
public:
    string addStrings(string num1, string num2) {
        if (num1.empty()) {
            return num2;
        }
        if (num2.empty()) {
            return num1;
        }
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        string ans;
        int carry = 0;
        int i = 0;
        while (i < num1.size() || i < num2.size()) {
            int first = (i < num1.size() ? num1[i] - '0' : 0);
            int second = (i < num2.size() ? num2[i] - '0' : 0);
            int sum = first + second + carry;
            ans += to_string(sum % 10);
            carry = sum / 10;
            i++;
        }
        if (carry) {
            ans += to_string(carry);
        }
        reverse(ans.begin(), ans.end());
        return ans;
    }
};


========= Better one and optimize =======
    string addStrings(string num1, string num2) {
        int size1 = num1.size();
        int size2 = num2.size();
        
        int size = max(size1, size2);
        string ans;
        ans.resize(size + 1);
        int iter = size, iter1 = size1 - 1, iter2 = size2 - 1;
        int carry = 0;
        while (iter1 >= 0 || iter2 >= 0) {
            int dig1 = (iter1 >= 0 ? num1[iter1] - '0': 0);
            int dig2 = (iter2 >= 0 ? num2[iter2] - '0': 0);
            ans[iter--] = '0' + ((carry + dig1 + dig2) % 10);
            carry = (carry + dig1 + dig2) / 10;
            iter1--;
            iter2--;
        }
        if (carry != 0) {
            ans[0] = '0' + carry;
            return ans;
        }
        return ans.substr(1);
    }

986. Interval List Intersections

Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted order.
Return the intersection of these two interval lists.
(Formally, a closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b.  The intersection of two closed intervals is a set of real numbers that is either empty, or can be represented as a closed interval.  For example, the intersection of [1, 3] and [2, 4] is [2, 3].)

Example 1:
Input: A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]]
Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
Reminder: The inputs and the desired output are lists of Interval objects, and not arrays or lists.

Note:
  1. 0 <= A.length < 1000
  2. 0 <= B.length < 1000
  3. 0 <= A[i].start, A[i].end, B[i].start, B[i].end < 10^9

class Solution {
public:
   
    vector<int> intersect(vector<int>& A, vector<int>& B) {
        vector<int> ans;
        if (B[0] > A[1] || A[0] > B[1]) {
            return ans;
        }
        ans = {max(A[0], B[0]), min(A[1], B[1])};
        return ans;
    }
   
    vector<vector<int>> intervalIntersection(vector<vector<int>>& A, vector<vector<int>>& B) {
        vector<vector<int>> ans;
        if (A.size() == 0 || B.size() == 0) {
            return ans;
        }
       
        int size_a = A.size();
        int size_b = B.size();       
        int first = 0, second = 0;
       
        while (first < size_a && second < size_b) {
            vector<int> sol = intersect(A[first], B[second]);
            if (sol.size() > 0) {
                ans.push_back(sol);
            }
            if (A[first][1] > B[second][1]) {
                second++;
            } else if (A[first][1] < B[second][1]) {
                first++;
            } else {
                first++;
                second++;
            }
        } 
        return ans;
    }
};

621. Task Scheduler

Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks. Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle.
However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle.
You need to return the least number of intervals the CPU will take to finish all the given tasks.

Example:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.

Note:
  1. The number of tasks is in the range [1, 10000].
  2. The integer n is in the range [0, 100].

struct comp {
    bool operator()(pair<char, int>& first, pair<char, int>& second) {
        return first.second < second.second;
    }
};

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
        int ans = 0;
        if (tasks.size() == 0 || n ==0) {
            return tasks.size();
        }
        // Get tasks count in map.
        map<char, int> mp;
        for (auto task : tasks) {
            mp[task]++;
        }
        
        priority_queue<pair<char, int>, vector<pair<char, int>>, comp> pq;
        // Store the pair info into prioriy queue.
        for (auto entry : mp) {
            pq.push(entry);
        }
        
        while (!pq.empty()) {
            vector<pair<char, int>> tasksCompleted;
            for (int i = 0; i <= n; i++) {
                if (!pq.empty()) {
                    // This means that a task can be scheduled in this interval.
                    pair<char, int> entry = pq.top(); pq.pop();
                    // Decrement the task count list.
                    entry.second--;
                    if (entry.second != 0) {
                        tasksCompleted.push_back(entry);
                    }
                }       
                // Increment the ans.
                ans++;
                if (pq.empty() && tasksCompleted.size() == 0) {
                    return ans;
                }
            }
            // Check if tasks are pending.
            for (auto entry : tasksCompleted) {
                pq.push(entry);
            }
        }
        return ans;
    }
};

========= Next time =====
struct comp {
    bool operator()(pair<char, int>& first, pair<char, int>& second) {
        return first.second < second.second;
    }
};

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
        map<char, int> mp;
        for (auto task: tasks) {
            mp[task]++;
        }
        priority_queue<pair<char, int>, vector<pair<char, int>>, comp> pq;
        for (auto entry : mp) {
            pq.push(entry);
        }
        
        int ans = 0;
        while (!pq.empty()) {
            vector<pair<char, int>> remaining_tasks;
            for (int i = 0; i <= n; i++) {
                if (pq.empty() && remaining_tasks.size() == 0) {
                    return ans;
                }
                ans++;
                if (pq.empty()) {
                    continue;
                }
                pair<char, int> entry = pq.top(); pq.pop();
                entry.second--;
                if (entry.second > 0) {
                    remaining_tasks.push_back(entry);
                }
            }
            for (auto task : remaining_tasks) {
                pq.push(task);
            }
        }
        return ans;
    }
};

=========== Another approach using free slots =====
int leastInterval(vector<char>& tasks, int n) { int max_freq=0; vector<int> freq(26,0); for (char c : tasks) freq[c-'A']++; sort(freq.begin(),freq.end()); int free_slots=(freq[25]-1)*n; for (int i=0; i < 25; i++) free_slots-=min(freq[25]-1,freq[i]); return free_slots <= 0 ? tasks.size() : tasks.size()+free_slots; }

Friday, February 28, 2020

Binary Tree Right Side View

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
Example:
Input: [1,2,3,null,5,null,4]
Output: [1, 3, 4]
Explanation:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> ans;
        queue<TreeNode *> q;
        if (root == NULL) {
            return ans;
        }
        q.push(root);
        while (!q.empty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                TreeNode *node = q.front(); q.pop();
                if (i == size - 1) {
                    ans.push_back(node -> val);
                }
                if (node -> left) {
                    q.push(node -> left);
                }
                if (node -> right) {
                    q.push(node -> right);
                }
            }
        }
        return ans;
    }
};

========== Recursive =========
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> ans;
        unordered_set<int> st;
        helper(root, st, ans, 0);
        return ans;
    }
    
    void helper(TreeNode* root, unordered_set<int>& st, vector<int>& ans, int height) {
        if (root == NULL) {
            return;
        }
        if (st.count(height) == 0) {
            ans.push_back(root -> val);
        }
        st.insert(height);
        helper(root -> right, st, ans, height + 1);
        helper(root -> left, st, ans, height + 1);
    }
};

K Closest Points to Origin

We have a list of points on the plane.  Find the K closest points to the origin (0, 0).
(Here, the distance between two points on a plane is the Euclidean distance.)
You may return the answer in any order.  The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:
Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation: 
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].
Example 2:
Input: points = [[3,3],[5,-1],[-2,4]], K = 2
Output: [[3,3],[-2,4]]
(The answer [[-2,4],[3,3]] would also be accepted.)

Note:
  1. 1 <= K <= points.length <= 10000
  2. -10000 < points[i][0] < 10000
  3. -10000 < points[i][1] < 10000

=== Map approach O(n) time and space

class Solution {
public:
    vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
        vector<vector<int>> ans;
        if (points.size() == 0 || k == 0) {
            return ans;
        }
        map<int,vector<vector<int>>> mp;
       
        for (auto point : points) {
            int dist = pow(point[0], 2) + pow(point[1], 2);
            mp[dist].push_back(point);
        }
       
        int counter = 0;
        for (auto entry : mp) {
            for (auto point : entry.second) {
                ans.push_back(point);
                if (++counter == k) {
                    return ans;
                }
            }
        }
        return ans;
    }
};

======== Can use just sorting nlogn by writing comparator.

Or, use priority queue or quick select.

===========
struct comp {
    bool operator()(vector<int>& first, vector<int>& second) {
        int dist_one = (first[0]*first[0] + first[1]*first[1]);
        int dist_two = (second[0]*second[0] + second[1]*second[1]);
        return dist_one < dist_two;
    }
};

class Solution {
public:
    vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
        if (points.size() <= k) {
            return points;
        }
        priority_queue<vector<int>, vector<vector<int>>, comp> pq;
        
        for (int i = 0; i < k; i++) {
            pq.push(points[i]);
        }
        
        for (int i = k; i < points.size(); i++) {
            int dist_val = dist(points[i]);
            if (dist_val < dist(pq.top())) {
                pq.pop();
                pq.push(points[i]);
            }
        }
        
        vector<vector<int>> ans;
        while (!pq.empty()) {
            ans.push_back(pq.top());
            pq.pop();
        }
        return ans;
    }
    
    int dist(vector<int> point) {
        return (point[0]*point[0] + point[1]*point[1]);
    }
};

============== Quick select =========
class Solution { public: int distance(vector<int> &a) { return a[0]*a[0] + a[1]*a[1]; } int partition(vector<vector<int>>& points, int low, int high) { int i = low - 1; vector<int> pivot = points[high]; for (int j = low; j < high; j++) { if (distance(points[j]) <= distance(pivot)) { i++; swap(points[i], points[j]); } } swap(points[i + 1], points[high]); return (i + 1); } vector<vector<int>> kClosest(vector<vector<int>>& points, int k) { int low = 0, high = points.size() - 1; while(low <= high) { int ind = partition(points, low, high); if (ind == k - 1) break; else if (ind < k - 1) low = ind + 1; else high = ind - 1; } return vector<vector<int>>(points.begin(), points.begin() + k); } };


========= My attempt (not clean) ====== (above one is better) ======
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) { // K select algorithm. // base cases (size check with k) and other int size = points.size(); int st = 0, end = size - 1; helper(points, st, end, k); vector<vector<int>> ans = vector<vector<int>>(points.begin(), points.begin() + k); return ans; } void helper(vector<vector<int>>& points, int st, int end, int k) { if (st > end) { return; } int idx = partition(points, st, end); if (idx == k - 1) { return; } else if (idx < k - 1) { helper(points, idx + 1, end, k); } else { helper(points, st, idx - 1, k); } } int partition(vector<vector<int>>& points, int st, int end) { int iter = st - 1; int distance = dist(points[end]); for (int cur = st; cur < end; cur++) { if (dist(points[cur]) <= distance) { iter++; iter_swap(points.begin() + iter, points.begin() + cur); } } iter_swap(points.begin() + iter + 1, points.begin() + end); return iter + 1; }