code

12 阅读15分钟

remove node and height

public class BinaryTree {
    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        // Constructor to initialize the node.
        public TreeNode(int x) {
            val = x;
        }
    }

    private void buildParentMap(TreeNode node, TreeNode parent, Map<TreeNode, TreeNode> map) {
        if (node == null) return;
        // For root node, parent is null.
        map.put(node, parent);
        buildParentMap(node.left, node, map);
        buildParentMap(node.right, node, map);
    }


    // return The updated root of the tree.
    public TreeNode removeNode(TreeNode root, TreeNode nodeToRemove, Map<TreeNode, TreeNode> parentMap) {
        if (nodeToRemove == null) return root;

        // Determine the only child of the node to remove.
        TreeNode child = (nodeToRemove.left != null) ? nodeToRemove.left : nodeToRemove.right;

        // If nodeToRemove is the root, update the root pointer.
        if (root == nodeToRemove) {
            if (child != null) {
                parentMap.put(child, null); // Child becomes the new root.
            }
            return child;
        }

        // Get the parent from the precomputed map.
        TreeNode parent = parentMap.get(nodeToRemove);
         //if (parent != null) {
        // Replace nodeToRemove with its child in the parent's pointer.
        if (parent.left == nodeToRemove) {
            parent.left = child;
        } else if (parent.right == nodeToRemove) {
            parent.right = child;
        }
        //}
        // Update the parent map for the reattached child.
        if (child != null) {
            parentMap.put(child, parent);
        }
        return root;
    }

    public int computeHeight(TreeNode root) {
        if (root == null) return 0;
        return 1 + Math.max(computeHeight(root.left), computeHeight(root.right));
    }

  
    public int removeNodesAndGetHeight(TreeNode root, List<TreeNode> toRemove) {
        // Precompute parent pointers for all nodes.
        Map<TreeNode, TreeNode> parentMap = new HashMap<>();
        buildParentMap(root, null, parentMap);

        // Process each node in the removal list.
        for (TreeNode node : toRemove) {
            root = removeNode(root, node, parentMap);
        }
        return computeHeight(root);
    }

    // Example usage.
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();

        // Construct a sample tree:
        //         1
        //        / \
        //       2   3
        //        \
        //         4
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.right = new TreeNode(4); // Node 2 has only one child.

        // Suppose we want to remove node 2.
        List<TreeNode> nodesToRemove = List.of(root.left);

        // After removal, node 4 will be attached directly to node 1.
        int newHeight = tree.removeNodesAndGetHeight(root, nodesToRemove);
        System.out.println("Height of the modified tree: " + newHeight);
    }
}

Role permission 0

import java.util.*;

class Solution {

  public static List<Set<Character>> getEffectivePrivileges(int n, int[][] grants, List<Set<Character>> allowedList, List<Set<Character>> disallowedList) {

    // 建图
    Map<Integer, List<Integer>> graph = new HashMap<>();
    for (int i = 0; i < n; i++) {
      graph.put(i, new ArrayList<>());
    }

    // 入度表
    int[] inDegree = new int[n];
    for (int[] grant : grants) {
      int from = grant[0], to = grant[1];
      graph.get(from).add(to);
      inDegree[to]++;
    }

    // 入度 = 0, 入列可bfs
    Queue<Integer> queue = new LinkedList<>();
    for (int i = 0; i < n; i++) {
      if (inDegree[i] == 0) {
        queue.offer(i);
      }
    }
    
    List<Set<Character>> res = new ArrayList<>();

    // BFS
    while (!queue.isEmpty()) {
      int cur = queue.poll();

      // 当前node的allow
      Set<Character> curAllowed = allowedList.get(cur);
      res.add(curAllowed);

      // 如果自己的disallow里和allow有一样的东西
      // Set<Character> newCurAllowed = new HashSet<>(curAllowed);
      // newCurAllowed.removeAll(disallowedList.get(cur));
      // res.add(newCurAllowed);

      for (int neighbour: graph.get(cur)) {

            // 遍历当前node的权限
            for (Character c : curAllowed) {
                  // 如果adj的disallow里没有有当前权限,可以继承
                  if (!disallowedList.get(neighbour).contains(c)) {
                     allowedList.get(neighbour).add(c);
                  }
            }

            inDegree[neighbour]--;

            if (inDegree[neighbour] == 0) {
              queue.offer(neighbour);
            }
      }
    }

    return res;
  }

  public static void printPrivileges(List<Set<Character>> list) {
    for (int i = 0; i < list.size(); i++) {
      List<Character> l = new ArrayList<>(list.get(i));
      Collections.sort(l);
      System.out.println("NODE: " + i + ", allowed: " + l);
    }
  }


