Bea.AI coding blog
  • Tree
    • Tree Traverse
    • Iteration based traverse
    • Typical problems and solutions
      • Max width of binary tree
      • Binary Tree & BST Serialize & Deserialize
      • Lowest common ancestor (LCA) for Binary Tree and BST
      • Subproblem-based Approach for Resolving Max Value on Trees
      • Path sum III
  • Graph
  • Data structure
    • Java data structure
  • Algorithm general templates
    • Tree
    • Trie
    • Graph
  • Java Algorithm Tips and Tricks
    • Java concurrent list
  • Coding patterns & Strategies
  • Coding patterns & template
    • 1. Binary Search
    • 2. Two Pointer
    • 3. Sliding Window
    • 4. Backtracking
    • 5. DFS
    • 6. BFS
    • 7. Stack
    • 8. Heap
    • 9. Prefix Sum
    • 10. Linked List
    • 11. BST
    • 12. Line sweep
    • 14. Tree
    • 15. Graph
    • 16. Bit manipulation
    • 17. Matrix
    • 18. Monotonic Stack
    • 19. Sorting
    • 20. Union Find
    • 21. Trie
    • 22. Dynamic programming
    • 23. Customized Data Structure
  • Code interview steps
  • Leetcode
    • Tree
      • Traversal
      • Construction and Conversion
      • Search and Validation
      • Manipulation and Modification
      • Special Trees
      • Miscellaneous
    • Dynamic programing
      • Classic DP Problems
      • Sequence/Array DP
      • Matrix DP
      • Knapsack Problems
      • String DP
      • Tree/Graph DP
      • Optimization Problems
      • Combinatorial DP
    • DFS
      • Graph Traversal
      • Path Finding
      • Tree Traversal
      • Backtracking
      • Topological Sorting
      • Traversal Order
      • Dynamic Programming with DFS
      • Connected Components
    • BFS
      • Graph
      • Tree
      • Matrix
      • String
      • Others
    • Two points
      • Array
      • String
      • Linked List
      • Sorting
      • Others
    • LinkedList
      • Basic Operations
      • Cycle Detection and Handling
      • Intersection and Union
      • Partitioning and Merging
      • Palindrome
      • Miscellaneous
    • Backtracking
    • Binary Search
    • Union Find
    • Trie
    • Sort
    • Heap
    • Randomness
    • Topological sort
    • Stack
    • HashTable
    • Sliding Window
  • Blind 75
    • Array
    • Binary
    • Dynamic Programming
    • Graph
    • Interval
    • LinkedList
    • Matrix
    • String
    • Tree
    • Heap
  • Companies
    • Apple
Powered by GitBook
On this page
  • Tree traverse
  • Graph traverse
  • Graph DFS traverse
  • Binary Search
  • Sliding Window (Two pointers)
  • Tree
  • Find all ancestors for a node
  • BST
  • Back Tracking
  • Graph
  • Word Dictionary with . wildchards matching
  • Typical Tree Recursion subproblem (use postorder)

Algorithm general templates

Tree traverse

void traverse(TreeNode root) {
    if (root == null) return;
    traverse(root.left);
    traverse(root.right);
}

Graph traverse

void traverse(Node root) {
   if (root == null) return;
   for (Node child : root.children) {
      traverse(child);
   }
}

Graph DFS traverse

boolean[] visited = new boolean[len];
void traverse(Graph graph, int v) {
    if (visited[v]) return;
    visited[v] = true;
    for (Node neighbor : graph.neighbors(v)) {
        traverse(graph, neighbor);
    }
}

void traverse2(Graph graph, int v) {
    visited[v] = true;
    for (int neighbor : graph.neighors(v)) {
        if (!visited[neighbor]) {
            traverse(neighbor);
        }
    }
}

