# Google and Facebook Interviews
## Interview Tips
1. Always give Brute Force for every question.
    - Benefits:
      - It favours against worse odds. It is better to give a brute force then to be totally blank.
      - Predicts Optimal Solution
2. Data Structures/ Algorithms
  
Time Complexity| Datastructure and Algorithms
:--|:--
$O(n\log{n})$ | Sorting
$O(n)$ | Two Pointers/ Smart Sorting/ dfs/ bfs
$O(n^2)$ | Dynamic Programming
$O(\log{n})$ | Binary Search
$O(1)$ | HashMap

3. Writing a working code
    - Google/Facebook/Uber/Microsoft
    - They need working code
    - Take care of Edge cases
      - Candidates may get rejected for not taking care of Edge cases
      - Spend $10\%$ of your time on Edge cases
    - Give proper names to characters
      - Benefits
        - Less Confusion, Error free code 
        - Good presentation and easier to explain

## Question 1 Time Based Key-Value Store
Create a timebased key-value store class TimeMap, that supports two operations.

1. set(string key, string value, int timestamp)
  - Stores the key and value, along with the given timestamp.
2. get(string key, int timestamp)
  - Returns a value such that set(key, value, times tamp_prev) was called previously, with timestamp_prev <= timestamp.
  - If there are multiple such values, it returns the one with the largest timestamp_prev.
  - If there are no values, it returns the empty string ("").
 

Example 1:

```C++
Input: 
inputs = ["TimeMap","set","get","get","set","get","get"], 
inputs = [[],["foo","bar",1],["foo",1],["foo",3],
["foo","bar2",4],["foo",4],["foo",5]]
Output: [null,null,"bar","bar",null,"bar2","bar2"]
Explanation:   
TimeMap kv;   
kv.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1   
kv.get("foo", 1);  // output "bar"   
kv.get("foo", 3); // output "bar" since there is no value corresponding to foo at timestamp 3 and timestamp 2, then the only value is at timestamp 1 ie "bar"   
kv.set("foo", "bar2", 4);   
kv.get("foo", 4); // output "bar2"   
kv.get("foo", 5); //output "bar2"   
```
Example 2:
```C++
Input: inputs = ["TimeMap","set","set","get","get","get","get","get"], inputs = [[],["love","high",10],["love","low",20],["love",5],["love",10],["love",15],["love",20],["love",25]]
Output: [null,null,null,"","high","high","low","low"]
``` 

__Note:__
- All key/value strings are lowercase.
- All key/value strings have length in the range [1, 100]
- The timestamps for all TimeMap.set operations are strictly increasing.
- 1 <= timestamp <= 10^7
- TimeMap.set and TimeMap.get functions will be called a total of 120000 times (combined) per test case.

__Brute Force__
- Store key, value and timestamp in an array.
- For every get request run a linear loop to find the largest timestamp in the given bounds with the given key. Return value.
- Time complexity:
  - TimeMap.set = $O(1)$.
  - TimeMap.get = $O(n)$. Because you are iterating over the whole array.

__Hints__
- Suppose there were no time stamps. What would be the best data structure for this problem. Hashmap, As it gives $O(1)$ look up.
- If we store all the timestamps corresponding to a key in an array, and store that array as value in a HashMap. Then for a given key we can run a loop on the corresponding array and find our answer.
- This approach is still $O(n)$ as we may have only one key.
- It is given that "The timestamps for all TimeMap.set operations are strictly increasing." Can we do a binary search to find our answer?
- The time complexity now will be $O(\log{n})$.

__Code__
```C++
class TimeMap {
public:
    /** Initialize your data structure here. */
    unordered_map<string, vector<pair<int,string>>> mp;
    TimeMap() {
        
    }
    
    void set(string key, string value, int timestamp) {
        if(mp.find(key)!= mp.end()){
            mp[key].push_back({timestamp,value});
        }else{
            vector<pair<int,string>> temp;
            temp.push_back({timestamp,value});
            mp[key] = temp;
        }
    }
    
    string get(string key, int timestamp) {
        if(mp.find(key) == mp.end()){
            return NULL;
        }
        int lo = 0, hi = mp[key].size()-1;
        string ans;
        while(lo<=hi){
            int mid = lo + (hi-lo)/2;
            if(mp[key][mid].first <= timestamp){
                ans = mp[key][mid].second;
                lo = mid+1;
            }else{
                hi = mid-1;
            }
        }
        return ans;
    }
};

/**
 * Your TimeMap object will be instantiated and called as such:
 * TimeMap* obj = new TimeMap();
 * obj->set(key,value,timestamp);
 * string param_2 = obj->get(key,timestamp);
 */
```
__Time Complexity__
- Worst case it will $O(\log{n})$ for each get query, where n is the number of set queries.
- For set query it will be $O(1)$. 