  public static void main(String[] args) {
      // Test Case 1:
        // Simple chain: Role 0 -> Role 1 -> Role 2.
        // Role 0 allowed: [A, B]; Role 1 allowed: [C] but disallows [B]; Role 2 allowed: [D] but disallows [C].
        int n1 = 3;

        int[][] grants1 = {
          {0,1},
          {1,2}
        };

        List<Set<Character>> allowedList1 = new ArrayList<>();
        allowedList1.add(new HashSet<>(Arrays.asList('A', 'B'))); // Role 0
        allowedList1.add(new HashSet<>(Arrays.asList('C')));      // Role 1
        allowedList1.add(new HashSet<>(Arrays.asList('D')));      // Role 2
        
        List<Set<Character>> disallowedList1 = new ArrayList<>();
        disallowedList1.add(new HashSet<>());                     // Role 0
        disallowedList1.add(new HashSet<>(Arrays.asList('B')));     // Role 1
        disallowedList1.add(new HashSet<>(Arrays.asList('C')));     // Role 2
        
        System.out.println("Test Case 1:");
        List<Set<Character>> result1 = getEffectivePrivileges(n1, grants1, allowedList1, disallowedList1);
        printPrivileges(result1);
        
        // Test Case 2:
        // Branching tree:
        //         Role 0
        //       /       \
        //   Role 1      Role 2
        //       \       /
        //        Role 3
        // Allowed privileges:
        // Role 0: [A]
        // Role 1: [B] and disallows [C]
        // Role 2: [C]
        // Role 3: [D] and disallows [A]
        int n2 = 4;
        int[][] grants2 = {
            {0, 1},
            {0, 2},
            {1, 3},
            {2, 3}
        };
        
        List<Set<Character>> allowedList2 = new ArrayList<>();
        allowedList2.add(new HashSet<>(Arrays.asList('A'))); // Role 0
        allowedList2.add(new HashSet<>(Arrays.asList('B'))); // Role 1
        allowedList2.add(new HashSet<>(Arrays.asList('C'))); // Role 2
        allowedList2.add(new HashSet<>(Arrays.asList('D'))); // Role 3
        
        List<Set<Character>> disallowedList2 = new ArrayList<>();
        disallowedList2.add(new HashSet<>());                     // Role 0
        disallowedList2.add(new HashSet<>(Arrays.asList('C')));     // Role 1
        disallowedList2.add(new HashSet<>());                     // Role 2
        disallowedList2.add(new HashSet<>(Arrays.asList('A')));     // Role 3
        
        System.out.println("\nTest Case 2:");
        List<Set<Character>> result2 = getEffectivePrivileges(n2, grants2, allowedList2, disallowedList2);
        printPrivileges(result2);
        
        // Test Case 3:
        // A role with no grants (an isolated role).
        // Role 0 allowed: [X, Y] but disallows [Y].
        int n3 = 1;
        // List<int[]> grants3 = new ArrayList<>();
        int[][] grants3 = {};
        
        List<Set<Character>> allowedList3 = new ArrayList<>();
        allowedList3.add(new HashSet<>(Arrays.asList('X', 'Y')));
        
        List<Set<Character>> disallowedList3 = new ArrayList<>();
        disallowedList3.add(new HashSet<>(Arrays.asList( 'Y')));
        
        System.out.println("\nTest Case 3:");
        List<Set<Character>> result3 = getEffectivePrivileges(n3, grants3, allowedList3, disallowedList3);
        printPrivileges(result3);
  }
}

Role permission 1

import java.util.*;

import java.util.*;

class RolePermission {
    // 给定role的继承relation,当前assign的权限的role list,返回role有没有权限
    public boolean hasRole(int[][] relationship, int[] assigned, int role) {
        // Build the graph: key is a role, value is a list of roles it inherits.
        // 《node, 孩子们〉
        Map<Integer, List<Integer>> graph = new HashMap<>();
        for (int[] r : relationship) { 
            if (!graph.containsKey(r[0])) {
              graph.put(r[0], new ArrayList<>());
            }
            graph.get(r[0]).add(r[1]);
        }
        
        // Set to keep track of visited roles to avoid processing them more than once.
        // in case of cycle
        Set<Integer> visited = new HashSet<>();

        // Queue for BFS.
        Queue<Integer> queue = new LinkedList<>();
        
        // 有权限的role,可以入列,从他们开始bfs
        for (int r : assigned) {
            queue.offer(r);
            visited.add(r); 
        }
        
        // Perform BFS.
        while (!queue.isEmpty()) {
            int cur = queue.poll();

            // If current role matches the target role, return true.
            if (cur == role) {
                return true;
            }

            if (graph.containsKey(cur)) {
                for (int adj : graph.get(cur)) {
                  // 否则可能会infinite loop,1-2-3-1, t = 4
                  if (!visited.contains(adj)) {
                      visited.add(adj);
                      queue.offer(adj);
                  }
                }
            }
          
        }
        return false;
    }
}


public class Solution {
    // Sample test run
    public static void main(String[] args) {
      RolePermission rp = new RolePermission();
        // // Example
        // int[][] relationship = {
        //     {1, 2},
        //     {2, 3},
        //     {4, 3},
        //     {3, 5}
        // };
 
        // int[] assigned = {2, 4};
        
        // System.out.println(rp.hasRole(relationship, assigned, 1)); // Output: false

        // System.out.println(rp.hasRole(relationship, assigned, 3)); // Output: true

        // System.out.println(rp.hasRole(relationship, assigned, 2)); // Output: true

        // System.out.println(rp.hasRole(relationship, assigned, 5)); // Output: true

        // Cycle
        int[][] relationshipCycle = {
            {1, 2},
            {2, 3},
            {3, 1}
        };
        int[] assignedCycle = {1}; // User is directly assigned role 1.
        // We expect true because role 3 can be reached via the cycle: 1 -> 2 -> 3.
        System.out.println("Cycle Test: User has role 3? " + rp.hasRole(relationshipCycle, assignedCycle, 3));

        // 可以测试visited set,这样不会infinite loop
        System.out.println("Cycle Test: User has role 4? " + rp.hasRole(relationshipCycle, assignedCycle, 4));
        
    }
}

