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]]
}
}