Wednesday, March 7, 2018

LeetCode 39 40 216 377 Combination Sum I, II, III, IV

LeetCode 39 40 216 377

Yifeng Zeng

Description

Idea Report

For LC 39, we are looking for any combination that has the sum of the target. So this becomes a problem that is very similar like subset or permutation problem. So we can do a search. For example we have [2,3,6,7] and target is 7. We can add 2 in the result and looking for 7 - 2 = 5 recursively in the [2,3,6,7] input array. And when we find out that if the target decreases to 0, we found one of the result. This becomes a very standard DFS search problem.
Code 1a
class Solution {
    // 1a Combination Sum, for loop
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        helper(candidates, target, res, new ArrayList<>(), 0);
        return res;
    }

    private void helper(int[] candidates, int target, List<List<Integer>> res,
                        List<Integer> path, int index) {
        if (target <= 0 || index >= candidates.length) {
            if (target == 0) {
                res.add(new ArrayList<>(path));
            }
            return;
        }

        for (int i = index; i < candidates.length; i++) {
            path.add(candidates[i]);
            helper(candidates, target - candidates[i], res, path, i);
            path.remove(path.size() - 1);
        }
    }
}
Looking at the input [2,3,6,7], target 7. We can choose add one element or not add one element. If we add one element 2, then we are looking for target 7 - 2 = 5 in sub input [2,3,6,7]. If we don't add element 2, then we are looing for target 7 in sub input [3,6,7]. Until we are looking for target 0, then the previous elements we have already added are the results that we want.
Code 1b
class Solution {
  // 1b Combination Sum, choose/not choose
  public List<List<Integer>> combinationSum(int[] candidates, int target) {
      List<List<Integer>> res = new ArrayList<>();
      search(target, 0, new ArrayList<>(), res, candidates);
      return res;
  }

  private void search(int target, int startIndex, List<Integer> path,
                      List<List<Integer>> res, int[] candidates) {
      if (target < 0) {
          return;
      }

      if (target == 0) {
          res.add(path);
          return;
      }

      if (startIndex >= candidates.length) {
          return;
      }

      List<Integer> firstPath = new ArrayList<>(path);
      firstPath.add(candidates[startIndex]);
      search(target - candidates[startIndex],
             startIndex, firstPath, res, candidates);
      search(target, startIndex + 1, path, res, candidates);
  }
}
For LC 40, each element should only be used once. Then we do the recursion, we need to start to search from the next index, not the current index. And also, we need to remove the duplex by check is the current element we want to add is the same value with the previous value, but the previous element is not in the result. For example, i we search target 8 in [1,2a,2b,3,4]. If we have a result [1,2a, 4], then we can't use [1, 2b, 4] because that is a duplication. So during the search, when we want to add [2b], we have to check if [2a] is in the result [1, 2a] to add [2b], if it is not we can't add it, otherwise will have both [1,2a] and [1,2b] and that would cause duplication.
Code 2a
class Solution {
    // 2a Combination Sum II, for loop
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(candidates);
        helper(candidates, target, res, new ArrayList<>(), 0);
        return res;
    }

    private void helper(int[] candidates, int target, List<List<Integer>> res,
                        List<Integer> path, int index) {
        if (target <= 0 || index >= candidates.length) {
            if (target == 0) {
                res.add(new ArrayList<>(path));
            }
            return;
        }

        for (int i = index; i < candidates.length; i++) {
            if (i > index && candidates[i] == candidates[i-1]) {
                continue;
            }
            if (target - candidates[i] < 0) {
                break;
            }
            path.add(candidates[i]);
            helper(candidates, target - candidates[i], res, path, i + 1);
            path.remove(path.size() - 1);
        }
    }
}
Based on choose/not choose method from Code 1b, if we choose to add current element, the next search index is startIndex + 1. If we do not choose to add current element, the next search index is the next element that has a different value of the current element. Based on example [1,1,2,5,6,7,10], target = 8, we have the original (target, pos) pair (8,0). If we choose to add first 1, then the next recursion is (7,1). If we do not choose to add first 1, then we can't the second 1 because we do not add any 1 at all, so the next recursion is (8,2) (This is why I answered (8,2) in the class).
Code 2b
class Solution {
  // 2b Combination Sum II, choose/not choose
  public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<List<Integer>> res = new ArrayList<>();
        search(target, 0, new ArrayList<>(), res, candidates);
        return res;
    }

    private void search(int target, int startIndex, List<Integer> path,
                        List<List<Integer>> res, int[] candidates) {
        if (target < 0) {
            return;
        }
        if (target == 0) {
            res.add(new ArrayList<>(path));
            return;
        }
        if (startIndex >= candidates.length) {
            return;
        }

        List<Integer> firstPath = new ArrayList<>(path);
        firstPath.add(candidates[startIndex]);
        search(target - candidates[startIndex],
               startIndex + 1, firstPath, res, candidates);
        while (startIndex + 1 < candidates.length
               && candidates[startIndex] == candidates[startIndex + 1]) {
            startIndex++;
        }
        search(target, startIndex + 1, path, res, candidates);
    }
}
For LC 216, similarly to code 2a, we have a for loop to add a number x from 1 to 9 into the result, and recursively find the (target - x) until the target == 0. Because we will have to choose k and only k numbers, so if the result's (path's) length is k and target is 0, we add it to the final result. If there are more then k numbers in the path, or the target is less than 0, we won't find any valid answer, then we just return the recursion.
Code 3a
class Solution {
    // 3a Combination Sum III, for loop
    public List<List<Integer>> combinationSum3(int k, int target) {
        List<List<Integer>> res = new ArrayList<>();
        helper(target, res, new ArrayList<>(), k, 1);
        return res;
    }