Role permission 2

Time:

    O(e)         // building the graph
+ O(d × (n + e))   // processing each deny pair
= O(d × (n + e))

Space

O(n + e)          // for the graph
+ O(n) per deny pair
= O(n + e + d × n)
class RolePermission {
    public boolean isDenied(int[][] relationship, int[][] deny_pairs, int user_role, int target_role) {
        // Build the graph
        Map<Integer, List<Integer>> graph = new HashMap<>();
        for (int[] r : relationship) { 
            if (!graph.containsKey(r[0])) {
              graph.put(r[0], new ArrayList<>());
            }
            graph.get(r[0]).add(r[1]);
        }
        
        // For each deny pair [a, b], check if the deny applies.
        for (int[] pair : deny_pairs) {
            int a = pair[0];
            int b = pair[1];
            
            // All children of 'a' , exculde a
            Set<Integer> set1 = getChildren(a, graph);
            set1.remove(a);
            // All children of b include b 
            Set<Integer> set2 = getChildren(b, graph);
            
            if (set1.contains(user_role) && set2.contains(target_role)) {
                return true;
            }
        }
        return false;
    }
    
    private Set<Integer> getChildren(int role, Map<Integer, List<Integer>> graph) {

        Set<Integer> result = new HashSet<>();
        
        
        result.add(role);

        Queue<Integer> queue = new LinkedList<>();
        queue.offer(role);
     
        while (!queue.isEmpty()) {
            int cur = queue.poll();
            if (graph.get(cur) != null) {
                for (int adj : graph.get(cur)) {
                    // prevent infi loop can ignore if there is no loop
                    if (!result.contains(adj)) { 
                        result.add(adj);
                        queue.offer(adj);
                    }
                }
            }
        }
        return result;
    }
  
}


public class Solution {
    // Sample test runs
    public static void main(String[] args) {
        RolePermission rp = new RolePermission();
        // 1->2->3->4->5
        int[][] relationship3 = {
            {1, 2},
            {2, 3},
            {3, 4},
            {4, 5},
            // {5,1}

        };
        // Deny pair: [1,2]
        int[][] deny_pairs3 = {
            {2, 4}
        };
        System.out.println("Test Case 4a: " + rp.isDenied(relationship3, deny_pairs3, 2, 5)); // Expected: false;
        
        System.out.println("Test Case 4a: " + rp.isDenied(relationship3, deny_pairs3, 1, 3)); // Expected: false;

        System.out.println("Test Case 4a: " + rp.isDenied(relationship3, deny_pairs3, 3, 4)); // Expected: true;
    }
}

prefix map

import java.util.*;

class Trie {
    // Define Trie Node
    class Node {
        Map<Character, Node> children = new HashMap<>();
        boolean isEnd = false;
        Integer value = null; // value stored at end of a key
    }
    
     class Node {
        Node[] children; 
        boolean isEnd;//当前节点为叶子?
        Node() { children = new Node[26]; } 
    }

  

    private Node root;

    public Trie() {
        root = new Node();
    }

    // Insert key with value
    public void insert(String word, int val) {
        Node cur = root;
        for (char c : word.toCharArray()) {
            // new char on the path
            if (!cur.children.containsKey(c)) { 
              cur.children.put(c, new Node());
            }
            cur = cur.children.get(c);
        }
        cur.isEnd = true;
        cur.value = val;
    }

    // Exact key lookup
    public Integer containSearch(String word) {
        Node cur = root;
        for (char c : word.toCharArray()) {
            if (!cur.children.containsKey(c)) {
              return null;
            }
            cur = cur.children.get(c);
        }
        return cur.isEnd ? cur.value : null;
    }

    // Return all values with given prefix
    public List<Integer> prefixSearch(String prefix) {
        List<Integer> result = new ArrayList<>();
        Node cur = root;
        for (char c : prefix.toCharArray()) {
            if (!cur.children.containsKey(c)) {
              return result; // return empty list
            }
            cur = cur.children.get(c);
        }
        // at this point, cur is at the last node of prefix
        // Do dfs to the sub-tree, then get result
        dfs(cur, result);
        return result;
    }

    // DFS to collect values from subtree
    private void dfs(Node node, List<Integer> result) {
         // if (node.isEnd && node.value != null) {
        if (node.isEnd) {
            result.add(node.value);
        }
        for (Node child : node.children.values()) {
            dfs(child, result);
        }
    }
}


public class Solution {
    // Sample test run
    public static void main(String[] args) {

         Trie trie = new Trie();
        trie.insert("abc", 1);
        trie.insert("abcd", 2);
        trie.insert("abf", 3);

        System.out.println(trie.containSearch("abc"));   // 1
        System.out.println(trie.containSearch("ab"));    // null
        System.out.println(trie.prefixSearch("ab"));     // [1, 2, 3]
        System.out.println(trie.prefixSearch("abc"));    // [1, 2]
        System.out.println(trie.prefixSearch("abcd"));   // [2]
    }
}

graph coloring

    • For each node, the algorithm tries 3 possible colors. In the worst-case, it will try all possible combinations for V nodes, which gives a worst-case complexity of O(3^V).

    • Additionally, for each color assignment, the algorithm checks all neighbors (which could be O(V) in a dense graph), making the overall worst-case time complexity roughly O(3^V * V).

    • The graph is stored as an adjacency list, requiring O(V + E) space.