Binary Search

    public int search(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return -1;
        }
        int left =0, right = nums.length - 1;
        while(left <= right){
            int middle = left + (rigth - left) / 2;
            if(nums[middle] == target) return middle; //f(x)
            if(nums[middle] > target){ // g(x)
                right = middle - 1;
            } else{
                left = middle + 1;
            }
        }
        // left is the smallest index which satisfice g(x)
        // in this case, left is upper bond
        return -1;
    }
    
    int left_bound(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] == target) {
                // Don't return, but move right pointer closer
                right = mid - 1;
            }
        }
        // Check if left point exceeded the bound 
        if (left >= nums.length || nums[left] != target)
            return -1;
        return left;
    }
    
    public static int findLeftBound(int[] nums, int target) {
        int left = 0;
        int right = nums.length;

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (nums[mid] < target) {
                // Condition is not satisfied, left bound must be to the right of mid
                left = mid + 1;
            } else {
                // Condition is satisfied, left bound must be at or to the left of mid
                right = mid;
            }
        }

        return left;
    }
    
    int right_bound(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] == target) {
                // Don't return, but move left pointer further
                left = mid + 1;
            }
        }
        // Check if the right pointer exceeded the bound
        if (right < 0 || nums[right] != target)
            return -1;
        return right;
    }
    
    public static int findRightBound(int[] nums, int target) {
        int left = 0;
        int right = nums.length;

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (nums[mid] <= target) {
                // Condition is satisfied, right bound must be to the right of mid
                left = mid + 1;
            } else {
                // Condition is not satisfied, right bound must be to the left of mid
                right = mid;
            }
        }

        return left;
    }

Sliding Window (Two pointers)

public int lengthOfLongestSubstringKDistinct(String s, int k) {
        if(s == null || s.length() == 0){
            return 0;
        }
        int start = 0, end = 0;
        int count = 0, max = 0;
        int[] charMap = new int[128];
        while(end < s.length()){
            // increase end pointer and count for char at end
            // increase the window
            if(charMap[s.charAt(end++)]++ == 0){
                count++;
            }
            // while conditions not met, move start pointer
            //shrink the window
            while(count > k){
                if(charMap[s.charAt(start++)]-- == 1){
                    count--;
                }
            }
            // calculate max for all valid conditions
            max = Math.max(max, end - start);
        }

        return max;
}

Tree

Inorder traversal a Binary Search Tree with iteration which will get a sorted array.

public List<Integer> inorderTraverse(TreeNode root) {
    List<Integer> list = new ArrayList<>();
    if(root == null) { 
        return list;
    }
    
    Stack<TreeNode> stack = new Stack<>();
    while(root != null || !stack.empty()){
        while(root != null){
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        list.add(root.val);
        root = root.right;

    }
    return list;
}

Preorder traverse binary tree using iteration way

public List<Integer> preorderTraverse(TreeNode root) {
  List<Integer> result = new ArrayList<>();
  if (root == null) {
     return result;
  }
  Stack<TreeNode> stack = new Stack<>();
  stack.push(root);
  while (!stack.isEmpty()) {
     TreeNode curNode = stack.pop();
     result.add(curNode.val);
     if (curNode.right != null) {
        stack.push(curNode.right);
     }
     if (curNode.left != null) {
        stack.push(curNode.left);
     }
  }
  return result;
}

Postorder traverse binary tree using iteration way

public List<Integer> postorderTraverse(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    if (root == null) {
        return result;
    }
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode curNode = stack.pop();
        result.add(0, curNode.val);
        if (curNode.left != null) {
           stack.push(curNode.left);
        }
        if (curNode.right != null) {
            stack.push(curNode.right);
        }
    }
    return result;
}

Find all ancestors for a node

List<TreeNode> ancestors = new ArrayList<>();
public boolean findAllAncestors(TreeNode root, TreeNode target) {
        if (root == null) return false;
        if (root == target) return true;
        boolean left = findAncestors(root.left, target);
        boolean right = findAncestors(root.right, target);
        if (left || right) {
            ancestors.add(root);
        }
        return left || right;
    }

BST

//Template1 of finding items in Binary search tree
void BST(TreeNode root, int target) {
    if (root.val == target)
        //find the item
    if (root.val < target) 
        BST(root.right, target);
    if (root.val > target)
        BST(root.left, target);
}
//Valid BST
 public boolean isValidBST(TreeNode root) {
        return isValidBST(root, null, null);
    }

    private boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) {
        if (root == null) {
            return true;
        }
        if (min != null && root.val <= min.val) return false;
        if (max != null && root.val >= max.val) return false;

        return isValidBST(root.left, min ,root) && isValidBST(root.right, root, max);

    }

Back Tracking

//Template

result = List<>
public void backtrack(/path, /choices) {
    if(meet condition) {
        result.add(path);
        return;
    }
    for (choice : choices) {
        make the choice based on path
        backtrack(path, choices);
        reverse the choice
    }
}