    private void helper(int target, List<List<Integer>> res,
                        List<Integer> path, int k, int value) {
        if (target == 0 && path.size() == k) {
            res.add(new ArrayList<>(path));
            return;
        }
        if (target < 0 || path.size() > k) {
            return;
        }

        for (int v = value; v <= 9; v++) {
            if (target - v < 0) {
                break;
            }
            path.add(v);
            helper(target - v, res, path, k, v + 1);
            path.remove(path.size() - 1);
        }
    }
}
For LC 216, similarly to code 2b, for current value we have 2 choices. One is to add it, the then next recursion level is to search target - value, the next value shoulde be (value + 1). The other choise is not add it, then next recursion level is still to search target, and the next value to add should also be (value + 1). The exit condition is the same as metioned in 3a, plus if the current value is larger than 9, we return, cause we only choose from 1 to 9.
Code 3b
class Solution {
    // 3b Combination Sum III, choose/not choose
    public List<List<Integer>> combinationSum3(int k, int target) {
        List<List<Integer>> res = new ArrayList<>();
        search(target, 1, k, new ArrayList<>(), res);
        return res;
    }

    private void search(int target, int value, int k,
                        List<Integer> path, List<List<Integer>> res) {
        if (target == 0 && path.size() == k) {
            res.add(new ArrayList<>(path));
            return;
        }
        if (target < 0 || path.size() > k || value > 9) {
            return;
        }

        // choose current value
        path.add(value);
        search(target - value, value + 1, k, path, res);
        path.remove(path.size() - 1);
        // not choose current value
        search(target, value + 1, k, path, res);
    }
}
For LC 377, the primitive idea is to list all the possible combinations very similar to the permutation but same value can be chose many times. This approach list all the possible combinations and got time limit exceeded.
Code 4a
class Solution {
    // Time Limit Exceeded
    // 4a Combination Sum IV, for loop
    public int combinationSum4(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        helper(candidates, target, res, new ArrayList<>());
        return res.size();
    }

    private void helper(int[] candidates, int target, List<List<Integer>> res,
                        List<Integer> path) {
        if (target <= 0) {
            if (target == 0) {
                res.add(new ArrayList<>(path));
            }
            return;
        }

        for (int i = 0; i < candidates.length; i++) {
            if (target - candidates[i] < 0) {
                break;
            }
            path.add(candidates[i]);
            helper(candidates, target - candidates[i], res, path);
            path.remove(path.size() - 1);
        }
    }
}
We are actually just returning how many different combinations are there but not care about the actual combinations. So we can just do combinationSum 1 and find the number of combinations of each result in combinationSum 1, this still got time limit exceeded.
Code 4b
class Solution {
    // Time Limit Exceeded
    // 4b Combination Sum IV, choose/not choose
    public int combinationSum4(int[] candidates, int target) {
        int[] res = new int[1];
        search(target, 0, new ArrayList<>(), res, candidates);
        return res[0];
    }