import java.util.*;

public class Solution {
    public static boolean canColorWithThreeColors(int[][] edges, List<Integer> nodes) {
        // Step 1: 建图
        Map<Integer, List<Integer>> graph = new HashMap<>();
        for (int node : nodes) {
            graph.put(node, new ArrayList<>());
        }
        for (int[] edge : edges) {
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]); 
            // Because it's an undirected graph
        }

        // Step 2: 初始化fill所有node为0,无颜色
        // <Node, color>
        Map<Integer, Integer> colorMap = new HashMap<>();
        for (int node : nodes) {
            colorMap.put(node, 0);
        }

        // Step 3: Try to color each node (in case of disconnected components)
        for (int node : nodes) {
            if (colorMap.get(node) == 0) {
                // If coloring fails for any component, return false
                if (!dfsColor(node, graph, colorMap)) {
                    return false;
                }
            }
        }

        // All nodes colored successfully with no conflicts
        return true;
    }


    // return true if coloring succeeds from this node onward
    private static boolean dfsColor(int node, Map<Integer, List<Integer>> graph, Map<Integer, Integer> colorMap) {

        // 尝试给当前node染不同颜色 (1 = red, 2 = green, 3 = blue)
        for (int color = 1; color <= 3; color++) {
            boolean validColor = true;

            // 如果邻居有相同颜色,意味当前颜色不可用
            for (int neighbor : graph.get(node)) {
                if (colorMap.get(neighbor) == color) {
                    // 跳过当前color
                    validColor = false;
                    break;
                }
            }

            // If the color is not safe to use, skip
            if (!validColor) {
              continue;
            }
 
            // Assign the color to the current node
            colorMap.put(node, color);

            // Recursively try to color all uncolored neighbors
            boolean success = true;
            for (int neighbor : graph.get(node)) {
                // 邻居还没颜色
                if (colorMap.get(neighbor) == 0) {
                    if (!dfsColor(neighbor, graph, colorMap)) {
                        // 当前节点选择了color,导致邻居染色失败,所以不选
                        success = false; 
                        break;
                    }
                }
            }

            // If all neighbors were successfully colored, then we are done — return true
            if (success) {
                return true;
            }

            // Backtrack: undo the color assignment and try next color
            colorMap.put(node, 0);
            
        }

        // No valid color assignment found for this node
        return false;
    }

    // Sample test run
    public static void main(String[] args) {

        // true
        // int[][] edges = {
        //     {1, 2},
        //     {2, 3},
        //     {3, 1},
        //     {3, 4}
        // };

        // 4 nodes fully connected graph -> false
        // int[][] edges = {
            // {1, 2},
            // {1, 3},
            // {1, 4},
            // {2, 3},
            // {2, 4},
            // {3, 4}
        // };

        // Disconnected components
        // true
        //  int[][] edges = {
        //     {1, 2},
        //     {2, 3},
        //     {3, 1},
        //     {4,4}
        // };

        // true
        //  int[][] edges = {
        //     {1, 2},
        //     {2, 3},
        //     {3, 1},
        //     {4, 5}
        // };


        // false
        // int[][] edges = {
        //     {1, 2},
        //     {1, 3},
        //     {1, 4},
        //     {2, 3},
        //     {2, 4},
        //     {3, 4},
        //     {5,6}
        // };

               

        List<Integer> nodes = Arrays.asList(1, 2, 3, 4,5,6);

        boolean result = canColorWithThreeColors(edges, nodes);

        System.out.println("Can color with 3 colors: " + result);
    }
}


private static boolean bfsColor(int startNode, Map<Integer, List<Integer>> graph, Map<Integer, Integer> colorMap) {
    // BFS queue to process nodes level by level
    Queue<Integer> queue = new LinkedList<>();
    queue.offer(startNode);

    // Start coloring the first node with color 1 (you can pick any from 1 to 3)
    colorMap.put(startNode, 1);

    // BFS traversal
    while (!queue.isEmpty()) {
        int node = queue.poll(); // Dequeue a node
        int currentColor = colorMap.get(node); // Get its assigned color

        // Traverse all its neighbors
        for (int neighbor : graph.get(node)) {

            // Case 1: Neighbor has not been colored yet
            if (colorMap.get(neighbor) == 0) {
                boolean colored = false;

                // Try assigning a color from 1 to 3
                for (int c = 1; c <= 3; c++) {
                    boolean canUse = true;

                    // Check if any neighbor of this neighbor already has color 'c'
                    for (int adj : graph.get(neighbor)) {
                        if (colorMap.get(adj) != null && colorMap.get(adj) == c) {
                            canUse = false; // Conflict found
                            break;
                        }
                    }

                    // If color 'c' is safe to assign
                    if (canUse) {
                        colorMap.put(neighbor, c); // Assign the color
                        queue.offer(neighbor);     // Enqueue the neighbor for further processing
                        colored = true;
                        break;
                    }
                }

                // If no color could be assigned to this neighbor
                if (!colored) {
                    return false; // Coloring fails
                }

            // Case 2: Neighbor is already colored — check for conflict
            } else if (colorMap.get(neighbor) == currentColor) {
                // Adjacent nodes cannot have the same color
                return false;
            }
        }
    }

    // All nodes in this component successfully colored with 3 colors
    return true;
}