Combination

  public static List<List<Integer>> allCombine(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        backtrack(result, new ArrayList<>(), nums, 0);
        return result;
    }

    public static void backtrack(List<List<Integer>> result, List<Integer> tmpList, int[] nums, int index) {
        // Make a copy of tmpList
        result.add(new ArrayList<>(tmpList));
        // Loop through all possibilities for next position (Purning)
        for (int i = index; i < nums.length; i++) {
            tmpList.add(nums[i]);
            backtrack(result, tmpList, nums, i + 1);
            tmpList.remove(tmpList.size() - 1);
        }
    }

Permutation

 public List<List<Integer>> permuteUnique(int[] nums) {
        // Need to srot the array first if it contains the same numbers
        Arrays.sort(nums);
        List<List<Integer>> result = new ArrayList<>();
        backtrack(result, new ArrayList<>(), nums, new boolean[nums.length]);
        return result;
    }

    private void backtrack(List<List<Integer>> result, List<Integer> tmp, int[] nums, boolean[] visited){
        // Only add valid list to result
        if(tmp.size() == nums.length){
            result.add(new ArrayList(tmp));
            return;
        }

        for(int i=0; i < nums.length; i++){
            // Do not put the same # at the same position twice
            if(visited[i] || i > 0 && nums[i] == nums[i-1] && !visited[i-1]){
                continue;
            }
            tmp.add(nums[i]);
            visited[i] = true;
            backtrack(result, tmp, nums, visited);
            visited[i] = false;
            tmp.remove(tmp.size() -1);
        }
    }

Graph

BFS

//Simple graph BFS template
private void bfs(int[][] graph, int start) {
    Queue<Integer> queue = new LinkedList<>();
    visited[start] = true;
    queue.offer(start);
    while (!queue.isEmpty()) {
        int v = queue.poll();
        for (int w: graph[v]) {
            if (!visited[w]) {
                visited[w] = true;
                queue.offer(w);
            }
        }
    }
}

Leetcode 286


    public void wallsAndGates(int[][] rooms) {
        if(rooms == null || rooms.length == 0){
            return;
        }
        int m = rooms.length, n = rooms[0].length;
        Queue<int[]> queue = new ArrayDeque<>();
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(rooms[i][j] == 0){
                    queue.offer(new int[]{i, j, 0});
                }
            }
        }
        int[][] directions = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        while(!queue.isEmpty()){
            int[] cur = queue.poll();
            for(int[] dir : directions){
                int r = cur[0] + dir[0];
                int c = cur[1] + dir[1];
                // out of boundaries
                if(r < 0 || r >= m || c < 0 || c >= n){
                    continue;
                }
                // condition check/check visited or not
                if(rooms[r][c] != Integer.MAX_VALUE){
                    continue;
                }
                // set visted and update node
                rooms[r][c] = cur[2] + 1;
                // add neighbour into queue
                queue.offer(new int[]{r, c, rooms[r][c]});
            }
        }
    }

DFS

Leetcode 733

 public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
        int color = image[sr][sc];
        // do dfs for each source point
        if(color != newColor)
            dfs(image, sr, sc, color, newColor);
        return image;
    }

    private void dfs(int[][] image, int row, int col,int color, int newColor){
        // if condition do not meet, return
        if(row < 0 || row >= image.length || col < 0 || col >= image[0].length
           || image[row][col] != color){
            return;
        }
        // set visted and operate current point
        image[row][col] = newColor;
        dfs(image, row, col - 1, color, newColor);
        dfs(image, row, col + 1, color, newColor);
        dfs(image, row - 1, col, color, newColor);
        dfs(image, row + 1, col, color, newColor);
    }

Dijkstra

Leetcode 743

 public int networkDelayTime(int[][] times, int N, int K) {
        Map<Integer, List<int[]>> graph = new HashMap<>();
        for(int[] time : times){
            List<int[]> edges = graph.getOrDefault(time[0], new ArrayList<>());
            edges.add(new int[]{time[1], time[2]});
            graph.put(time[0], edges);
        }
        // target, weight -- use heap to reduce time complexity
        PriorityQueue<int[]> pq = new PriorityQueue<>((n1, n2) -> n1[1] -n2[1]);
        pq.offer(new int[]{K, 0});
        // Init distance map
        int[] dist = new int[N+1];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[K] = 0;
        int count = 0;
        while(!pq.isEmpty()){
            int[] cur = pq.poll();
            if(dist[cur[0]] < cur[1]) continue;
            count++;
            if(graph.get(cur[0]) != null){
                for(int[] edge : graph.get(cur[0])){
                    int d = cur[1] + edge[1];
                    if(d < dist[edge[0]]){
                        dist[edge[0]] = d;
                        pq.offer(new int[]{edge[0], d});
                    }
                }
            }
        }
        if(count != N) return -1;
        int max = 0;
        for(int i = 1; i <= N; i++){
            max = Math.max(max, dist[i]);
        }

        return max;
    }