    private void search(int target, int startIndex, List<Integer> path,
                      int[] res, int[] candidates) {
        if (target < 0) {
          return;
        }
        if (target == 0) {
            res[0] += findN(path);
            return;
        }
        if (startIndex >= candidates.length) {
          return;
        }

        List<Integer> firstPath = new ArrayList<>(path);
        firstPath.add(candidates[startIndex]);
        search(target - candidates[startIndex], startIndex, firstPath, res,
               candidates);
        search(target, startIndex + 1, path, res, candidates);
    }

    private int findN(List<Integer> path) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i : path) {
            map.put(i, map.getOrDefault(i, 0) + 1);
        }

        int n = path.size();
        int res = 1;
        for (int key : map.keySet()) {
            int value = map.get(key);
            res *= C(n, value);
            n = n - value;
            if (n == 0) {
                break;
            }
        }

        return res;
    }

    private int C(int n, int r) {
        // C(n, r) = n! / r! / (n-r)!
        long res = 1;
        for (long x = r + 1; x <= n; x++) {
            res *= x;
        }
        for (long x = n - r; x > 1; x--) {
            res /= x;
        }
        return (int) res;
    }
}
Define comb[n] as the number of combinations to get sum of n. So taking the example of[1,2,3], target = 4, we are looking for comb[4]. We consider the last step that we get a sum of 4, we have 3 different situations:
  • The last number we add is [1], so that is comb[3] of different answers, each add 1. So there are comb[3] different answers add 1 to get comb[4].
  • Similarly, we have comb[4-2] = comb[2] of different answers, each add 2 to get sum of 4.
  • Similarly, we have comb[4-3] = comb[1].
So
  • comb[4] = comb[1] + comb[2] + comb[3]; (for loop of the candidates before 4)
  • comb[3] = comb[1] + comb[2]; (for loop of the candidates before 3)
  • comb[2] = comb[1]; (for loop of the candidates before 2)
The base case is that comb[0] should be 1, because for any value (say 6) in the candidates, it will be always have one sum which is 6 itself, so comb[6] = comb[0] (then add the number 6).
Code DP
class Solution {
    // 4b Combination Sum IV, DP, AC
    public int combinationSum4(int[] candidates, int target) {
        int[] comb = new int[target + 1];
        comb[0] = 1;
        Arrays.sort(candidates);
        for (int i = 1; i <= target; i++) {
            for (int j = 0; j < candidates.length; j++) {
                if (candidates[j] >= comb.length) {
                    break;
                }
                if (i - candidates[j] < 0) {
                    continue;
                }
                comb[i] += comb[i - candidates[j]];
            }
        }
        System.out.println(Arrays.toString(comb));
        return comb[target];
    }
}

Summary

  • Use for loop or choose/not choose an element to divid it into sub problems to do the DFS.
  • Use the following code to early stop the search to speed up:
    • if (target - candidates[i] < 0) {break;}
  • DP would consider the last step and from last to begnning, and consider the first base case.

Combination Sum IV Follow up