event recording

// Define the Event class.
class Event {
    String type;
    long time;
    
    public Event(String type, long time) {
        this.type = type;
        this.time = time;
    }
    
    @Override
    public String toString() {
        return "Event[type=" + type + ", time=" + time + "]";
    }
}

// Define the BST node.
class TreeNode {
    TreeNode left;
    TreeNode right;
    Event event;
    
    public TreeNode(Event event) {
        this.event = event;
    }
}

// BST-based Event recorder
class EventBST {
    TreeNode root;
    
    // Insert an event into the BST.
    // This method assumes that root is not null; if it is, we initialize it.
    public void insert(Event event) {
        if (root == null) {
            root = new TreeNode(event);
        } else {
            insert(event, root);
        }
    }
    
    // Insert the event into the BST starting from the given root.
    public void insert(Event event, TreeNode root) {
        if (event.time < root.event.time) {
            if (root.left == null) {
                root.left = new TreeNode(event);
            } else {
                insert(event, root.left);
            }
        } else if (event.time > root.event.time) {
            if (root.right == null) {
                root.right = new TreeNode(event);
            } else {
                insert(event, root.right);
            }
        } else {
            // If an event with the same time exists, override it.
            root.event = event;
        }
    }
    
    // Retrieve the event at the specified time by searching the BST.
    public Event find(TreeNode root, long time) {
        if (root == null) {
            return null;
        }
        if (time == root.event.time) {
            return root.event;
        } else if (time < root.event.time) {
            return find(root.left, time);
        } else {
            return find(root.right, time);
        }
    }
    
    // Helper method: retrieve event starting from the BST's root.
    public Event find(long time) {
        return find(root, time);
    }
    
    // Count the number of events of the specified type that occurred 
    // between the start and end times (inclusive).
    public int count(String type, long start, long end) {
        return count(root, type, start, end);
    }
    
    // Recursive helper for count.
    private int count(TreeNode node, String type, long start, long end) {
        if (node == null) {
            return 0;
        }
        int cnt = 0;
        // Only consider the current node if its time is within the range.
        if (node.event.time >= start && node.event.time <= end) {
            if (node.event.type.equals(type)) {
                cnt = 1;
            }
        }
        // If the node's time is greater than start, then the left subtree might have nodes in range.
        if (node.event.time > start) {
            cnt += count(node.left, type, start, end);
        }
        // If the node's time is less than end, then the right subtree might have nodes in range.
        if (node.event.time < end) {
            cnt += count(node.right, type, start, end);
        }
        return cnt;
    }
    
    // Optional: an in-order traversal to print all events (for testing purposes).
    public void inOrder(TreeNode node) {
        if (node == null) return;
        inOrder(node.left);
        System.out.println(node.event);
        inOrder(node.right);
    }
    
    public void printInOrder() {
        inOrder(root);
    }
}

// Test driver to demonstrate the functionality.
public class Solution {
    public static void main(String[] args) {
        EventBST bst = new EventBST();
        
        // Insert several events.
        bst.insert(new Event("login", 1000));   // at time 1000
        bst.insert(new Event("logout", 2000));  // at time 2000
        bst.insert(new Event("login", 3000));   // at time 3000
        bst.insert(new Event("purchase", 4000)); // at time 4000
        bst.insert(new Event("login", 5000));   // at time 5000
        
        // Retrieve an event at a specific time.
        Event e = bst.find(2000);
        System.out.println("Event at time 2000: " + (e != null ? e : "Not found"));
        // Expected output: Event at time 2000: Event[type=logout, time=2000]
        
        // Count the number of "login" events between time 1000 and 5000 (inclusive).
        int countLogin = bst.count("login", 1000, 5000);
        System.out.println("Count of login events between 1000 and 5000: " + countLogin);
        // Expected output: 3 (times 1000, 3000, 5000)
        
        // Optionally, print the BST in order.
        System.out.println("All events in order:");
        bst.printInOrder();
    }
}

non-leaf, sub tree avg node

class TreeNode {
      int val;
      TreeNode left, right;
      TreeNode(int val) { this.val = val; }
  }

public  class Solution {
  

    private static boolean isValid = true;

    public static boolean isAverageTree(TreeNode root) {
        postOrder(root);
        return isValid;
    }

    private static double[] postOrder(TreeNode node) {
        if (node == null) return new double[]{0, 0}; // {sum, count}

        double[] left = postOrder(node.left);
        double[] right = postOrder(node.right);

        double sum = left[0] + right[0] + node.val;
        double count = left[1] + right[1] + 1;

        // Only check non-leaf nodes
        if (node.left != null || node.right != null) {
            double average = sum / count;
            if (node.val != average) {
                isValid = false;
            }
        }

        return new double[]{sum, count};
    }

    public static void main(String[] args) {

        TreeNode root = new TreeNode(5);
        root.left = new TreeNode(1);
        root.right = new TreeNode(9);
        // 5 == (5+1+9)/3 = 5  ✅

        System.out.println(isAverageTree(root)); // true

        root.left = new TreeNode(2); // Now 5 != (5+2+9)/3 = 5.33 
        System.out.println(isAverageTree(root)); // false
    }
}

012 cake - count index

brute force