__Dry Run__
```C++
TimeMap kv;   
kv.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1   
kv.set("foo", "bar2", 2);
kv.set("foo", "bar3", 3);
kv.set("foo", "bar4", 4);
kv.get("foo", 3);  
```
|lo|hi|mid|key|mp[key]|Answer|
|:--|:--|:--|:--|:--|:--|
|0|3|1|foo|{{1,bar},{2,bar2},{3,bar3},{4,bar4}}|bar2|
|2|3|2|foo|{{1,bar},{2,bar2},{3,bar3},{4,bar4}}|bar3|
|3|3|3|foo|{{1,bar},{2,bar2},{3,bar3},{4,bar4}}|bar3|
|3|2| ||||

## Question 2 Order of People Heights
You are given the following :

A positive number N
Heights : A list of heights of N persons standing in a queue
Infronts : A list of numbers corresponding to each person (P) that gives the number of persons who are taller than P and standing in front of P
You need to return list of actual order of persons’s height

Consider that heights will be unique

Example

```C++
Input : 
Heights: 5 3 2 6 1 4
InFronts: 0 1 2 0 3 2
Output : 
actual order is: 5 3 2 1 6 4 

Explaination:

So, you can see that for the person with height 5, 
there is no one taller than him who is in front of him, 
and hence Infronts has 0 for him.

For person with height 3, there is 1 person 
( Height : 5 ) in front of him who is taller than him.

You can do similar inference for other people in the list.
```
__Brute Force__
- Go through all the permutations of the heights and for every permutation check if it holds true with Infronts order.
- The time complexity of this approach will be $O(n!* n)$

__Hints__
- If we sort the arrays based on heights, can we do something?
```C++
Heights: 1 2 3 4 5 6
Infront: 3 2 1 2 0 0
```
- We know the largest element will always have $0$ infront value. No matter how many elements we put in front of largest element there will be no larger element than the largest element.
- Lets put largest element at first place.
```C++
Ans: 6
```
- Now for the next largest element we know the position to insert.
```C++
Ans: 5 6
Ans: 5 6 4
Ans: 5 3 6 4
Ans: 5 3 2 6 4
Ans: 5 3 2 1 6 4
```
- Putting a smaller element in front a given element will not affect it. Thus if we move from the largest to smallest we can insert elements at their respective positions.
- Time complexity: $O(n^2)$. As we are shifting all the elements while inserting a given element. This is similar to insertion sort.
- Can we do better than this?
- If we already know which place a given element should go, we would not have to move the elements.
- For this we need to know the number of empty places infront a given position.
- If we fill elements in sorted order of ascending values, at every step we will know what ever is coming next will be greater than the given element.
- We can use segment trees to do the range queries.

__Code__
```C++
void buildST(int s, int e, int index, vector<int> &tree){
    if(s == e){
        tree[index] = 1;
        return;
    }
    int mid = s + (e-s)/2;
    buildST(s, mid, index*2+1, tree);
    buildST(mid+1, e, index*2+2, tree);
    tree[index] = tree[index*2+1] + tree[index*2+2];
}
int getPos(vector<int>&tree, int s, int e, int index, int pos){
    if(s==e){
        tree[index]--;
        return s;
    }
    int mid = s+(e-s)/2;
    if(pos >= tree[index*2+1]){
        tree[index]--;
        return getPos(tree, mid+1, e,index*2+2, pos-tree[index*2+1]);
    }else{
        tree[index]--;
        return getPos(tree, s, mid, index*2+1, pos);
    }
}
vector<int> Solution::order(vector<int> &A, vector<int> &B) {
    int n = A.size();
    vector<int> tree(4*n);
    vector<pair<int,int>> person;
    for(int i = 0; i<n; i++){
        person.push_back({A[i],B[i]});
    }
    sort(person.begin(), person.end());
    buildST(0,n-1,0,tree);
    vector<int> res(n);
    for(auto p: person){
        int pos = getPos(tree,0,n-1,0,p.second);
        //cout << pos << endl;
        res[pos] = p.first;
    }
    return res;
}
```
__Time Complexity__
- For each element we will spend $O(\log{n})$ time to find the proper position. Total time will be $O(n\log{n})$.
- Space Complexity will be $O(n)$ as we will be storing the elements in a segment tree.