The primitive DP idea is to draw the table
0 amount1234
0 coin10000
111111
211235
311247
We define int[][] f, f[i][j] means there are f[i][j] possible combinations that add up to the amount j using the first i coins in the candidates. The initialization is let all f[][0] = 1 because we always have 1 way to make the amount of 0. For each f[i][j], we need to check f[i][j - coins[0]], f[i][j - coins[1]], f[i][j - coins[2]], f[i][j - coins[3]], ..., f[i][j - coins[i]] and sum them together. Because for f[i][j], we have f[i][j - coins[i]] ways to make f[i][j] (based on add coins[i] amount to j - coins[i] amount).
class Solution {
    public int combinationSum4(int[] candidates, int target) {
        int[][] f = new int[candidates.length + 1][target + 1];
        for (int i = 1; i <= candidates.length; i++) {
            f[i][0] = 1;
            for (int j = 1; j <= target; j++) {
                for (int k = 0; k < i; k++) {
                    int coin = candidates[k];
                    if (j - coin >= 0) {
                        f[i][j] += f[i][j - coin];
                    }
                }
            }
        }
        for (int[] row : f) {
            System.out.println(Arrays.toString(row));
        }
        return f[candidates.length][target];
    }
}
Because we don't really use the information from previous rows, so we can juse use a 1-D array.
class Solution {
    // DP optimize space, AC
    public int combinationSum4(int[] candidates, int target) {
        int[] f = new int[target + 1];
        f[0] = 1;
            for (int j = 1; j <= target; j++) {
                for (int k = 0; k < candidates.length; k++) {
                    int coin = candidates[k];
                    if (j - coin >= 0) {
                        f[j] += f[j - coin];
                    }
                }
            }

        System.out.println(Arrays.toString(f));

        return f[target];
    }
}
After clearing up
class Solution {
    // DP optimization, AC
    public int combinationSum4(int[] candidates, int target) {
        int[] f = new int[target + 1];
        f[0] = 1;
        Arrays.sort(candidates);
        for (int j = 1; j <= target; j++) {
            for (int coin : candidates) {
                if (j - coin < 0) {
                    break;
                }
                f[j] += f[j - coin];
            }
        }
        return f[target];
    }
}

Sunday, March 4, 2018

LeetCode 529 Minesweeper

# **LeetCode 529**
---
https://leetcode.com/problems/minesweeper/description/

Yifeng Zeng