public class CakeDistance {
    public static int minDistance(int[] arr) {
        int n = arr.length;
        int minDist = Integer.MAX_VALUE;

        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                // 向左找
                for (int j = i - 1; j >= 0; j--) {
                    if (arr[j] == 2) {
                        minDist = Math.min(minDist, i - j);
                        break; // 找到最近的蛋糕就行
                    }
                }

                // 向右找
                for (int j = i + 1; j < n; j++) {
                    if (arr[j] == 2) {
                        minDist = Math.min(minDist, j - i);
                        break;
                    }
                }
            }
        }

        return minDist == Integer.MAX_VALUE ? -1 : minDist;
    }

    public static void main(String[] args) {
        int[] test1 = {1, 0, 2};    // -> 2
        int[] test2 = {1, 1, 2};    // -> 1
        int[] test3 = {1, 0, 0, 2}; // -> 3
        int[] test4 = {2, 0, 1};    // -> 2
        int[] test5 = {1, 0, 0, 1}; // -> -1

        System.out.println(minDistance(test1));
        System.out.println(minDistance(test2));
        System.out.println(minDistance(test3));
        System.out.println(minDistance(test4));
        System.out.println(minDistance(test5));
    }
}

leftmax and rightmax arr, O(N) 0(N)

import java.util.*;

class CakeDistance {
    public int minDistance(int[] arr) {
        int n = arr.length;
        int[] leftTwoDist = new int[n];
        int[] rightTwoDist = new int[n];

        // 初始化
        for (int i = 0; i < n; i++) {
            leftTwoDist[i] = Integer.MAX_VALUE;
            rightTwoDist[i] = Integer.MAX_VALUE;
        }

        // 从左向右扫,记录左边最近的2的 index 差值
        int lastTwo = -1;
        for (int i = 0; i < n; i++) {
            if (arr[i] == 2) {
                lastTwo = i;
            }
            if (lastTwo != -1) {
                leftTwoDist[i] = i - lastTwo;
            }
        }

        // 从右向左扫,记录右边最近的2的 index 差值
        lastTwo = -1;
        for (int i = n - 1; i >= 0; i--) {
            if (arr[i] == 2) {
                lastTwo = i;
            }
            if (lastTwo != -1) {
                rightTwoDist[i] = lastTwo - i;
            }
        }

        // 对每个 1,取左右距离的较小值
        int minDist = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                int closest = Math.min(leftTwoDist[i], rightTwoDist[i]);
                minDist = Math.min(minDist, closest);
            }
        }

        return minDist == Integer.MAX_VALUE ? -1 : minDist;
    }

}

public class Solution {
    // Sample test runs
    public static void main(String[] args) {
        CakeDistance cd = new CakeDistance();
        int[] test1 = {1, 0, 2};    // -> 2
        int[] test2 = {1, 1, 2};    // -> 1
        int[] test3 = {1, 0, 0, 2}; // -> 3
        int[] test4 = {2, 0, 1};    // -> 2
        int[] test5 = {1, 0, 0, 1}; // -> -1

        System.out.println(cd.minDistance(test1));
        System.out.println(cd.minDistance(test2));
        System.out.println(cd.minDistance(test3));
        System.out.println(cd.minDistance(test4));
        System.out.println(cd.minDistance(test5));
    }
}

O(n) o(1)

  • 一边从左往右扫,维护“当前最近的左边蛋糕的位置”,每当遇到 1 就记录 i - leftCake

  • 同样从右往左扫,维护“当前最近的右边蛋糕位置”,每当遇到 1 就记录 rightCake - i

  • 两个 pass 中每次遇到 1 就更新最小距离(minDist)。

public class CakeDistance {
    public static int minDistance(int[] arr) {
        int n = arr.length;
        int minDist = Integer.MAX_VALUE;

        // 从左往右扫描
        int lastCake = -1;
        for (int i = 0; i < n; i++) {
            if (arr[i] == 2) {
                lastCake = i;
            } else if (arr[i] == 1 && lastCake != -1) {
                minDist = Math.min(minDist, i - lastCake);
            }
        }

        // 从右往左扫描
        lastCake = -1;
        for (int i = n - 1; i >= 0; i--) {
            if (arr[i] == 2) {
                lastCake = i;
            } else if (arr[i] == 1 && lastCake != -1) {
                minDist = Math.min(minDist, lastCake - i);
            }
        }

        return minDist == Integer.MAX_VALUE ? -1 : minDist;
    }

    public static void main(String[] args) {
        int[] test1 = {1, 0, 2};    // -> 2
        int[] test2 = {1, 1, 2};    // -> 1
        int[] test3 = {1, 0, 0, 2}; // -> 3
        int[] test4 = {2, 0, 1};    // -> 2
        int[] test5 = {1, 0, 0, 1}; // -> -1
        int[] test6 = {2, 0, 2, 0, 1}; // -> 1 (1 最近的是 index 2 的蛋糕)

        System.out.println(minDistance(test1));
        System.out.println(minDistance(test2));
        System.out.println(minDistance(test3));
        System.out.println(minDistance(test4));
        System.out.println(minDistance(test5));
        System.out.println(minDistance(test6));
    }
}

012 cake - count 0

brute

