Thursday, January 31, 2019
248. Strobogrammatic Number III
21.52 %
class Solution {
public int strobogrammaticInRange(String low, String high) {
// 1 1
// 6 9
// 8 8
// 9 6
// 0 0
int start = low.length(), end = high.length();
List<String> rawResult = new ArrayList<>();
for (int i = start; i <= end; i++) {
rawResult.addAll(helper(i));
List<String> curr = helper(i);
}
int count = 0;
for (String str : rawResult) {
if ((str.length() > 1 && str.charAt(0) == '0')
|| (str.length() == low.length() && str.compareTo(low) < 0)
|| (str.length() == high.length() && str.compareTo(high) > 0)) continue;
count++;
}
return count;
}
private List<String> helper(int len) {
if (len == 0) return Arrays.asList(new String[]{""});
if (len == 1) return Arrays.asList(new String[]{"0", "1", "8"});
List<String> result = new ArrayList<>();
List<String> center = helper(len - 2);
for (String cen : center) {
result.add("1" + cen + "1");
result.add("6" + cen + "9");
result.add("8" + cen + "8");
result.add("9" + cen + "6");
result.add("0" + cen + "0");
}
return result;
}
}
150. Evaluate Reverse Polish Notation
Version #1 Stack
15.27 %
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < tokens.length; i++) {
String curr = tokens[i];
if (curr.equals("+") || curr.equals("-") || curr.equals("*") || curr.equals("/")) {
int operand2 = stack.pop();
int operand1 = stack.pop();
int res = 0;
switch (curr) {
case "+":
res = operand1 + operand2;
break;
case "-":
res = operand1 - operand2;
break;
case "*":
res = operand1 * operand2;
break;
case "/":
res = operand1 / operand2;
}
stack.push(res);
} else {
stack.push(Integer.valueOf(curr));
}
}
return stack.pop();
}
}
Wednesday, January 30, 2019
115. Distinct Subsequences
Version #1 DP
1st row must be 1s because we are using s to match empty string
and an empty string is the subsequence of any string
10.00 %
class Solution {
public int numDistinct(String s, String t) {
// dp[i][j] -> number of ways to match s.substring[0, i) with t.substring[0, j)
// if (s.charAt(i - 1) == t.charAt(j - 1))
// dp[i][j] += for all k, s.charAt(k - 1) == t.charAt(j - 2)
// if j == 1, dp[i][j] = 1
int[][] dp = new int[s.length() + 1][t.length() + 1];
for (int i = 0; i <= s.length(); i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= s.length(); i++) {
for (int j = 1; j <= t.length(); j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
// use or not use
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j]; // cannot use
}
}
}
return dp[s.length()][t.length()];
}
}
1st row must be 1s because we are using s to match empty string
and an empty string is the subsequence of any string
10.00 %
class Solution {
public int numDistinct(String s, String t) {
// dp[i][j] -> number of ways to match s.substring[0, i) with t.substring[0, j)
// if (s.charAt(i - 1) == t.charAt(j - 1))
// dp[i][j] += for all k, s.charAt(k - 1) == t.charAt(j - 2)
// if j == 1, dp[i][j] = 1
int[][] dp = new int[s.length() + 1][t.length() + 1];
for (int i = 0; i <= s.length(); i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= s.length(); i++) {
for (int j = 1; j <= t.length(); j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
// use or not use
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j]; // cannot use
}
}
}
return dp[s.length()][t.length()];
}
}
918. Maximum Sum Circular Subarray
Bug
One** corner case** to pay attention:
If all number are negative,
return the maximum one,
(which equals to the max subarray sum)
If the maximum sum is negative, means all numbers are negative
In this case, total sum is the minimum one -> total sum - min sum = 0, which is not a valid subarray
So when maxSum < 0, return maxSum
21.88 %
class Solution {
public int maxSubarraySumCircular(int[] A) {
// max subarray sum, min suarray sum
// result = Math.max(max, totalSum - min)
if (A == null || A.length == 0) return 0;
int prevMin = A[0], prevMax = A[0]; // min/max subarray sum end with i-1
int sum = A[0], max = A[0], min = A[0];
for (int i = 1; i < A.length; i++) {
sum += A[i];
int currMin = Math.min(prevMin, 0) + A[i];
int currMax = Math.max(prevMax, 0) + A[i];
max = Math.max(max, currMax);
min = Math.min(min, currMin);
prevMin = currMin;
prevMax = currMax;
}
return max > 0 ? Math.max(max, sum - min) : max;
}
}
152. Maximum Product Subarray
Version #1 Optimized DP
是一个dp题,对于乘法来说情况比较特殊,因为有负数
如果一个绝对值非常大的负数再乘一个负数,负负得正,有产生最大值的可能
所以要同时keep track of dpMin 以及dpMax
更新dp的时候要考虑也可是nums[i] 单独成为最大或者最小
70.82 %
class Solution {
public int maxProduct(int[] nums) {
// pos[i] -> maxProduct ends with current nums[i]
// neg[i] -> minProduct ends with current nums[i]
// pos[i] = Math.max(nums[i], Math.max(post[i - 1] * nums[i], neg[i - 1] * nums[i]));
// neg[i] = Math.min(nums[i], Math.min(post[i - 1] * nums[i], neg[i - 1] * nums[i]));
int result = Integer.MIN_VALUE;
int pos = 1, neg = 1;
for (int i = 0; i < nums.length; i++) {
int currPos = Math.max(nums[i], Math.max(pos * nums[i], neg * nums[i]));
int currNeg = Math.min(nums[i], Math.min(pos * nums[i], neg * nums[i]));
pos = currPos;
neg = currNeg;
result = Math.max(pos, result);
}
return result;
}
}
是一个dp题,对于乘法来说情况比较特殊,因为有负数
如果一个绝对值非常大的负数再乘一个负数,负负得正,有产生最大值的可能
所以要同时keep track of dpMin 以及dpMax
更新dp的时候要考虑也可是nums[i] 单独成为最大或者最小
70.82 %
class Solution {
public int maxProduct(int[] nums) {
// pos[i] -> maxProduct ends with current nums[i]
// neg[i] -> minProduct ends with current nums[i]
// pos[i] = Math.max(nums[i], Math.max(post[i - 1] * nums[i], neg[i - 1] * nums[i]));
// neg[i] = Math.min(nums[i], Math.min(post[i - 1] * nums[i], neg[i - 1] * nums[i]));
int result = Integer.MIN_VALUE;
int pos = 1, neg = 1;
for (int i = 0; i < nums.length; i++) {
int currPos = Math.max(nums[i], Math.max(pos * nums[i], neg * nums[i]));
int currNeg = Math.min(nums[i], Math.min(pos * nums[i], neg * nums[i]));
pos = currPos;
neg = currNeg;
result = Math.max(pos, result);
}
return result;
}
}
Tuesday, January 29, 2019
780. Reaching Points
Follow up:
What if any x, y can be negative
对source的正负号进行分类讨论, 如果同号,则可以转化成原题
因为如果source的xy value同负,那么target也只能是负的
所以最后只需要讨论xy异号的情况, 易知由于xy异号所以abs(x + y) will always become closer to zero
所以我们尝试枚举出所有这样的情况直到xy同号,然后问题退化成原问题
95.45 %
class Solution {
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
// all sx,sy,tx,ty are larger than zero
// if (tx > ty) -> it can only be generated from (tx - ty, ty)
// we can keep subtract ty from tx until tx < ty
// new tx = tx - kty = tx % ty
while (tx > sx && ty > sy) {
if (tx > ty) {
tx = tx % ty;
} else {
ty = ty % tx;
}
}
return tx == sx && (ty - sy) % tx == 0 ||
ty == sy && (tx - sx) % ty == 0;
}
}
What if any x, y can be negative
对source的正负号进行分类讨论, 如果同号,则可以转化成原题
因为如果source的xy value同负,那么target也只能是负的
所以最后只需要讨论xy异号的情况, 易知由于xy异号所以abs(x + y) will always become closer to zero
所以我们尝试枚举出所有这样的情况直到xy同号,然后问题退化成原问题
95.45 %
class Solution {
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
// all sx,sy,tx,ty are larger than zero
// if (tx > ty) -> it can only be generated from (tx - ty, ty)
// we can keep subtract ty from tx until tx < ty
// new tx = tx - kty = tx % ty
while (tx > sx && ty > sy) {
if (tx > ty) {
tx = tx % ty;
} else {
ty = ty % tx;
}
}
return tx == sx && (ty - sy) % tx == 0 ||
ty == sy && (tx - sx) % ty == 0;
}
}
Sunday, January 27, 2019
337. House Robber III
三刷 07/2022
Version #2 Bottom up DFS
Time O(N)
Space O(H) - height of the tree, worst O(N)
Runtime: 1 ms, faster than 92.27% of Java online submissions for House Robber III.
Memory Usage: 44.8 MB, less than 29.44% of Java online submissions for House Robber III.
class Solution {
public int rob(TreeNode root) {
int[] result = robHelper(root);
return Math.max(result[0], result[1]);
}
private int[] robHelper(TreeNode node) {
int[] result = new int[2];
if (node == null) {
return result;
}
int[] left = robHelper(node.left);
int[] right = robHelper(node.right);
result[0] = node.val + left[1] + right[1];
result[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return result;
}
}
Version #2 Bottom up DFS
我们return一个int[]表示rob current node/ not rob current node两个结果
每个node保证只visited一次
Time O(N)
一刷
Version #1 DFS
67.32 %
class Solution {
public int rob(TreeNode root) {
Map<TreeNode, Integer> map = new HashMap<>();
return dfs(root, map);
}
private int dfs(TreeNode node, Map<TreeNode, Integer> map) {
// max amount of money we can get if we enter through this node
if (node == null) {
return 0;
}
if (map.containsKey(node)) return map.get(node);
// if we rob this node, then we can't rob any of its child node
int curr = node.val;
if (node.left != null) {
curr += dfs(node.left.left, map) + dfs(node.left.right, map);
}
if (node.right != null) {
curr += dfs(node.right.left, map) + dfs(node.right.right, map);
}
curr = Math.max(curr, dfs(node.left, map) + dfs(node.right, map));
map.put(node, curr);
return curr;
}
}
Space - depth of the stack, O(N) worst, O(logN) best
Runtime: 0 ms, faster than 100.00% of Java online submissions for House Robber III.
Memory Usage: 41.5 MB, less than 98.09% of Java online submissions for House Robber III.
class Solution {
public int rob(TreeNode root) {
// For each node, return two values - int[0] max if rob the house, int[1] max of the children no matter rob or not rob
int[] res = robHelper(root);
return Math.max(res[0], res[1]);
}
private int[] robHelper(TreeNode node) {
if (node == null) {
return new int[]{0, 0};
}
// leaf
if (node.left == null && node.right == null) {
return new int[]{node.val, 0};
}
int[] left = robHelper(node.left);
int[] right = robHelper(node.right);
// if we rob the house, then we cannot rob it's children
int curr = node.val + left[1] + right[1];
// if not rob, we are free to choose rob the children or not
int children = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return new int[]{curr, children};
}
}
一刷
Version #1 DFS
67.32 %
class Solution {
public int rob(TreeNode root) {
Map<TreeNode, Integer> map = new HashMap<>();
return dfs(root, map);
}
private int dfs(TreeNode node, Map<TreeNode, Integer> map) {
// max amount of money we can get if we enter through this node
if (node == null) {
return 0;
}
if (map.containsKey(node)) return map.get(node);
// if we rob this node, then we can't rob any of its child node
int curr = node.val;
if (node.left != null) {
curr += dfs(node.left.left, map) + dfs(node.left.right, map);
}
if (node.right != null) {
curr += dfs(node.right.left, map) + dfs(node.right.right, map);
}
curr = Math.max(curr, dfs(node.left, map) + dfs(node.right, map));
map.put(node, curr);
return curr;
}
}
983. Minimum Cost For Tickets
二刷 07/2022
Version #1 DP
感觉这题有点难,想了很久想不出来
看了一刷的答案感觉一刷写的更好 用了一个pointer for days
一开始写了bug就是只有当i >= 7的时候才检查min,这种情况在7日票价低于1日票价的时候是有错误的
Time O(D) - D = 365
Space O(D) - D = 365
Runtime: 6 ms, faster than 17.80% of Java online submissions for Minimum Cost For Tickets.
Memory Usage: 42.4 MB, less than 33.67% of Java online submissions for Minimum Cost For Tickets.
class Solution {
public int mincostTickets(int[] days, int[] costs) {
Set<Integer> daySet = new HashSet<>();
for (int d : days) {
daySet.add(d);
}
// The min cost to cover travel until day i
int[] dp = new int[366];
for (int i = 1; i <= 365; i++) {
if (!daySet.contains(i)) {
dp[i] = dp[i - 1];
} else {
dp[i] = dp[i - 1] + costs[0];
dp[i] = Math.min(dp[i], (i >= 7 ? dp[i - 7] : 0) + costs[1]);
dp[i] = Math.min(dp[i], (i >= 30 ? dp[i - 30] : 0) + costs[2]);
}
}
return dp[365];
}
}
一刷
Version #1 DP100.00 %
class Solution {
public int mincostTickets(int[] days, int[] costs) {
// dp[i] - minimum cost to travel to day i
int[] dp = new int[366];
int daysIndex = 0;
// Easy to know that dp[i] >= dp[j] when i > j
for (int i = 1; i <= 365; i++) {
if (daysIndex >= days.length || days[daysIndex] != i) {
dp[i] = dp[i - 1];
} else {
daysIndex++;
dp[i] = Math.min(dp[Math.max(0, i - 1)] + costs[0],
Math.min(dp[Math.max(0, i - 7)] + costs[1],
dp[Math.max(0, i - 30)] + costs[2]));
}
}
return dp[365];
}
}
982. Triples with Bitwise AND Equal To Zero
Version #1 DP
37.50 %
class Solution {
public int countTriplets(int[] A) {
int N = 1 << 16;
int[] dp = new int[N];
for (int a : A) {
dp[a] += 1;
}
for (int i = 0; i < 2; i++) {
int[] temp = new int[N];
for (int k = 0; k < N; k++) {
for (int a : A) {
temp[k & a] += dp[k];
}
}
dp = temp;
}
return dp[0];
}
}
Saturday, January 26, 2019
556. Next Greater Element III
96.55 %
class Solution {
public int nextGreaterElement(int n) {
char[] chars = String.valueOf(n).toCharArray();
int i = 0;
for (i = chars.length - 1; i > 0; i--) {
if (chars[i] > chars[i - 1]) break;
}
int nextLargerDigit = i;
if (i != 0) {
for (int j = chars.length - 1; j > i; j--) {
if (chars[j] > chars[i - 1] && chars[j] < chars[nextLargerDigit]) {
nextLargerDigit = j;
}
}
char temp = chars[i - 1];
chars[i - 1] = chars[nextLargerDigit];
chars[nextLargerDigit] = temp;
Arrays.sort(chars, i, chars.length);
} else {
return -1;
}
long result = Long.valueOf(new String(chars));
return result > Integer.MAX_VALUE ? -1 : (int) result;
}
}
Tuesday, January 22, 2019
249. Group Shifted Strings
3.04 %
public List<List<String>> groupStrings(String[] strings) {
Map<String, List<String>> map = new HashMap<>();
for (String str : strings) {
map.computeIfAbsent(normalize(str), list -> new ArrayList<>()).add(str);
}
List<List<String>> result = new ArrayList<>();
for (List<String> list : map.values()) {
result.add(list);
}
return result;
}
private String normalize(String s) {
int offset = (int)(s.charAt(0) - 'a');
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
sb.append((char) ('a' + ((s.charAt(i) - offset + 26) % 26)));
}
// System.out.println(sb.toString());
return sb.toString();
}
616. Add Bold Tag in String
Version #1 Merge Intervals
13.51 %
class Solution {
public String addBoldTag(String s, String[] dict) {
// [interval[0], interval[1])
List<int[]> intervals = new ArrayList<>();
for (String word : dict) {
int start = 0;
while (start >= 0) {
start = s.indexOf(word, start);
if (start == -1) {
break;
}
intervals.add(new int[]{start, start + word.length()});
start++;
}
}
Collections.sort(intervals, Comparator.comparing(a -> a[0])); // only compare the start index
int i = 0;
List<int[]> merged = new ArrayList<>();
while (i < intervals.size()) {
int[] curr = intervals.get(i);
while (i < intervals.size() - 1 && intervals.get(i + 1)[0] <= curr[1]) {
curr[1] = Math.max(curr[1], intervals.get(i + 1)[1]);
i++;
}
merged.add(curr);
i++;
}
StringBuilder sb = new StringBuilder();
int prev = 0;
for (int[] interval : merged) {
sb.append(s.substring(prev, interval[0])).append("<b>").append(s.substring(interval[0], interval[1])).append("</b>");
prev = interval[1];
}
sb.append(s.substring(prev));
return sb.toString();
}
}
13.51 %
class Solution {
public String addBoldTag(String s, String[] dict) {
// [interval[0], interval[1])
List<int[]> intervals = new ArrayList<>();
for (String word : dict) {
int start = 0;
while (start >= 0) {
start = s.indexOf(word, start);
if (start == -1) {
break;
}
intervals.add(new int[]{start, start + word.length()});
start++;
}
}
Collections.sort(intervals, Comparator.comparing(a -> a[0])); // only compare the start index
int i = 0;
List<int[]> merged = new ArrayList<>();
while (i < intervals.size()) {
int[] curr = intervals.get(i);
while (i < intervals.size() - 1 && intervals.get(i + 1)[0] <= curr[1]) {
curr[1] = Math.max(curr[1], intervals.get(i + 1)[1]);
i++;
}
merged.add(curr);
i++;
}
StringBuilder sb = new StringBuilder();
int prev = 0;
for (int[] interval : merged) {
sb.append(s.substring(prev, interval[0])).append("<b>").append(s.substring(interval[0], interval[1])).append("</b>");
prev = interval[1];
}
sb.append(s.substring(prev));
return sb.toString();
}
}
Monday, January 21, 2019
935. Knight Dialer
Version #1 DP
71.11 %
class Solution {
public int knightDialer(int N) {
int[][] map = new int[][]{{4, 6}, {6, 8}, {7, 9}, {4, 8}, {3, 9, 0}, {}, {1, 7, 0}, {2, 6}, {1, 3}, {2, 4}};
int[] prev = new int[10];
int mod = (int)(1e9 + 7);
Arrays.fill(prev, 1);
for (int i = 2; i <= N; i++) {
int[] curr = new int[10];
for (int x = 0; x <= 9; x++) {
for (int last : map[x]) {
curr[x] = (curr[x] + prev[last]) % mod;
}
}
prev = curr;
}
int sum = 0;
for (int i = 0; i <= 9; i++) {
sum = (sum + prev[i]) % mod;
}
return sum;
}
}
71.11 %
class Solution {
public int knightDialer(int N) {
int[][] map = new int[][]{{4, 6}, {6, 8}, {7, 9}, {4, 8}, {3, 9, 0}, {}, {1, 7, 0}, {2, 6}, {1, 3}, {2, 4}};
int[] prev = new int[10];
int mod = (int)(1e9 + 7);
Arrays.fill(prev, 1);
for (int i = 2; i <= N; i++) {
int[] curr = new int[10];
for (int x = 0; x <= 9; x++) {
for (int last : map[x]) {
curr[x] = (curr[x] + prev[last]) % mod;
}
}
prev = curr;
}
int sum = 0;
for (int i = 0; i <= 9; i++) {
sum = (sum + prev[i]) % mod;
}
return sum;
}
}
421. Maximum XOR of Two Numbers in an Array
Version #1 PrefixTrie + DFS
We are passing two nodes into dfs simultaneously, if we can choose branch of different value, we choose. Otherwise choose the same value
95.05 %
class Solution {
class TrieNode {
TrieNode[] children;
public TrieNode() {
children = new TrieNode[2];
}
}
public int findMaximumXOR(int[] nums) {
TrieNode root = new TrieNode();
for (int num : nums) {
insert(root, num);
}
return dfs(root.children[0], root.children[1] == null ? root.children[0] : root.children[1], 0);
}
private int dfs(TrieNode left, TrieNode right, int diff) {
TrieNode left0 = left.children[0], left1 = left.children[1];
TrieNode right0 = right.children[0], right1 = right.children[1];
if (left0 == null && left1 == null) {
return diff;
} else if (left0 != null && left1 != null && right0 != null && right1 != null) {
return Math.max(dfs(left0, right1, (diff << 1) + 1), dfs(left1, right0, (diff << 1) + 1));
} else if (left0 != null && right1 != null) {
return dfs(left0, right1, (diff << 1) + 1);
} else if (left1 != null && right0 != null) {
return dfs(left1, right0, (diff << 1) + 1);
} else if (left0 != null && right0 != null){
return dfs(left0, right0, (diff << 1));
} else if (left1 != null && right1 != null) {
return dfs(left1, right1, (diff << 1));
}
return 0;
}
private void insert(TrieNode root, int num) {
TrieNode curr = root;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
if (curr.children[bit] == null) {
curr.children[bit] = new TrieNode();
}
curr = curr.children[bit];
}
}
}
We are passing two nodes into dfs simultaneously, if we can choose branch of different value, we choose. Otherwise choose the same value
95.05 %
class Solution {
class TrieNode {
TrieNode[] children;
public TrieNode() {
children = new TrieNode[2];
}
}
public int findMaximumXOR(int[] nums) {
TrieNode root = new TrieNode();
for (int num : nums) {
insert(root, num);
}
return dfs(root.children[0], root.children[1] == null ? root.children[0] : root.children[1], 0);
}
private int dfs(TrieNode left, TrieNode right, int diff) {
TrieNode left0 = left.children[0], left1 = left.children[1];
TrieNode right0 = right.children[0], right1 = right.children[1];
if (left0 == null && left1 == null) {
return diff;
} else if (left0 != null && left1 != null && right0 != null && right1 != null) {
return Math.max(dfs(left0, right1, (diff << 1) + 1), dfs(left1, right0, (diff << 1) + 1));
} else if (left0 != null && right1 != null) {
return dfs(left0, right1, (diff << 1) + 1);
} else if (left1 != null && right0 != null) {
return dfs(left1, right0, (diff << 1) + 1);
} else if (left0 != null && right0 != null){
return dfs(left0, right0, (diff << 1));
} else if (left1 != null && right1 != null) {
return dfs(left1, right1, (diff << 1));
}
return 0;
}
private void insert(TrieNode root, int num) {
TrieNode curr = root;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
if (curr.children[bit] == null) {
curr.children[bit] = new TrieNode();
}
curr = curr.children[bit];
}
}
}
Saturday, January 19, 2019
448. Find All Numbers Disappeared in an Array
69.09 %
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
// If we see this number, we mark the number that at this index as negative
for (int i = 0; i < nums.length; i++) {
int index = Math.abs(nums[i]) - 1;
if (nums[index] > 0) {
nums[index] = -nums[index];
}
}
List<Integer> result = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) {
result.add(i + 1);
}
}
return result;
}
}
463. Island Perimeter
86.10 %
class Solution {
public int islandPerimeter(int[][] grid) {
// try to add 4 edges to each node
// if there are to node connect to each other, then 2 edges should be subtracted
int result = 0;
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0;
for (int y = 0; y < grid.length; y++) {
for (int x = 0; x < grid[0].length; x++) {
if (grid[y][x] == 1) {
result += 4;
if (y + 1 < grid.length && grid[y + 1][x] == 1) {
result -= 2;
}
if (x + 1 < grid[0].length && grid[y][x + 1] == 1) {
result -= 2;
}
}
}
}
return result;
}
}
657. Robot Return to Origin
91.43 %
class Solution {
public boolean judgeCircle(String moves) {
int y = 0;
int x = 0;
for (int i = 0; i < moves.length(); i++) {
char c = moves.charAt(i);
if (c == 'U') {
y--;
} else if (c == 'D') {
y++;
} else if (c == 'L') {
x--;
} else {
x++;
}
}
return x == 0 && y == 0;
}
}
972. Equal Rational Numbers
68.52 %
class Solution {
public boolean isRationalEqual(String S, String T) {
return Double.valueOf(normalize(S)).compareTo(
Double.valueOf(normalize(T))) == 0;
}
private String normalize(String s) {
int index = s.indexOf("(");
String result = s;
if (index > 0) {
result = s.substring(0, index);
for (int i = 0; i < 20; i++) {
result += s.substring(index + 1, s.length() - 1);
}
}
return result;
}
}
958. Check Completeness of a Binary Tree
Version #2 BFS[TODO]
Version #1 DFS
98.36
class Solution {
int count;
public boolean isCompleteTree(TreeNode root) {
count = getCount(root);
return validate(root, 1);
}
private boolean validate(TreeNode node, int id) {
if (node == null) return true;
if (id > count) return false;
return validate(node.left, id * 2) && validate(node.right, id * 2 + 1);
}
private int getCount(TreeNode node) {
if (node == null) return 0;
return 1 + getCount(node.left) + getCount(node.right);
}
}
Version #1 DFS
98.36
class Solution {
int count;
public boolean isCompleteTree(TreeNode root) {
count = getCount(root);
return validate(root, 1);
}
private boolean validate(TreeNode node, int id) {
if (node == null) return true;
if (id > count) return false;
return validate(node.left, id * 2) && validate(node.right, id * 2 + 1);
}
private int getCount(TreeNode node) {
if (node == null) return 0;
return 1 + getCount(node.left) + getCount(node.right);
}
}
943. Find the Shortest Superstring
Version #1 DP
非常难的一道题
bug出在了当A[i] 为第一个word的时候,如果不设parent[1 << i][i] = i 而default为0的话就会陷入死循环
其余的思路其实和knapsack有点类似
关键在于状态压缩
把两个word之间的连接状态,压缩成一个已知的set,append一个word的状态
95.59 %
class Solution {
public String shortestSuperstring(String[] A) {
// int state -> which words index have been visited
// dp[state][i] -> minimum superstring length to cover state, and i is the last word
// having dp[state][j] -> try to expand to word that have not been visited before
// dp[state][i] = Math.min(dp[state][i], dp[state][j] + cost[j][i])
// store the last index j for dp[state][i] -> parent[state][i] = j
// cost[i][j] -> the length increased to append A[j] after A[i], not including length of A[i]
int len = A.length;
int[][] cost = new int[len][len];
int endState = 0; // if state reached this state, we know that all words have been used
for (int i = 0; i < len; i++) {
for (int j = 0; j < i; j++) {
cost[i][j] = getCost(A[i], A[j]);
cost[j][i] = getCost(A[j], A[i]);
}
endState += 1 << i;
}
int totalCost = Integer.MAX_VALUE;
int lastIndex = 0;
int[][] dp = new int[endState + 1][len];
int[][] parent = new int[endState + 1][len]; // parent index for min cost
for (int i = 0; i < len; i++) {
dp[1 << i][i] = A[i].length(); // A[i] is the first word, cost is it self
parent[1 << i][i] = i;
}
for (int s = 0; s <= endState; s++) {
for (int i = 0; i < len; i++) {
// check if this state has visited A[i] or not
if ((s & (1 << i)) == 0 || s == (1 << i)) continue;
dp[s][i] = Integer.MAX_VALUE;
int prevState = s & (~(1 << i)); // reset bit i
for (int j = 0; j < len; j++) {
if ((prevState & (1 << j)) == 0) continue;
// All possible prev states
if (dp[prevState][j] + cost[j][i] < dp[s][i]) {
dp[s][i] = dp[prevState][j] + cost[j][i];
parent[s][i] = j;
}
}
if (s == endState && dp[s][i] < totalCost) {
totalCost = dp[s][i];
lastIndex = i;
}
}
}
StringBuilder sb = new StringBuilder();
while (endState != 0) {
int curr = lastIndex;
lastIndex = parent[endState][curr];
endState = endState & (~(1 << curr)); // reset lastIndex
String temp = A[curr].substring(A[curr].length() - cost[lastIndex][curr]);
sb.insert(0, temp);
}
sb.insert(0, A[lastIndex]);
return sb.toString();
}
private int getCost(String first, String second) {
// abcd cdef
int overlap = 0;
for (int i = 0; i < first.length(); i++) {
if (second.startsWith(first.substring(i))) {
overlap = first.length() - i;
break;
}
}
return second.length() - overlap;
}
}
非常难的一道题
bug出在了当A[i] 为第一个word的时候,如果不设parent[1 << i][i] = i 而default为0的话就会陷入死循环
其余的思路其实和knapsack有点类似
关键在于状态压缩
把两个word之间的连接状态,压缩成一个已知的set,append一个word的状态
95.59 %
class Solution {
public String shortestSuperstring(String[] A) {
// int state -> which words index have been visited
// dp[state][i] -> minimum superstring length to cover state, and i is the last word
// having dp[state][j] -> try to expand to word that have not been visited before
// dp[state][i] = Math.min(dp[state][i], dp[state][j] + cost[j][i])
// store the last index j for dp[state][i] -> parent[state][i] = j
// cost[i][j] -> the length increased to append A[j] after A[i], not including length of A[i]
int len = A.length;
int[][] cost = new int[len][len];
int endState = 0; // if state reached this state, we know that all words have been used
for (int i = 0; i < len; i++) {
for (int j = 0; j < i; j++) {
cost[i][j] = getCost(A[i], A[j]);
cost[j][i] = getCost(A[j], A[i]);
}
endState += 1 << i;
}
int totalCost = Integer.MAX_VALUE;
int lastIndex = 0;
int[][] dp = new int[endState + 1][len];
int[][] parent = new int[endState + 1][len]; // parent index for min cost
for (int i = 0; i < len; i++) {
dp[1 << i][i] = A[i].length(); // A[i] is the first word, cost is it self
parent[1 << i][i] = i;
}
for (int s = 0; s <= endState; s++) {
for (int i = 0; i < len; i++) {
// check if this state has visited A[i] or not
if ((s & (1 << i)) == 0 || s == (1 << i)) continue;
dp[s][i] = Integer.MAX_VALUE;
int prevState = s & (~(1 << i)); // reset bit i
for (int j = 0; j < len; j++) {
if ((prevState & (1 << j)) == 0) continue;
// All possible prev states
if (dp[prevState][j] + cost[j][i] < dp[s][i]) {
dp[s][i] = dp[prevState][j] + cost[j][i];
parent[s][i] = j;
}
}
if (s == endState && dp[s][i] < totalCost) {
totalCost = dp[s][i];
lastIndex = i;
}
}
}
StringBuilder sb = new StringBuilder();
while (endState != 0) {
int curr = lastIndex;
lastIndex = parent[endState][curr];
endState = endState & (~(1 << curr)); // reset lastIndex
String temp = A[curr].substring(A[curr].length() - cost[lastIndex][curr]);
sb.insert(0, temp);
}
sb.insert(0, A[lastIndex]);
return sb.toString();
}
private int getCost(String first, String second) {
// abcd cdef
int overlap = 0;
for (int i = 0; i < first.length(); i++) {
if (second.startsWith(first.substring(i))) {
overlap = first.length() - i;
break;
}
}
return second.length() - overlap;
}
}
347. Top K Frequent Elements
二刷 06/2022
Version #3 Quick Select
和973用了不同的partition方法
这里没有把pivot swap到它正确的位置
返回的index是left - 1, 表示从(0-index) >= partition, (index+1, len-1) <= partition
如果index<k-1表示从0到index不足k个数,这时候要start=index+1,如果不+1会infinite loop
表示从0到index有大于等于k个数,这时候要end=index
Time O(N)
Space O(#distinct number)
Runtime: 16 ms, faster than 58.05% of Java online submissions for Top K Frequent Elements.
Memory Usage: 50.2 MB, less than 59.80% of Java online submissions for Top K Frequent Elements.
class Solution {
public int[] topKFrequent(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return new int[0];
}
Map<Integer, Integer> count = new HashMap<>();
for (int num : nums) {
count.put(num, count.getOrDefault(num, 0) + 1);
}
int[] unique = new int[count.size()];
int i = 0;
for (int num : count.keySet()) {
unique[i++] = num;
}
int index = unique.length;
int start = 0, end = unique.length - 1;
while (index != k - 1) {
index = partition(unique, start, end, count);
// System.out.printf("start=%d,end=%d,index=%d\n", start, end, index);
if (index < k - 1) {
start = index + 1;
} else {
end = index;
}
}
int[] result = new int[k];
for (int j = 0; j < k; j++) {
result[j] = unique[j];
}
return result;
}
private int partition(int[] nums, int start, int end, Map<Integer, Integer> count) {
int pivot = nums[start + (end - start) / 2];
int pivotCnt = count.get(pivot);
int left = start, right = end;
while (left <= right) {
while (left <= right && count.get(nums[left]) > pivotCnt) {
left++;
}
while (left <= right && count.get(nums[right]) < pivotCnt) {
right--;
}
if (left <= right) {
swap(nums, left, right);
left++;
right--;
}
}
return left - 1;
}
private void swap(int[] nums, int a, int b) {
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
有一个bug
因为count 是从1开始,所以生成的bucket size 需要 是length + 1
Time O(n)
95.43 %
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
// key-num, value-count
for (int num : nums) {
map.put(num, 1 + map.getOrDefault(num, 0));
}
// the frequency can't exceed total number of nums
List<Integer>[] bucket = new List[nums.length + 1];
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int count = entry.getValue();
if (bucket[count] == null) {
bucket[count] = new ArrayList<>();
}
bucket[count].add(entry.getKey());
}
List<Integer> result = new ArrayList<>();
int i = nums.length;
while (i >= 0 && result.size() < k) {
if (bucket[i] != null) {
result.addAll(bucket[i]);
}
i--;
}
return result;
}
}
Version #1 HashMap + minHeap
Time O(nlogk)
Space O(count of unique values)
51.98 %
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
// Count frequency -> Map<num, count> -> O(n) for all nums
// get most k count
// retrieve from map
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
int count = 1 + map.getOrDefault(num, 0);
map.put(num, count);
}
// O(nlogk)
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int count : map.values()) {
if (minHeap.size() < k) {
minHeap.offer(count);
} else if (count > minHeap.peek()) {
minHeap.poll();
minHeap.offer(count);
}
}
Set<Integer> countK = new HashSet<>(minHeap);
List<Integer> result = new ArrayList<>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (countK.contains(entry.getValue())) {
result.add(entry.getKey());
}
}
return result;
}
}
Friday, January 18, 2019
760. Find Anagram Mappings
92.70 %
class Solution {
public int[] anagramMappings(int[] A, int[] B) {
// key-num, value-index
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < B.length; i++) {
map.putIfAbsent(B[i], i);
}
int[] result = new int[A.length];
for (int i = 0; i < A.length; i++) {
result[i] = map.get(A[i]);
}
return result;
}
}
832. Flipping an Image
97.14 %
class Solution {
public int[][] flipAndInvertImage(int[][] A) {
if (A == null || A.length == 0 || A[0] == null || A[0].length == 0) return A;
int cols = A[0].length;
for (int y = 0; y < A.length; y++) {
int left = 0;
int right = cols - 1;
while (left <= right) {
if (left == right) {
A[y][left] ^= 1;
} else {
int temp = A[y][left] ^ 1;
A[y][left] = A[y][right] ^ 1;
A[y][right] = temp;
}
left++;
right--;
}
}
return A;
}
}
Wednesday, January 16, 2019
929. Unique Email Addresses
need to escape special chars in .split()
no need to escape in .replace()
59.26 %
class Solution {
public int numUniqueEmails(String[] emails) {
Set<String> set = new HashSet<>();
for (String email : emails) {
String[] parts = email.split("@");
String local = parts[0].split("\\+", 2)[0];
set.add(local.replace(".", "") + "@" + parts[1]);
}
return set.size();
}
}
no need to escape in .replace()
59.26 %
class Solution {
public int numUniqueEmails(String[] emails) {
Set<String> set = new HashSet<>();
for (String email : emails) {
String[] parts = email.split("@");
String local = parts[0].split("\\+", 2)[0];
set.add(local.replace(".", "") + "@" + parts[1]);
}
return set.size();
}
}
Monday, January 14, 2019
743. Network Delay Time
Version #1 Dijastra
1 BUG-> it is possible that a node be added to minHeap more than once
Since we are marking visited when we are polling it -> it is possible that one node is not polled yet and it is added one more time with an larger distance
So we have to check visited in to place
-> right after we poll out one node
-> before we add a node to minHeap
25.65 %
class Solution {
/*
times[i] = (u, v, w), where u is the source node, v is the target node,
and w is the time it takes for a signal to travel from source to target.
*/
public int networkDelayTime(int[][] times, int N, int K) {
// source target weight
Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
for (int[] time : times) {
// time[0]-source, time[1]-target, time[2]-weight
graph.computeIfAbsent(time[0], weightMap -> new HashMap<>()).put(time[1], time[2]);
}
int max = Integer.MIN_VALUE;
boolean[] visited = new boolean[N + 1]; // since nodes are 1 indexed
// a[0]-current node, a[1]-weight from source
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparing(a -> a[1]));
minHeap.offer(new int[]{K, 0});
while (!minHeap.isEmpty()) {
int[] curr = minHeap.poll();
int index = curr[0], distance = curr[1];
if (visited[index]) continue;
// System.out.println(index + " " + distance);
max = Math.max(max, distance);
visited[index] = true;
Map<Integer, Integer> neighbors = graph.get(index);
if (neighbors != null) {
for (int neighbor : neighbors.keySet()) {
if (!visited[neighbor]) {
minHeap.offer(new int[]{neighbor, distance + neighbors.get(neighbor)});
}
}
}
}
for (int i = 1; i < visited.length; i++) {
if (!visited[i]) return -1;
}
return max;
}
}
694. Number of Distinct Islands
二刷 05/2022
Test Cases:
[[1,1,0,0,0],[1,1,0,0,0],[0,0,0,1,1],[0,0,0,1,1]]
[[1,1,0,1,1],[1,0,0,0,0],[0,0,0,0,1],[1,1,0,1,1]]
一刷
Version #1 DFS
Hash each island by grids offset from its left most & top grid
58.50 %
class Solution {
public int numDistinctIslands(int[][] grid) {
// when we see the left,top grid of an island, try to expand it
// keep track of each grid by its relative position, seperated by " "
// use a string to encode the shape of each island
Set<String> set = new HashSet<>();
StringBuilder sb = new StringBuilder();
for (int y = 0; y < grid.length; y++) {
for (int x = 0; x < grid[0].length; x++) {
if (grid[y][x] == 1) {
dfs(grid, y, x, 0, 0, sb);
set.add(sb.toString());
sb.setLength(0);
}
}
}
return set.size();
}
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
private void dfs(int[][] grid, int y, int x, int offY, int offX, StringBuilder sb) {
sb.append(offY).append(" ").append(offX).append(" ");
grid[y][x] = 0;
for (int i = 0; i < 4; i++) {
int nextY = y + dy[i];
int nextX = x + dx[i];
if (nextX >= 0 && nextX < grid[0].length && nextY >= 0 && nextY < grid.length
&& grid[nextY][nextX] == 1) {
dfs(grid, nextY, nextX, offY + dy[i], offX + dx[i], sb);
}
}
}
}
Version #2 BFS
Hash each island into List<List<Integer>>
Each position is normalize by calculating the offset from the left top grid of the island
caveat: 这里如果用int[]是不work的,可能int array的hash function是由地址代替的
Runtime: 21 ms, faster than 30.36% of Java online submissions for Number of Distinct Islands.
Memory Usage: 54.5 MB, less than 20.22% of Java online submissions for Number of Distinct Islands.
class Solution {
public int numDistinctIslands(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
// Find all points of an island and store them in List<int[]>
// Since we iterate from smaller to larger indexes, the fisrt grid in the list is always the top left grid
// Normalize an island by calculate the relative position of every point with the top left point
// Store the island grid list in a hash set
Set<List<List<Integer>>> islands = new HashSet<>();
int rows = grid.length, cols = grid[0].length;
boolean[][] visited = new boolean[rows][cols];
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
if (!visited[y][x] && grid[y][x] == 1) {
// Expand an island from starting point (x, y) and returns all of its grids
List<List<Integer>> island = findIsland(grid, y, x, visited);
islands.add(island);
}
}
}
return islands.size();
}
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
List<List<Integer>> findIsland(int[][] grid, int y, int x, boolean[][] visited) {
List<List<Integer>> island = new ArrayList<>();
Queue<List<Integer>> que = new ArrayDeque<>();
que.offer(Arrays.asList(y, x));
visited[y][x] = true;
while (!que.isEmpty()) {
List<Integer> curr = que.poll();
island.add(Arrays.asList(curr.get(0) - y, curr.get(1) - x));
// iterate all 4 directions
for (int i = 0; i < 4; i++) {
int ny = curr.get(0) + dy[i];
int nx = curr.get(1) + dx[i];
// out of the boundary
if (ny < 0 || ny >= grid.length || nx < 0 || nx >= grid[0].length) {
continue;
}
if (!visited[ny][nx] && grid[ny][nx] == 1) {
visited[ny][nx] = true;
que.offer(Arrays.asList(ny, nx));
}
}
}
return island;
}
}
Test Cases:
[[1,1,0,0,0],[1,1,0,0,0],[0,0,0,1,1],[0,0,0,1,1]]
[[1,1,0,1,1],[1,0,0,0,0],[0,0,0,0,1],[1,1,0,1,1]]
一刷
Version #1 DFS
Hash each island by grids offset from its left most & top grid
58.50 %
class Solution {
public int numDistinctIslands(int[][] grid) {
// when we see the left,top grid of an island, try to expand it
// keep track of each grid by its relative position, seperated by " "
// use a string to encode the shape of each island
Set<String> set = new HashSet<>();
StringBuilder sb = new StringBuilder();
for (int y = 0; y < grid.length; y++) {
for (int x = 0; x < grid[0].length; x++) {
if (grid[y][x] == 1) {
dfs(grid, y, x, 0, 0, sb);
set.add(sb.toString());
sb.setLength(0);
}
}
}
return set.size();
}
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
private void dfs(int[][] grid, int y, int x, int offY, int offX, StringBuilder sb) {
sb.append(offY).append(" ").append(offX).append(" ");
grid[y][x] = 0;
for (int i = 0; i < 4; i++) {
int nextY = y + dy[i];
int nextX = x + dx[i];
if (nextX >= 0 && nextX < grid[0].length && nextY >= 0 && nextY < grid.length
&& grid[nextY][nextX] == 1) {
dfs(grid, nextY, nextX, offY + dy[i], offX + dx[i], sb);
}
}
}
}
695. Max Area of Island
三刷 07/2022
Version #3 Union Find
Time O(MN) - we have 4 MN union operations, union with size rank and path compression will result in amortized O(1) time
Space O(MN)
Runtime: 6 ms, faster than 25.46% of Java online submissions for Max Area of Island.
Memory Usage: 48 MB, less than 21.47% of Java online submissions for Max Area of Island.
class Solution {
private static int ISLAND = 1;
class UnionFind {
private int[] size;
private int[] id;
private int rows;
private int cols;
int maxSize = 0;
public UnionFind(int[][] grid) {
rows = grid.length;
cols = grid[0].length;
size = new int[rows * cols];
id = new int[rows * cols];
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
int index = getIndex(cols, y, x);
if (grid[y][x] == 1) {
maxSize = 1;
size[index] = 1;
id[index] = index;
}
}
}
}
public int root(int i) {
while (id[i] != i) {
id[i] = id[id[i]];
i = id[i];
}
return i;
}
public void union(int p, int q) {
int rootP = root(p);
int rootQ = root(q);
if (rootP == rootQ) {
return;
}
if (size[rootP] < size[rootQ]) {
id[rootP] = rootQ;
size[rootQ] += size[rootP];
maxSize = Math.max(maxSize, size[rootQ]);
} else {
id[rootQ] = rootP;
size[rootP] += size[rootQ];
maxSize = Math.max(maxSize, size[rootP]);
}
}
public int getMaxSize() {
return maxSize;
}
}
public int getIndex(int cols, int y, int x) {
return y * cols + x;
}
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
public int maxAreaOfIsland(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;
UnionFind uf = new UnionFind(grid);
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
if (grid[y][x] != ISLAND) {
continue;
}
int index = getIndex(cols, y, x);
for (int i = 0; i < 4; i++) {
int ny = y + dy[i];
int nx = x + dx[i];
if (ny < 0 || nx < 0 || ny >= rows || nx >= cols || grid[ny][nx] != ISLAND) {
continue;
}
uf.union(index, getIndex(cols, ny, nx));
}
}
}
return uf.getMaxSize();
}
}
二刷 06/2022
We could also use stack based DFS to avoid using recursion
Version #2 DFS without changing the original matrix
Time O(MN)
Space O(MN)
Runtime: 4 ms, faster than 52.28% of Java online submissions for Max Area of Island.
Memory Usage: 47.4 MB, less than 48.23% of Java online submissions for Max Area of Island.
class Solution {
public int maxAreaOfIsland(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;
boolean[][] visited = new boolean[rows][cols];
int max = 0;
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
if (grid[y][x] == 1 && !visited[y][x]) {
visited[y][x] = true;
max = Math.max(max, dfs(grid, visited, y, x));
}
}
}
return max;
}
private static int[] dx = new int[]{1, 0, -1, 0};
private static int[] dy = new int[]{0, -1, 0, 1};
// Return how many 1s are in current island
private int dfs(int[][] grid, boolean[][] visited, int y, int x) {
int count = 1;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || nx >= grid[0].length || ny >= grid.length || visited[ny][nx] || grid[ny][nx] != 1) {
continue;
}
visited[ny][nx] = true;
count += dfs(grid, visited, ny, nx);
}
return count;
}
}
Version #1 DFS
43.59 %
class Solution {
public int maxAreaOfIsland(int[][] grid) {
// iterate through the grid, if we see any 1, we try to expand this island
// set any visited grid to 0
int max = 0;
for (int y = 0; y < grid.length; y++) {
for (int x = 0; x < grid[0].length; x++) {
if (grid[y][x] == 1) {
max = Math.max(max, dfs(grid, x, y));
}
}
}
return max;
}
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
private int dfs(int[][] grid, int x, int y) {
// return the size of current island
int size = 1;
grid[y][x] = 0;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < grid[0].length && ny >= 0 && ny < grid.length
&& grid[ny][nx] == 1) {
size += dfs(grid, nx, ny);
}
}
return size;
}
}
725. Split Linked List in Parts
Version #1 Straight-forward
98.82 %
class Solution {
public ListNode[] splitListToParts(ListNode root, int k) {
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
//Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
// length = 10, bucketLength = 10/3=3, residual = 10%3 = 1
ListNode[] result = new ListNode[k];
ListNode curr = root;
int length = 0;
while (curr != null) {
length++;
curr = curr.next;
}
int bucketLength = length / k;
int residual = length % k;
curr = root;
for (int i = 0; i < k && curr != null; i++) {
int len = bucketLength;
if (residual > 0) {
len++;
residual--;
}
result[i] = curr;
ListNode prev = null;
while (curr != null && len > 0) {
prev = curr;
curr = curr.next;
len--;
}
prev.next = null;
}
return result;
}
}
729. My Calendar I
二刷 08/2022
Version #1 TreeMap
一个bug,如果用floorKey(end)的话// [19,25)[25,32)[33,41)[47,50) 要加入[19,25)就会失败,因为25的floorKey是[25,32)entry,然后32又比19大
所以应该用lowerKey
注意这里没有必要合并相邻的intervals
Time O(logN)
Space O(N)
Runtime: 30 ms, faster than 75.04% of Java online submissions for My Calendar I.
Memory Usage: 54.6 MB, less than 51.82% of Java online submissions for My Calendar I.
class MyCalendar {
TreeMap<Integer, Integer> events;
public MyCalendar() {
this.events = new TreeMap<>();
}
// [19,25)[25,32)[33,41)[47,50)
public boolean book(int start, int end) {
// [start, end)
Integer prevStart = events.lowerKey(end);
if (prevStart != null && events.get(prevStart) > start) {
return false;
}
// [prevStart, prevEnd) [start, end)
events.put(start, end);
return true;
}
}
Version #1 TreeMap
Time O(logn) for each book() call
94.57 %
class MyCalendar {
TreeMap<Integer, Integer> treeMap;
public MyCalendar() {
// key-start, value-end
this.treeMap = new TreeMap<>();
}
public boolean book(int start, int end) {
// [start, end) [start, end)
// There should be two constraints
// 1.any event happens after current start time, should start after end time
// 2.any event happens before current start time, should end before start time
Map.Entry<Integer, Integer> prev = treeMap.floorEntry(start);
if (prev != null && prev.getValue() > start) return false;
Map.Entry<Integer, Integer> next = treeMap.ceilingEntry(start);
if (next != null && next.getKey() < end) return false;
treeMap.put(start, end);
return true;
}
}
Subscribe to:
Posts (Atom)