# 1. Two Sum (opens new window)

# Hashtable

Store the value-index pair of each element in map. For value x of nums, check if target - x also in the map and get the corresponding index from map.

vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); ++i){
            if (map.find(target - nums[i]) != map.end())
                return {map[target - nums[i]], i};
            map[nums[i]] = i;
        }
        return {};
    }
public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2];
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; ++i){
            if (map.containsKey(target - nums[i])){
                result[0] = i;
                result[1] = map.get(target - nums[i]);
                return result;
            }
            map.put(nums[i], i);
        }
        return result;
    }
def twoSum(self, A: List[int], t: int) -> List[int]:
        pos = collections.defaultdict(int)
        for i, a in enumerate(A):
            if t - a in pos:
                return [pos[t - a], i]
            pos[a] = i


# 146. LRU Cache (opens new window)

Double linked list

class LRUCache {
    class Node{
        int key;
        int val;
        Node next;
        Node prev;
    }
    
    private void move(Node node){
        Node pre = node.prev;
        Node nxt = node.next;
        pre.next = nxt;
        nxt.prev = pre;
        
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }
    private Map<Integer, Node> map = new HashMap<>();
    private int c;
    private int capacity;
    private Node head, tail;
    
    public LRUCache(int capacity) {
        this.c = 0;
        this.capacity = capacity;
        head = new Node();
        tail = new Node();
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        Node node = map.get(key);
        if (node == null) return -1;
        else{
            move(node);
            return node.val;
        }
    }
    
    public void put(int key, int value) {
        Node node = map.get(key);
        if (node != null){
            node.val = value;
            move(node);
        }
        else{
            Node newnode = new Node();
            newnode.key = key;
            newnode.val = value;
            map.put(key, newnode);
            if (c == capacity){
                Node cur = tail.prev;
                map.remove(cur.key);
                tail.prev = tail.prev.prev;
                tail.prev.next = tail;
                c--;
            }
            newnode.prev = head;
            newnode.next = head.next;
            head.next.prev = newnode;
            head.next = newnode;
            c++;
        }
    }
}
class Node:
    def __init__(self, key = None, val = None):
        self.key = key
        self.val = val
        self.prev = None
        self.next = None

class LRUCache:

    def __init__(self, capacity: int):
        self.c = capacity
        self.map = {}
        self.head = Node()
        self.tail = Node()
        self.head.next = self.tail
        self.tail.prev = self.head
        
    def move_to_top(self, key):
        node = self.map[key]
        node.prev.next = node.next
        node.next.prev = node.prev
        
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev = node
        self.head.next = node

    def get(self, key: int) -> int:
        if key in self.map:
            self.move_to_top(key)
        res = self.map.get(key, -1)
        if res == -1: 
            return res
        else: 
            return res.val

    def put(self, key: int, value: int) -> None:
        if key in self.map:
            self.map[key].val = value
            self.move_to_top(key)
        else:
            if len(self.map) == self.c:
                self.map.pop(self.tail.prev.key)
                self.tail.prev = self.tail.prev.prev
                self.tail.prev.next = self.tail
            new = Node(key, value)
            self.map[key] = new
            
            new.prev = self.head
            new.next = self.head.next
            self.head.next.prev = new
            self.head.next = new


# 1249. Minimum Remove to Make Valid Parentheses (opens new window)

Two pass, remove the extra ')' from left to right, and extra '(' from right to left.

private StringBuilder remove(CharSequence string, char open, char close) {
        StringBuilder sb = new StringBuilder();
        int curr = 0;
        for (int i = 0; i < string.length(); ++i) {
            char ch = string.charAt(i);
            if (ch == open) { 
                curr++;
            } if (ch == close) {
                if (curr == 0) continue;
                curr--;
            }
            sb.append(ch);
        }
        return sb;
    }
    
    public String minRemoveToMakeValid(String s) {
        StringBuilder result = remove(s, '(', ')');
        result = remove(result.reverse(), ')', '(');
        return result.reverse().toString();
    }
def minRemoveToMakeValid(self, s: str) -> str:
        def remove(s, op, cl):
            ans, curr = "", 0
            for ch in s:
                if ch == op:
                    curr += 1
                if ch == cl:
                    if curr == 0:
                        continue
                    curr -= 1
                ans += ch
            return ans
        res = remove(s, '(', ')')
        return remove(res[::-1], ')', '(')[::-1]    