# Description
---
[529. Minesweeper](https://leetcode.com/problems/minesweeper/description/)


# Idea Report
---

Given a board matrix and a clicking point we need to update this board by some rules:

- 1. If the click point is an unrevealed mine 'M', we change it to revealed mine 'X' and no further step will be needed.
- 2. If the click point is an already revealed square no matter it's 'M'/'B'/'X'/'Digit', we just return the same board because it is a click that doesn't do anything.
- 3. If the click point is an unrevealed empty square 'E', we need to do two different things depends on what that square should be.
  - 3.1. If it should be a digit, we change it form 'E' to the 'Digit'
  - 3.2. If it should be a revealed blank square 'B', we change it to 'B' and do a search to find all the neighboring 'B'. We stop the searching if we find an already revealed square. Or we stop if we find a square that should be a 'Digit', and also we need to change that sqaure to the 'Digit'.

We can use both BFS or DFS to do the search.

Code
```java
class Solution {
    //AC BFS
    final int[] dx = {0,  0, 1, -1, 1,  1, -1, -1};
    final int[] dy = {1, -1, 0,  0, 1, -1,  1, -1};

    public char[][] updateBoard(char[][] board, int[] click) {
        final int rows = board.length;
        final int cols = board[0].length;

        int x = click[0];
        int y = click[1];
        if (board[x][y] == 'M') {
            board[x][y] = 'X';
            return board;
        }
        if (board[x][y] != 'E') {
            return board;
        }

        int count = check(board, click[0], click[1]);
        if (count != 0) {
            board[x][y] = (char) (count + '0');
            return board;
        }

        // BFS
        Deque<int[]> q = new LinkedList<>();
        q.offer(click);
        board[x][y] = 'B';

        while (!q.isEmpty()) {
            int[] cur = q.poll();
            for (int i = 0; i < dx.length; i++) {
                int r = cur[0] + dx[i];
                int c = cur[1] + dy[i];
                if (!isValid(board, r, c) || board[r][c] != 'E') {
                    continue;
                }
                count = check(board, r, c);
                if (count == 0) {
                    q.offer(new int[]{r, c});
                    board[r][c] = 'B';
                } else {
                    board[r][c] = (char) (count + '0');
                }
            }
        }

        return board;
    }


    private int check(char[][] board, int row, int col) {
        int count = 0;
        for (int i = 0; i < dx.length; i++) {
            int r = row + dx[i];
            int c = col + dy[i];
            if (isValid(board, r, c) && board[r][c] == 'M') {
                count++;
            }
        }
        return count;
    }


    private boolean isValid(char[][] board, int r, int c) {
        if (0 <= r && r < board.length && 0 <= c && c < board[0].length) {
            return true;
        }
        return false;
    }
}
```

Code
```java
class Solution {

    // AC DFS
    final int[] dx = {0,  0, 1, -1, 1,  1, -1, -1};
    final int[] dy = {1, -1, 0,  0, 1, -1,  1, -1};

    public char[][] updateBoard(char[][] board, int[] click) {
        dfsHelper(board, click);
        return board;
    }

    private void dfsHelper(char[][] board, int[] click) {
        int x = click[0];
        int y = click[1];
        if (!isValid(board, x, y)) {
            return;
        }

        if (board[x][y] == 'M') {
            board[x][y] = 'X';
            return;
        }
        if (board[x][y] != 'E') {
            return;
        }
        int count = check(board, click[0], click[1]);
        if (count != 0) {
            board[x][y] = (char) (count + '0');
            return;
        }

        board[x][y] = 'B';
        for (int i = 0; i < dx.length; i++) {
            click[0] = x + dx[i];
            click[1] = y + dy[i];
            dfsHelper(board, click);
        }
    }


    private int check(char[][] board, int row, int col) {
        int count = 0;
        for (int i = 0; i < dx.length; i++) {
            int r = row + dx[i];
            int c = col + dy[i];
            if (isValid(board, r, c) && board[r][c] == 'M') {
                count++;
            }
        }
        return count;
    }


    private boolean isValid(char[][] board, int r, int c) {
        if (0 <= r && r < board.length && 0 <= c && c < board[0].length) {
            return true;
        }
        return false;
    }
}
```

# Summary
---
- Use int[] dx, int[] dy to simplify the search direction.
- Analysing the steps first then the coding part is just following the steps.
- Try to modulize the code, like isValid() etc.

LeetCode 301 Remove Invalid Parentheses

# **LeetCode 301**
---
https://leetcode.com/problems/remove-invalid-parentheses/description/

Yifeng Zeng

# Description
---
[301. Remove Invalid Parentheses](https://leetcode.com/problems/remove-invalid-parentheses/description/)


# Idea Report
---

The basic idea is to check if current string s is valid. If it is, add to the output. If it is not, remove any one character and see if the substring is valid or not. And treat substring as input s and redo the above process. We can do both BFS or DFS. To save time, we can use a hash table to store any string that has already been searched. So for any substring that is in the hash table, we do not need to search again.

Code
```java
class Solution {
    // BFS AC
    public List<String> removeInvalidParentheses(String s) {
        List<String> res = new ArrayList<>();
        if (s == null) {
            return res;
        }

        // BFS
        Deque<String> q = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        q.offer(s);
        visited.add(s);

        while (!q.isEmpty()) {
            int size = q.size();
            for (int j = 0; j < size; j++) {
                String cur = q.poll();
                if (isValid(cur)) {
                    res.add(cur);
                }

                for (int i = 0; i < cur.length() && res.size() == 0; i++) {
                    if (cur.charAt(i) != '(' && cur.charAt(i) != ')') {
                        continue;
                    }
                    String substring = cur.substring(0, i)
                                       + cur.substring(i + 1);
                    if (!visited.contains(substring)) {
                        q.offer(substring);
                        visited.add(substring);
                    }
                }
            }
        }

        return res;
    }

    private boolean isValid(String s) {
        int count = 0;
        for (char ch : s.toCharArray()) {
            if (ch == '(') {
                count++;
            } else if (ch == ')') {
                count--;
            }
            if (count < 0) {
                return false;
            }
        }
        return count == 0;
    }
}
```

Code
```java
class Solution {
    // DFS AC
    public List<String> removeInvalidParentheses(String s) {
        List<String> res = new ArrayList<>();
        Set<String> visited = new HashSet<>();
        helper(res, s, visited);
        return res;
    }

    private void helper(List<String> res, String s, Set<String> visited) {
        if (res.size() != 0 && s.length() < res.get(0).length()) {
            return;
        }

        if ((res.size() == 0 || s.length() >= res.get(0).length())
            && isValid(s)) {
            if (res.size() != 0 && s.length() > res.get(0).length()) {
                res.clear();
            }
            res.add(s);
            return;
        }

        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch != '(' && ch != ')') {
                continue;
            }
            String substring = s.substring(0, i) + s.substring(i + 1);
            if (!visited.contains(substring)) {
                visited.add(substring);
                helper(res, substring, visited);
            }
        }
    }

    private boolean isValid(String s) {
        int count = 0;
        for (char ch : s.toCharArray()) {
            if (ch == '(') {
                count++;
            } else if (ch == ')') {
                count--;
            }
            if (count < 0) {
                return false;
            }
        }
        return count == 0;
    }
}
```

# Summary
---
- Try modulize the code using isValid().
- Use a visited hash table to prune the search.

LeetCode 23 Merge k Sorted Lists

# **LeetCode 23**
---
https://leetcode.com/problems/merge-k-sorted-lists/description/

Yifeng Zeng

# Description
---
[23. Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/description/)


# Idea Report
---

We want to merge k already sorted lists ListNode[] into one single linked list. We need to find the smallest ListNode in these k lists one at a time, add it to the output. Also we need to remove the smallest from the input and then again find the smallest ListNode from the updated input. The primitive idea is to loop the k nodes and find the smallest one, the time complexity is O(nk*k), where n is the average number of nodes for each linked list because for each node we need to loop k nodes to find the smallest.

To speed up, we are actually looking for the smallest node from k nodes, then we can put the k nodes in a container and pick the smallest one from this container. The minHeap can find the smallest element from k elements so we can use a minHeap instead of looping through the k nodes. Each time we poll out the smallest node, add it to output, and if it's .next node is not null, we add .next node back into the minHeap. This way the time complexity is O(nklogk).

Code
```java
public class Solution {
  public ListNode mergeKLists(ListNode[] lists) {
      if (lists == null || lists.length == 0) {
          return null;
      }

      Queue<ListNode> pq = new PriorityQueue<>((a, b) -> (a.val - b.val));
      for (ListNode list : lists) {
          if (list != null) {
              pq.offer(list);
          }
      }

      ListNode dummy = new ListNode(0);
      ListNode head = dummy;
      while (!pq.isEmpty()) {
          ListNode cur = pq.poll();
          head.next = cur;
          head = head.next;
          if (cur.next != null) {
              pq.offer(cur.next);
          }
      }

      return dummy.next;
  }
}
```

Another faster way is to merge these k lists pair by pair. Suppose if we have 4 lists A,B,C,D, we select 2 lists A,B to merge them together into E, and we merge the next 2 lists C,D to merge them together into F. And then we merge E and F to the final result. In this way, we reduce the input size by half, to the time complexity is O(nlogk), where n is the average length of each list because to merge 2 lists use O(n) time, and we need to merge logk times.

Code
```java
class Solution {

    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }

        return mergeKLists(lists, 0, lists.length - 1);
    }

    private ListNode mergeKLists(ListNode[] lists, int start, int end) {
        if (start == end) {
            return lists[start];
        }

        int mid = (end - start) / 2 + start;
        ListNode left = mergeKLists(lists, start, mid);
        ListNode right = mergeKLists(lists, mid + 1, end);
        return merge(left, right);
    }

    private ListNode merge(ListNode left, ListNode right) {
        ListNode dummy = new ListNode(0);
        ListNode head = dummy;
        while (left != null && right != null) {
            if (left.val < right.val) {
                head.next = left;
                left = left.next;
            } else {
                head.next = right;
                right = right.next;
            }
            head = head.next;
        }
        if (left != null) {
            head.next = left;
        }
        if (right != null) {
            head.next = right;
        }
        return dummy.next;
    }
}
```

# Summary
---
- Looking for smallest/largest one in k elements, we can use a heap.
- For a large input with a parallel task, we can consider divid input into two halves to solve the two sub problem.

Wednesday, February 28, 2018

LeetCode 199 Binary Tree Right Side View

#**LeetCode 199**
---
https://leetcode.com/problems/binary-tree-right-side-view/description/

Yifeng Zeng

#Description
---
[199. Binary Tree Right Side View](https://leetcode.com/problems/binary-tree-right-side-view/description/)


#Idea Report
---

If I'm standing on the right side of a binary tree, I would see the right-most node of each level of the tree. So this becomes a problem to find the right-most node in each level of the tree. We can do a root-right-left preorder traversal and for each level we just record the first node that has been traversed. This can be achieved both using DFS or BFS.


Code
```java
public class Solution {
    // DFS
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        dfsHelper(res, root, 0);
        return res;
    }

    private void dfsHelper(List<Integer> res, TreeNode root, int level) {
        if (root == null) {
            return;
        }

        if (res.size() == level) {
            res.add(root.val);
        }

        dfsHelper(res, root.right, level + 1);
        dfsHelper(res, root.left, level + 1);
    }
}
```

Code
```java
public class Solution {
    // BFS
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }

        Deque<TreeNode> q = new LinkedList<>();
        q.offer(root);
        int level = 0;

        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                TreeNode cur = q.poll();
                if (res.size() == level) {
                    res.add(cur.val);
                }
                if (cur.right != null) {
                    q.offer(cur.right);
                }
                if (cur.left != null) {
                    q.offer(cur.left);
                }
            }
            level++;
        }

        return res;
    }
}
```

#Summary
---
- Standard DFS/BFS operation in binary tree.

LeetCode 200 Number of Islands

#**LeetCode 200**
---
https://leetcode.com/problems/number-of-islands/description/

Yifeng Zeng

#Description
---
[200. Number of Islands](https://leetcode.com/problems/number-of-islands/description/)


#Idea Report
---

An island is all the connected points in the matrix. So we can treat a point as a node in a undrected graph, each pair of nodes next to each other has an edge connect to them. In this case, we can just traverse the whole matrix. Each time we find a point that is a part of island ('1'), we do a search from that point, and mark all the points to a special character so that in the next iterations we would skip them in order to get the number of the different islands. We can do both BFS or DFS.

When writing the code, we can ask if we need to maintain the original input, it we need, we can assign traversed island points to a special character and recover it before return.

Code
```java
public class Solution {

  // BFS
  public int numIslands(char[][] grid) {
      if (grid == null || grid.length == 0 || grid[0].length == 0) {
          return 0;
      }

      int rows = grid.length;
      int cols = grid[0].length;
      int count = 0;
      for (int r = 0; r < rows; r++) {
          for (int c = 0; c < cols; c++) {
              if (grid[r][c] == '1') {
                  bfsHelper(grid, r, c);
                  count++;
              }
          }
      }
      return count;
  }

  private void bfsHelper(char[][] grid, int row, int col) {
      int[] dx = {0, 0, 1, -1};
      int[] dy = {1, -1, 0, 0};
      Deque<int[]> q = new LinkedList<>();
      q.offer(new int[]{row, col});
      grid[row][col] = '0';

      while (!q.isEmpty()) {
          int[] cur = q.poll();
          for (int i = 0; i < dx.length; i++) {
              int r = cur[0] + dx[i];
              int c = cur[1] + dy[i];
              if (isValid(grid, r, c)) {
                  q.offer(new int[]{r, c});
                  grid[r][c] = '0';
              }
          }
      }
  }

  private boolean isValid(char[][] grid, int r, int c) {
      if (0 <= r && r < grid.length && 0 <= c && c < grid[0].length) {
          return grid[r][c] == '1';
      }
      return false;
  }
}
```

Code
```java
class Solution {

    // DFS
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }

        int rows = grid.length;
        int cols = grid[0].length;
        int count = 0;
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                if (grid[r][c] == '1') {
                    dfsHelper(grid, r, c);
                    count++;
                }
            }
        }
        return count;
    }

    private void dfsHelper(char[][] grid, int row, int col) {
        if (row < 0 || row >= grid.length || col < 0 || col >= grid[0].length) {
            return;
        }
        if (grid[row][col] == '0') {
            return;
        }

        grid[row][col] = '0';
        dfsHelper(grid, row+1, col);
        dfsHelper(grid, row-1, col);
        dfsHelper(grid, row, col+1);
        dfsHelper(grid, row, col-1);
    }
}
```

#Summary
---
- Moving on a matrix can be represented as search in an undirected graph.
- Use the following array to represent the direction
  - int[] dx = {0, 0, 1, -1};
  - int[] dy = {1, -1, 0, 0};
- Use separate method isValid() to see if a move is within the boundary