Sort algorithms

// Quick sort
public int[] quickSort(int[] array, int l, int h) {
    if (l<h) {
        int partition = partition(array, l, h);
        quickSort(array, l, partition-1);
        quickSort(array, partition+1, h);
    }
}

public void swap (int[] array, i, j) {

}

public int partition(int[] array, int l, int h) {
    int partition = l;
    int pivot = array[h];
    for (int i = l; i < h; i++) {
        if (array[i] <= pivot) {
            swap(array, i, partition);
            partition++;
        }
    }
    swap(array, partition, h);
    return partition;
}


// merge sort
public static void mergeSort(int[] a, int n) {
    if (n < 2) {
        return;
    }
    int mid = n / 2;
    int[] l = new int[mid];
    int[] r = new int[n - mid];

    for (int i = 0; i < mid; i++) {
        l[i] = a[i];
    }
    for (int i = mid; i < n; i++) {
        r[i - mid] = a[i];
    }
    mergeSort(l, mid);
    mergeSort(r, n - mid);

    merge(a, l, r, mid, n - mid);
}

public static void merge(
  int[] a, int[] l, int[] r, int left, int right) {
 
    int i = 0, j = 0, k = 0;
    while (i < left && j < right) {
        if (l[i] <= r[j]) {
            a[k++] = l[i++];
        }
        else {
            a[k++] = r[j++];
        }
    }
    while (i < left) {
        a[k++] = l[i++];
    }
    while (j < right) {
        a[k++] = r[j++];
    }
}

Toplogical Sort

public boolean canFinish(int numCourses, int[][] prerequisites) {
        if(prerequisites == null || prerequisites.length == 0) return true;

        //Record the indegree num of every cources
        int[] indegrees = new int[numCourses];
        Map<Integer, List<Integer>> graph = new HashMap<>();
        int res = numCourses;

        //set indegree and build graph
        for (int[] prerequisite :  prerequisites) {
            indegrees[prerequisite[0]]++;
            graph.computeIfAbsent(prerequisite[1], k -> new ArrayList<>()).add(prerequisite[0]);
        }

        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (indegrees[i] == 0) {
                queue.offer(i);
            }
        }
        
        //BFS on the courses with 0 indegree, add the new cources to the queue if indegree is 0
        while (!queue.isEmpty()) {
            int cource = queue.poll();
            res--;
            if (graph.get(cource) != null) {
                for (int node : graph.get(cource)) {
                    indegrees[node]--;
                    if (indegrees[node] == 0) {
                        queue.offer(node);
                    }
                }
            }
        }

        return res == 0;

    }

Union Find

//without rank
int[] parents
void Union(int p, int q) { 
   parents[find(p)] = find(q); 
}

public int find(int i){
    if(parents[i] == i){
        return i;
    }
    return parents[i] = find(parents[i]);
}

public UnionFind(int n){
    parents = new int[n];
    for(int i = 0; i < n; i++){
        parents[i] = i;
    }
}
//With rank
class UnionFind{
    int[] parents;
    int[] ranks;

    public UnionFind(int n){
        parents = new int[n];
        ranks = new int[n];
        for(int i = 0; i < n; i++){
            parents[i] = i;
        }
    }

    public int find(int i){
        if(parents[i] == i){
            return i;
        }
        return parents[i] = find(parents[i]);
    }

    public void union(int a, int b){
        int root1 = find(a);
        int root2 = find(b);
        if(root1 == root2){
            return;
        }
        if(ranks[root1] < ranks[root2]){
            parents[root1] = root2;
        }else if(ranks[root2] < ranks[root1]){
            parents[root2] = root1;
        }else{
            parents[root2] = root1;
            ranks[root1]++;
        }
    }

}

Trie

class TrieNode{
    Map<Character, TrieNode> children;
    boolean isWord;

    public TrieNode(){
        children = new HashMap<>();
    }
}

class Trie{
    TrieNode root;

    public Tire(){
        root = new TrieNode();
    }