__Dry Run__
```C++
Heights: 1 2 3 4 5 6
Infront: 3 2 1 2 0 0
```
|Segment Tree|Height|Infront|Answer|
|:--|:--|:--|:--|
|{0,5,6}{0,2,3}{3,5,3}{0,1,2}{2,2,1}{3,4,2}{5,5,1}{0,0,1}{1,1,1}{}{}{3,3,1}{4,4,1}{}{}|1|3|{, , ,1, , }|
|{0,5,5}{0,2,3}{3,5,2}{0,1,2}{2,2,1}{3,4,1}{5,5,1}{0,0,1}{1,1,1}{}{}{3,3,0}{4,4,1}{}{}|2|2|{ , ,2,1, , }|
|{0,5,4}{0,2,2}{3,5,2}{0,1,2}{2,2,0}{3,4,1}{5,5,1}{0,0,1}{1,1,1}{}{}{3,3,0}{4,4,1}{}{}|3|1|{,3,2,1, , }|
|{0,5,3}{0,2,1}{3,5,2}{0,1,1}{2,2,0}{3,4,1}{5,5,1}{0,0,1}{1,1,0}{}{}{3,3,0}{4,4,1}{}{}|4|2|{,3,2,1, ,4}|
|{0,5,2}{0,2,1}{3,5,1}{0,1,1}{2,2,0}{3,4,1}{5,5,0}{0,0,1}{1,1,0}{}{}{3,3,0}{4,4,1}{}{}|5|0|{5,3,2,1, ,4}|
|{0,5,1}{0,2,0}{3,5,1}{0,1,0}{2,2,0}{3,4,1}{5,5,0}{0,0,0}{1,1,0}{}{}{3,3,0}{4,4,1}{}{}|6|0|{5,3,2,1,6,4}|
|{0,5,0}{0,2,0}{3,5,0}{0,1,0}{2,2,0}{3,4,0}{5,5,0}{0,0,0}{1,1,0}{}{}{3,3,0}{4,4,0}{}{}||||



## Question 3 Merge Overlapping Intervals
Given a collection of intervals, merge all overlapping intervals.

For example:

```C++
Given [1,3],[2,6],[8,10],[15,18],

return [1,6],[8,10],[15,18].
```

Make sure the returned intervals are sorted.

__Brute Force__
- If we iterate over all the intervals and for each interval try to find another interval that is overlapping.
- When we find an overlapping pair we can merge them and again start our iterations.
- Time Complexity: For finding a pair we may take $O(n^2)$ time. Every time we merge a pair we reduce the list by one. There can be at maximum $O(n)$ pairs. So, the overall time complexity will be $O(n^3)$.

__Hint__
- If we sort the intervals based on the starting time, all the overlapping itervals will be adjacent to each other.
- We can then merge the overlapping intervals in linear time.

__Code__
```C++
/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
bool compareIntervals(Interval a, Interval b){
    return a.start < b.start;
}
vector<Interval> Solution::merge(vector<Interval> &A) {
    // Do not write main() function.
    // Do not read input, instead use the arguments to the function.
    // Do not print the output, instead return values as specified
    // Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
    sort(A.begin(), A.end(), compareIntervals);
    vector<Interval> res;
    int cur_start, cur_end;
    bool first = true;
    for(auto a:A){
        if(first){
            first = false;
            cur_start = a.start;
            cur_end = a.end;
            continue;
        }
        if(a.start <= cur_end){
            cur_end = max(a.end,cur_end);
        }else{
            Interval *i = new Interval(cur_start, cur_end);
            res.push_back(*i);
            cur_start = a.start;
            cur_end = a.end;
        }
    }
    Interval* i = new Interval(cur_start, cur_end);
    res.push_back(*i);
    return res;
}
```
__Time Complexity__
- $O(n)$