public class CakeDistance {
    public static int minDistance(int[] arr) {
        int n = arr.length;
        int minDist = Integer.MAX_VALUE;

        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                // 向左找
                int leftZeros = 0;
                for (int j = i - 1; j >= 0; j--) {
                    if (arr[j] == 0) {
                        leftZeros++;
                    } else if (arr[j] == 2) {
                        minDist = Math.min(minDist, leftZeros);
                        break;
                    } else {
                        leftZeros++; // 遇到 1 也继续,只是不计作蛋糕
                    }
                }

                // 向右找
                int rightZeros = 0;
                for (int j = i + 1; j < n; j++) {
                    if (arr[j] == 0) {
                        rightZeros++;
                    } else if (arr[j] == 2) {
                        minDist = Math.min(minDist, rightZeros);
                        break;
                    } else {
                        rightZeros++;
                    }
                }
            }
        }

        return minDist == Integer.MAX_VALUE ? -1 : minDist;
    }
}

ON ON

public class Solution {
    public static int minDistance(int[] arr) {
        int n = arr.length;

        int[] leftZeroDist = new int[n];
        int[] rightZeroDist = new int[n];

        // 初始化为 INF
        for (int i = 0; i < n; i++) {
            leftZeroDist[i] = Integer.MAX_VALUE;
            rightZeroDist[i] = Integer.MAX_VALUE;
        }

        // 左 -> 右:遇到蛋糕后开始记 0 数
        int zeroCount = 0;
        boolean seenCake = false;
        for (int i = 0; i < n; i++) {
            if (arr[i] == 2) {
                zeroCount = 0;
                seenCake = true;
            } else if (arr[i] == 0 && seenCake) {
                zeroCount++;
            } else if (arr[i] == 1 && seenCake) {
                leftZeroDist[i] = zeroCount;
            }
        }

        // 右 -> 左:同样处理
        zeroCount = 0;
        seenCake = false;
        for (int i = n - 1; i >= 0; i--) {
            if (arr[i] == 2) {
                zeroCount = 0;
                seenCake = true;
            } else if (arr[i] == 0 && seenCake) {
                zeroCount++;
            } else if (arr[i] == 1 && seenCake) {
                rightZeroDist[i] = zeroCount;
            }
        }

        // 计算每个 1 到最近蛋糕的最小 0 数量
        int minDist = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                int d = Math.min(leftZeroDist[i], rightZeroDist[i]);
                minDist = Math.min(minDist, d);
            }
        }

        return minDist == Integer.MAX_VALUE ? -1 : minDist;
    }

    public static void main(String[] args) {
        int[] test1 = {1, 0, 2};    // -> 1
        int[] test2 = {1, 1, 2};    // -> 0
        int[] test3 = {1, 0, 0, 2}; // -> 2
        int[] test4 = {2, 0, 1};    // -> 1
        int[] test5 = {1, 0, 0, 1}; // -> -1

        System.out.println(minDistance(test1));
        System.out.println(minDistance(test2));
        System.out.println(minDistance(test3));
        System.out.println(minDistance(test4));
        System.out.println(minDistance(test5));
    }
}

ON O1

两次遍历:

第一次从左往右:每遇到 1,从当前位置向右找第一个 2,数中间的 0 的个数。

第二次从右往左:每遇到 1,从当前位置向左找第一个 2,数中间的 0 的个数。

每次更新最小值。

由于是顺着方向找一次蛋糕就 break,所以虽然是嵌套循环,总体是 O(n)(每个元素只参与一次匹配)。

public class CakeDistance {
    public static int minZeroDistance(int[] arr) {
        int n = arr.length;
        int minDist = Integer.MAX_VALUE;

        // 从左往右找:遇到 1,向右找最近的 2,数 0
        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                int zeroCount = 0;
                for (int j = i + 1; j < n; j++) {
                    if (arr[j] == 0) {
                        zeroCount++;
                    } else if (arr[j] == 2) {
                        minDist = Math.min(minDist, zeroCount);
                        break;
                    } else {
                        // 遇到 1 也继续,但不计数
                    }
                }
            }
        }

        // 从右往左找:遇到 1,向左找最近的 2,数 0
        for (int i = n - 1; i >= 0; i--) {
            if (arr[i] == 1) {
                int zeroCount = 0;
                for (int j = i - 1; j >= 0; j--) {
                    if (arr[j] == 0) {
                        zeroCount++;
                    } else if (arr[j] == 2) {
                        minDist = Math.min(minDist, zeroCount);
                        break;
                    }
                }
            }
        }

        return minDist == Integer.MAX_VALUE ? -1 : minDist;
    }

    public static void main(String[] args) {
        int[] test1 = {1, 0, 2};        // -> 1
        int[] test2 = {1, 1, 2};        // -> 0
        int[] test3 = {1, 0, 0, 2};     // -> 2
        int[] test4 = {2, 0, 1};        // -> 1
        int[] test5 = {1, 0, 0, 1};     // -> -1
        int[] test6 = {1, 0, 1, 0, 2};  // -> 2

        System.out.println(minZeroDistance(test1));
        System.out.println(minZeroDistance(test2));
        System.out.println(minZeroDistance(test3));
        System.out.println(minZeroDistance(test4));
        System.out.println(minZeroDistance(test5));
        System.out.println(minZeroDistance(test6));
    }
}

check win

class Solution {