# 56. Merge Intervals (opens new window)

Greedy. We sort intervals by the starting position. Then traverse the sorted intervals, if the current interval [x, y] doesn't overlap with the previous ones, meaning there exist a gap before x.

vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end());
        vector<vector<int>> ans;
        for (auto interval : intervals) {
            if (ans.empty() || ans.back()[1] < interval[0]) 
                ans.push_back(interval);
            else 
                ans.back()[1] = max(ans.back()[1], interval[1]);
        }
        return ans;
    }
public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
        LinkedList<int[]> ans = new LinkedList<>();
        for (int[] interval : intervals) {
            if (ans.isEmpty() || ans.getLast()[1] < interval[0])
                ans.add(interval);
            else
                ans.getLast()[1] = Math.max(ans.getLast()[1], interval[1]);
        }
        return ans.toArray(new int[ans.size()][]);
    }
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key=lambda x: x[0])
        res=[]
        for i in intervals:
            if res and res[-1][1]>=i[0]:
                res[-1][1]=max(res[-1][1],i[1])
            else:
                res.append(i)
        return res


# 200. Number of Islands (opens new window)

BFS over grids, when we reach an unvisited land, find all the lands of the same island.

int numIslands(vector<vector<char>>& A) {
        int m = A.size(), n = A[0].size(), ans = 0;
        vector<vector<int>> dirs = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
        deque<vector<int>> deq;
        vector<int> cur;
        
        for (int i = 0; i < m; ++i) 
            for (int j = 0; j < n; ++j)
                if (A[i][j] == '1') {
                    A[i][j] = 'v';
                    deq.clear();
                    deq.push_back({i, j});
                    while (!deq.empty()) {
                        cur = deq.front();
                        deq.pop_front();
                        for (auto dir : dirs) {
                            int nx = cur[0] + dir[0], ny = cur[1] + dir[1];
                            if (0 <= nx && nx < m && 0 <= ny && ny < n && A[nx][ny] == '1') {
                                A[nx][ny] = 'v';
                                deq.push_back({nx, ny});
                            }   
                        }
                    }
                    ans++;
                }
        return ans;
    }
def numIslands(self, grid: List[List[str]]) -> int:
        m, n = len(grid), len(grid[0])
        index = 0
        dirs = ((1, 0), (0, 1), (-1, 0), (0, -1))
        dq = collections.deque()
        for i in range(m):
            for j in range(n):
                if grid[i][j] == "1":
                    grid[i][j] = "v"
                    dq.append((i, j))
                    while dq:
                        ox, oy = dq.popleft()
                        for x, y in dirs:
                            nx, ny = x + ox, y + oy
                            if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == "1":
                                dq.append((nx, ny))
                                grid[nx][ny] = "v"
                    index += 1

        return index


# 680. Valid Palindrome II (opens new window)

def validPalindrome(self, s: str) -> bool:
        l, r = 0, len(s) - 1
        while l < r:
            if s[l] != s[r]:
                a, b = s[l + 1 : r + 1], s[l : r]
                return l + 1 == r or a == a[::-1] or b == b[::-1]
            l += 1
            r -= 1
        return True


# 314. Binary Tree Vertical Order Traversal (opens new window)

DFS over tree and save nodes by horizontal and vertical indexes.

def verticalOrder(self, root: TreeNode) -> List[List[int]]:
        d = collections.defaultdict(list)
        def dfs(root, col, dep):
            if not root:
                return []
            d[col].append([dep, root.val])
            if root.left:
                dfs(root.left, col - 1, dep + 1)
            if root.right:
                dfs(root.right, col + 1, dep + 1)
        
        dfs(root, 0, 0)

        ans = []
        for i in sorted(d.keys()):
            cur = sorted(d[i], key = lambda x : x[0])
            ans.append(list(x[1] for x in cur))
        
        return ans

BFS

def verticalOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        d = collections.defaultdict(list)
        dq = collections.deque()
        dq.append((root, 0, 0))
        while dq:
            curn, curx, cury = dq.popleft()
            d[curx].append([cury, curn.val])
            if curn.left:
                dq.append([curn.left, curx - 1, cury - 1])
            if curn.right:
                dq.append([curn.right, curx + 1, cury - 1])   

        ans = []
        for i in sorted(d.keys()):
            cur = sorted(d[i], key = lambda x : -x[0])
            ans.append(list(x[1] for x in cur))
        
        return ans