    public void insert(String word){
        TrieNode p = root;
        for(char c : word.toCharArray()){
            p.children.computeIfAbsent(c, k -> new TrieNode());
            p = p.children.get(c);
        }
        p.isWord = true;
    }

    public TrieNode find(String prefix){
        TrieNode p = root;
        for(char c : prefix.toCharArray()){
            if(p.children.get(c) == null){
                return null;
            }
            p = p.children.get(c);
        }

        return p;
    }
    
}

Word Dictionary with . wildchards matching

class WordDictionary {

    class TrieNode {
        TrieNode[] children;
        boolean isWord;
        TrieNode() {
            children = new TrieNode[26];
            isWord = false;
        }
    }

    TrieNode root;

    public WordDictionary() {
        root = new TrieNode();
    }
    
    public void addWord(String word) {
        TrieNode curNode = root;
        for (char ch : word.toCharArray()) {
            int charIndex = ch - 'a';
            if (curNode.children[charIndex] == null) {
                curNode.children[charIndex] = new TrieNode();
            }
            curNode = curNode.children[charIndex];
        }
        curNode.isWord = true;
    }
    
    public boolean search(String word) {
       return find(word, root, 0);
    }

    //Need DFS search, because of wildcard matching
    private boolean find(String word, TrieNode startNode, int index) {
        if (index == word.length()) {
            return startNode.isWord;
        }
        char ch = word.charAt(index);
        if (ch != '.') {
            int charIndex = ch - 'a';
            return startNode.children[charIndex] != null && find(word, startNode.children[charIndex], index + 1);
        } else {
            for (TrieNode node : startNode.children) {
                if (node != null && find(word, node, index + 1)) {
                    return true;
                }
            }
            return false;
        }
    }
}

Segment Tree

class SegmentTreeNode{
    int start;
    int end;
    int sum;
    SegmentTreeNode left;
    SegmentTreeNode right;

	public SegmentTreeNode(int start, int end){
        this.start = start;
        this.end = end;
    }

    private SegmentTreeNode buildTree(int start, int end, int[] nums){
	    if(start > end) return null;
        SegmentTreeNode node = new SegmentTreeNode(start, end);
 	    if(start == end){
	        node.sum = nums[start];
	        return node;
        } else {
            int mid = start + (end - start)/2;
            node.left = buildTree(start, mid, nums);
            node.right = buildTree(mid + 1, end, nums);
	        node.sum = node.left.sum + node.right.sum;
        }

        return node;
    }

    private void updateNode(SegmentTreeNode node, int index, int val){
	    if(node.start == node.end){
	        node.sum = val;
	        return;
        }
        int mid = node.start + (node.end - node.start)/2;
        if(mid >= index){
            updateNode(node.left, index, val);
        }else{
            updateNode(node.right, index, val);
        }
        node.sum = node.left.sum + node.right.sum;
    }

    private int sumRange(SegmentTreeNode node, int start, int end){
	    if(node.start == start && node.end == end){
	        return node.sum;
        }
        int mid = node.start + (node.end - node.start)/2;
        if(start > mid){
	        return sumRange(node.right, start, end);
        }else if(end <= mid){
	        return sumRange(node.left, start, end);
        }else{
            return sumRange(node.left, start, mid) + sumRange(node.right, mid + 1, end);
        }
    }
}

Typical Tree Recursion subproblem (use postorder)

//Diameter of a tree
//https://leetcode.com/problems/diameter-of-binary-tree/
int maxDiameter = 0;
public int diameter(TreeNode root) {
    maxDepth(root);
    return maxDiameter;
}
private int maxDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    int leftMaxDepth = maxDepth(root.left);
    int rightMaxDepth = maxDepth(root.right);
    maxDiameter = Math.max(maxDiameter, leftMaxDepth + rightMaxDepth);
    return Math.max(leftMaxDepth, rightMaxDepth) + 1;
}
/********************************/


//Max path sum of a tree
int maxPathSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
    maxSingleSidePathSum(root);
    return maxPathSum;
}
private int maxSingleSidePathSum(TreeNode root) {
    if (root == null) {
        return 0;
    }
    int leftPathSum = Math.max(0, maxSingleSidePathSum(root.left));
    int rightPathSum = Math.max(0, maxSingleSidePathSum(root.right));
    maxPathSum = Math.max(maxPathSum, leftPathSum + rightPathSum + root.val);
    return Math.max(leftPathSum, rightPathSum) + root.val;
}
PreviousJava data structureNextTree

Last updated 1 year ago