    public boolean checkWin(char[][] board, int row, int col, char player, int K) {
        int m = board.length;
        int n = board[0].length;
        
        // Define the four directions: horizontal, vertical, diagonal, anti-diagonal.
        // Each direction is represented as a pair: {rowDelta, colDelta}
        int[][] directions = {
            {0, 1},  // Horizontal: right
            {1, 0},  // Vertical: down
            {1, 1},  // Diagonal: down-right
            {1, -1}  // Anti-diagonal: down-left
        };

        // For each direction, count consecutive symbols in both directions.
        for (int[] dir : directions) {
            int count = 1;  // count the current cell
            
            // Check in the "positive" direction
            int r = row + dir[0], c = col + dir[1];
            while (r >= 0 && r < m && c >= 0 && c < n && board[r][c] == player) {
                count++;
                r += dir[0];
                c += dir[1];
            }
            
            // Check in the "negative" direction
            r = row - dir[0];
            c = col - dir[1];
            while (r >= 0 && r < m && c >= 0 && c < n && board[r][c] == player) {
                count++;
                r -= dir[0];
                c -= dir[1];
            }
            
            // If we have at least K in a row, we have a winner.
            if (count >= K) {
                return true;
            }
        }
        return false;
    }
    
    // Example usage:
    public static void main(String[] args) {
        char[][] board = {
            {'A', '.', '.', '.'},
            {'.', 'A', '.', '.'},
            {'.', '.', 'A', '.'},
            {'.', '.', '.', '.'}
        };
        int K = 4;
        int row = 3, col = 3; // Let's say player A makes a move at (3, 3)
        board[row][col] = 'A';
        
        Solution checker = new Solution();
        boolean win = checker.checkWin(board, row, col, 'A', K);
        System.out.println("Winning move? " + win); // should output true if move wins
    }
}

perfect tree

public static class TreeNode {
      TreeNode left;
      TreeNode right;
      int val;
      TreeNode() {}
      TreeNode(int val) {
          this.val = val;
      }
  }

  public static TreeNode buildPerfectTree(TreeNode root) {
      if (root == null) return root;
      Queue<TreeNode> queue = new LinkedList<>();
      queue.offer(root);
      int level = 0;
      int height = 0;
      boolean flag = false;
      while (!queue.isEmpty()) {
          int desired = (int) Math.pow(2, level);
          int size = queue.size();
          // missing > present
          int missing = desired - size;
          if (missing > size) {
              height = level;
              flag = true;
              break;
          }
          for (int i = 0; i < size; i++) {
              TreeNode node = queue.poll();
              if (node.left != null) {
                  queue.add(node.left);
              }
              if (node.right != null) {
                  queue.add(node.right);
              }
          }
          level++;
      }

      // means the tree is perfect OR we only fill up the leafs
      if (!flag) {
        height = level - 1;
      }


      queue.clear();
      
      TreeNode newRoot = new TreeNode();
      queue.offer(newRoot);
      int count = 0;
      while (!queue.isEmpty()) {
        if (count == height) {
          break;
        }
        int size = queue.size();
        for (int i = 0; i < size; i++) {
          TreeNode node = queue.poll();
          node.left = new TreeNode();
          node.right = new TreeNode();
          queue.offer(node.left);
          queue.offer(node.right);
        }
        count++;
      }
      

      return newRoot;
  }

json

import java.util.*;

class Solution {

    static int i; // Global index to traverse the input

    public static String parseJson2(String input) {
        i = 0;
        return parseHelper(input);
    }

    // Helper to check if current character is a digit
    private static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

    // Parse an array and return it as a stringified list
    private static String parseArray(String input) {
        List<String> res = new ArrayList<>();
        i++; // Skip '['

        while (input.charAt(i) != ']') {
            if (input.charAt(i) == ',') {
                i++; // Skip comma
            }
            res.add(parseHelper(input));
        }

        i++; // Skip closing ']'
        return "[" + String.join(", ", res) + "]";
    }

    // Parses a string with escape handling and returns it without quotes
    private static String parseString(String input) {
        StringBuilder sb = new StringBuilder();
        i++; // Skip opening quote

        while (i < input.length()) {
            char c = input.charAt(i);
            
            // if char is \
            if (c == '\\') {
                i++;
                if (i >= input.length()) break;
                char next = input.charAt(i);

                if (next == '"' || next == '\\') {
                    sb.append(next); // Valid escapes: \" or \\
                } else {
                    // Ignore invalid escapes
                }
            } else if (c == '"') {
                i++; // End of string
                break;
            } else {
                sb.append(c);
            }

            i++;
        }

        return sb.toString();
    }

    // Parse number (non-negative integer) and return as String
    private static String parseNumber(String input) {
        int start = i;
        while (i < input.length() && isNumber(input.charAt(i))) {
            i++;
        }
        return String.valueOf(Long.parseLong(input.substring(start, i)));
    }

    // Main recursive helper that checks the type of the current token
    private static String parseHelper(String input) {
        char c = input.charAt(i);

        if (c == '[') {
            return parseArray(input);
        } else if (c == '"') {
            return parseString(input);
        } else {
            return parseNumber(input);
        }
    }

    // Main method for testing
    public static void main(String[] args) {
        String test1 = "[9876543321,[5,[0,1]]]";
        String test2 = "[[\"avx\\\"\",123],[0412]]";

        System.out.println(parseJson2(test1));  // Output: [9876543321, [5, [0, 1]]]
        System.out.println(parseJson2(test2));  // Output: [[avx", 123], [412]]
    }
}