__Dry Run__
```C++
Array: [1,3],[2,6],[8,10],[15,18]
```
|cur_start|cur_end|cur_interval|Answer|
|:--|:--|:--|:--|
|  | |[1,3]|{}|
|1|3|[2,6]|{}|
|1|6|[8,10]|{{1,6}}|
|8|10|[15,18]|{{1,6},{8,10}}|
|15|18| | {{1,6},{8,10},{15,18}}|


## Question 4 Remove Invalid Parentheses
Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

Note: The input string may contain letters other than the parentheses ( and ).

Example 1:
```C++
Input: "()())()"
Output: ["()()()", "(())()"]
```
Example 2:
```C++
Input: "(a)())()"
Output: ["(a)()()", "(a())()"]
```
Example 3:
```C++
Input: ")("
Output: [""]
```
__Brute Force__
- If we are given a string of parentheses, we can check if it is valid or not. We can use a stack or a counter to do so. This will be an $O(n)$ algorithm.
- We can recursively solve this question by keeping track of number of characters removed.
- We will first remove no character and check the string. Then we will remove one character to iteratively using backtracking. 
- We will check when ever the number of characters to remove becomes zero.
- When we find a valid string we can add it to the result set. As there can be multiple calls to same string.
- Whenever the result array becomes non-empty we will stop increasing the number of characters to be removed and return.

__Hint__
- Questions like this do not have good algorithms.
- I am sharing it so that you understand the importance of Brute force.
- However, you can apply some pruning to considerably improve the actual running time. 
- I have used several ideas to improve time complexity.
  - Count the number of bad parentheses. And you know your minimum.
  - I also counted number of bad open parentheses and bad close parentheses saperately. 
  - I counted number of open and close parentheses so far.

__Code__
```C++
class Solution {
public:
    bool isValid(string s){
        if(s=="")return true;
        int count = 0;
        for(auto c: s){
            if(c == '('){
                count++;
            }else if (c== ')'){
                if(count <= 0) return false;
                count--;
            }
        }
        if(count!=0) return false;
        return true;
    }
    void makevalid(string s, int open_to_remove, int close_to_remove, int open_count, int close_count, int from, unordered_set<string> &res){
        if(close_count > open_count) return;
        int toDelete = open_to_remove + close_to_remove;
        if(toDelete > s.size() - from){
            return;
        }
        if(toDelete == 0 && isValid(s)){
            res.insert(s);
        }else{
            for(int i = from; i<=s.size()-toDelete; i++){
                if(s[i] == ')' && close_to_remove>0){
                    string newS = s.substr(0,i);
                    newS += (i+1<s.size())? s.substr(i+1, s.size()-i-1):"";
                    makevalid(newS,open_to_remove, close_to_remove-1, open_count, close_count, i, res);
                }
                if(s[i] == '(' && open_to_remove>0){
                    string newS = s.substr(0,i);
                    newS += (i+1<s.size())? s.substr(i+1, s.size()-i-1):"";
                    makevalid(newS,open_to_remove-1, close_to_remove , open_count, close_count, i, res);
                }
                if(s[i] == ')') close_count++;
                else if(s[i] == '(') open_count++;
            }
        }
    }
    int findMin(string s, int &open_to_remove, int &close_to_remove){
        int ans = 0, count =0;
        for(auto c:s){
            if(c==')'){
                count--;
            }else if(c=='('){
                count++;
            }
            if(count < 0){
                ans++;
                count=0;
            }
        }
        open_to_remove = count;
        close_to_remove = ans;
        return ans+count;
    }
    vector<string> removeInvalidParentheses(string s) {
        unordered_set<string> res;
        int open_to_remove, close_to_remove;
        findMin(s, open_to_remove, close_to_remove);
        makevalid(s,open_to_remove, close_to_remove,0,0,0,res);
        vector<string> res2;
        for(auto s: res){
            res2.push_back(s);
        }
        return res2;
    }
};
```
__Time Complexity__
- $O(2^n)$ For every i, every element will either be removed or included.

__Dry Run__
```C++
s = "())"
```
|Main Call|Children Calls|res|
|:--|:--|:--|
|makevalid("())",1,0)|makevalid("))",0,0), makevalid("()",0,1), makevalid("()",0,2)| |
|makevalid("))",0,0)| Invalid | |
|makevalid("()",0,1)| Valid| {"()"}|
|makevalid("()",0,2)| Valid| {"()"}|