一刷 05/2022
Version #1 BFS
Time O(MN)
Spance O(MN)
361 mstime cost
22.63 MBmemory cost
Your submission beats16.20 %Submissions
public class Solution {
一刷 05/2022
Version #1 BFS
Time O(MN)
Spance O(MN)
361 mstime cost
22.63 MBmemory cost
Your submission beats16.20 %Submissions
public class Solution {
2649 mstime cost
22.94 MBmemory cost
Your submission beats11.00 %Submissions
/**
一刷 05/2022
Version #1 Topological Sort
Time O(E + V)
Space O(E + V)
class Solution {
public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
Set<Integer>[] graph = new HashSet[numCourses];
int[] indegree = new int[numCourses];
Set<Integer>[] preReq = new HashSet[numCourses];
for (int i = 0; i < numCourses; i++) {
graph[i] = new HashSet<>();
preReq[i] = new HashSet<>();
}
for (int[] prerequisite : prerequisites) {
int from = prerequisite[0];
int to = prerequisite[1];
graph[from].add(to);
indegree[to]++;
}
Queue<Integer> que = new ArrayDeque<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) {
que.offer(i);
}
}
while (!que.isEmpty()) {
Integer curr = que.poll();
for (int next : graph[curr]) {
preReq[next].add(curr);
preReq[next].addAll(preReq[curr]);
indegree[next]--;
if (indegree[next] == 0) {
que.offer(next);
}
}
}
List<Boolean> result = new ArrayList<>();
for (int[] query : queries) {
if (preReq[query[1]].contains(query[0])) {
result.add(true);
} else {
result.add(false);
}
}
return result;
}
}
一刷 05/2022
Version #1 Topological Sort
Time O(#nums)
Space O(#nums^2)
class Solution {
public boolean sequenceReconstruction(int[] nums, List<List<Integer>> sequences) {
Map<Integer, Set<Integer>> graph = new HashMap<>();
Map<Integer, Integer> indegree = new HashMap<>();
for (int num : nums) {
graph.put(num, new HashSet<>());
indegree.put(num, 0);
}
for (List<Integer> sequence : sequences) {
Integer from = null, to = null;
for (Integer n : sequence) {
if (from == null) {
from = n;
continue;
}
to = n;
Set<Integer> neighbors = graph.get(from);
if (!neighbors.contains(to)) {
neighbors.add(to);
indegree.put(to, indegree.get(to) + 1);
}
from = n;
}
}
// for (Map.Entry<Integer, Set<Integer>> entry : graph.entrySet()) {
// System.out.printf("key-%d, set-%s\n", entry.getKey(), entry.getValue());
// }
Queue<Integer> que = new ArrayDeque<>();
for (Map.Entry<Integer,Integer> entry : indegree.entrySet()) {
if (entry.getValue() == 0) {
que.offer(entry.getKey());
}
}
int index = 0;
while (!que.isEmpty()) {
if (que.size() > 1) {
return false;
}
Integer curr = que.poll();
// System.out.println(curr);
if (curr != nums[index++]) {
return false;
}
for (Integer neighbor : graph.get(curr)) {
int id = indegree.get(neighbor);
id -= 1;
if (id == 0) {
que.offer(neighbor);
}
indegree.put(neighbor, id);
}
}
return true;
}
}
一刷
Version #1 BFS
TLE if we use HashMap to implement the visited grids
We should use a boolean array instead
Given the coordinate of the target as (x,y), the number of cells covered by the circle that is centered at point (0,0) and reaches the target point is roughly (max(∣x∣,∣y∣))2
Time O(max(|x|, |y|)^2)
Space O(max(|x|, |y|)^2)
class Solution {
private int[] dx = new int[]{2, 1, -1, -2, -2, -1, 1, 2};
private int[] dy = new int[]{1, 2, 2, 1, -1, -2, -2, -1};
public int minKnightMoves(int x, int y) {
if (x == 0 && y == 0) {
return 0;
}
Queue<int[]> que = new ArrayDeque<>();
boolean[][] visited = new boolean[601][601];
que.offer(new int[]{0, 0});
visited[300][300] = true;
int step = 0;
while (!que.isEmpty()) {
int size = que.size();
step++;
while (size-- > 0) {
int[] curr = que.poll();
// y = curr[0], x = curr[1]
for (int i = 0; i < 8; i++) {
int ny = curr[0] + dy[i];
int nx = curr[1] + dx[i];
if (nx == x && ny == y) {
return step;
}
if (visited[ny + 300][nx + 300]) {
continue;
}
que.offer(new int[]{ny, nx});
visited[ny + 300][nx + 300] = true;
}
}
}
return -1;
}
}
Version #2 Bidirectional BFS
这里只是记录这种bidirectional的思路
实际写的时候visited array的boundary和offsite都非常tricky, 写错了好几次
如果不用visited array而用hash成string的方法就会TLE
所以问题很多
Time 和 Space complexity都和上面是一样的
class Solution {
private int[] dx = new int[]{2, 1, -1, -2, -2, -1, 1, 2};
private int[] dy = new int[]{1, 2, 2, 1, -1, -2, -2, -1};
private String hash(int[] grid) {
return grid[0] + "," + grid[1];
}
private int offsite = 600;
public int minKnightMoves(int x, int y) {
if (x == 0 && y == 0) {
return 0;
}
// Bidirectional BFS
// Search from both start point and the end point
int bound = 1201;
int[][] sourceVisited = new int[bound][bound];
int[][] targetVisited = new int[bound][bound];
for (int i = 0; i < bound; i++) {
for (int j = 0; j < bound; j++) {
sourceVisited[i][j] = -1;
targetVisited[i][j] = -1;
}
}
Queue<int[]> sourceQue = new ArrayDeque<>();
sourceVisited[offsite][offsite] = 0;
sourceQue.offer(new int[]{0, 0});
Queue<int[]> targetQue = new ArrayDeque<>();
targetVisited[x + offsite][y + offsite] = 0;
targetQue.offer(new int[]{x, y});
// while (!sourceQue.isEmpty() && !targetQue.isEmpty())
// The queue will never be empty since the board is infinite, so we can just use while "true"
while (true) {
int dist = bfs(sourceQue, sourceVisited, targetVisited);
if (dist > 0) {
return dist;
}
dist = bfs(targetQue, targetVisited, sourceVisited);
if (dist > 0) {
return dist;
}
}
}
private int bfs(Queue<int[]> que, int[][] selfVisited, int[][] otherVisited) {
int[] curr = que.poll();
// dist to the next point
int dist = selfVisited[curr[0] + offsite][curr[1] + offsite] + 1;
// System.out.printf("(%d,%d) -> %d", curr[0], curr[1], dist);
for (int i = 0; i < 8; i++) {
int nx = curr[0] + dx[i];
int ny = curr[1] + dy[i];
if (otherVisited[nx + offsite][ny + offsite] != -1) {
return dist + otherVisited[nx + offsite][ny + offsite];
}
if (selfVisited[nx + offsite][ny + offsite] != -1) {
continue;
}
selfVisited[nx + offsite][ny + offsite] = dist;
que.offer(new int[]{nx, ny});
}
return -1;
}
}
一刷 05/2022
Version #1 BFS
参考LC649
重点是把一个island normalize
这里可以hash成一个string
StringBuilder append 加String.format很慢,要避免,最好一个一个append
class Solution {
public int numDistinctIslands2(int[][] grid) {
// find all grids of an island
// enumerate all transformations of that island
// Normalize those transformations by calculating the relative position of the left & top point
// Sort all the transformations and use the minimum representative to represent the island
// Use a hash set to deduplicate
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
int rows = grid.length, cols = grid[0].length;
boolean[][] visited = new boolean[rows][cols];
Set<String> islands = new HashSet<>();
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
if (!visited[y][x] && grid[y][x] == 1) {
String island = normalize(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};
private 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(curr);
// go to 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 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;
}
private String normalize(List<List<Integer>> island) {
List<List<List<Integer>>> transformations = new ArrayList<>();
List<String> strs = new ArrayList<>();
for (int i = 0; i < 8; i++) {
transformations.add(new ArrayList<>());
}
for (List<Integer> curr : island) {
int y = curr.get(0);
int x = curr.get(1);
transformations.get(0).add(Arrays.asList(x, y));
transformations.get(1).add(Arrays.asList(-x, y));
transformations.get(2).add(Arrays.asList(x, -y));
transformations.get(3).add(Arrays.asList(-x, -y));
transformations.get(4).add(Arrays.asList(y, x));
transformations.get(5).add(Arrays.asList(-y, x));
transformations.get(6).add(Arrays.asList(y, -x));
transformations.get(7).add(Arrays.asList(-y, -x));
}
StringBuilder sb = new StringBuilder();
for (List<List<Integer>> transformation : transformations) {
Collections.sort(transformation, new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> a, List<Integer> b) {
if (a.get(0) != b.get(0)) {
return a.get(0) - b.get(0);
}
return a.get(1) - b.get(1);
}
});
Integer y0 = transformation.get(0).get(0);
Integer x0 = transformation.get(0).get(1);
for (int i = 0; i < transformation.size(); i++) {
List<Integer> yx = transformation.get(i);
// y = yx.get(0) - y0
// x = yx.get(1) - x0
sb.append("(" + (yx.get(0) - y0) + "," + (yx.get(1) - x0) + ")");
}
strs.add(sb.toString());
sb.setLength(0);
}
Collections.sort(strs);
return strs.get(0);
}
}
Version #2 DFS
class Solution {
class Point implements Comparable<Point> {
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int compareTo(Point p) {
if (this.y != p.y) {
return this.y - p.y;
}
return this.x - p.x;
}
@Override
public String toString() {
return String.format("(%s,%s)", x, y);
}
}
public int numDistinctIslands2(int[][] grid) {
// find all grids of an island
// enumerate all transformations of that island
// Normalize those transformations by calculating the relative position of the left & top point
// Sort all the transformations and use the minimum representative to represent the island
// Use a hash set to deduplicate
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
int rows = grid.length, cols = grid[0].length;
boolean[][] visited = new boolean[rows][cols];
Set<String> islands = new HashSet<>();
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
if (!visited[y][x] && grid[y][x] == 1) {
List<Point> island = new ArrayList<>();
visited[y][x] = true;
findIsland(grid, y, x, visited, island);
String str = normalize(island);
islands.add(str);
}
}
}
return islands.size();
}
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
private void findIsland(int[][] grid, int y, int x, boolean[][] visited, List<Point> island) {
island.add(new Point(x, y));
for (int i = 0; i < 4; i++) {
int ny = y + dy[i];
int nx = x + dx[i];
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;
findIsland(grid, ny, nx, visited, island);
}
}
}
private String normalize(List<Point> island) {
List<Point>[] transformations = new List[8];
String[] strs = new String[8];
for (int i = 0; i < 8; i++) {
transformations[i] = new ArrayList<>();
}
for (Point p : island) {
int y = p.y;
int x = p.x;
transformations[0].add(new Point(x, y));
transformations[1].add(new Point(-x, y));
transformations[2].add(new Point(x, -y));
transformations[3].add(new Point(-x, -y));
transformations[4].add(new Point(y, x));
transformations[5].add(new Point(-y, x));
transformations[6].add(new Point(y, -x));
transformations[7].add(new Point(-y, -x));
}
for (int i = 0; i < 8; i++) {
StringBuilder sb = new StringBuilder();
Collections.sort(transformations[i]);
int x0 = transformations[i].get(0).x;
int y0 = transformations[i].get(0).y;
for (Point p : transformations[i]) {
sb.append(String.format("(%s,%s)", p.x - x0, p.y - y0));
}
strs[i] = sb.toString();
}
Arrays.sort(strs);
return strs[0];
}
}
一刷 05/2022
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class BSTIterator {
// add a array to keep record of all elements that have been visited
private Stack<TreeNode> stack;
private List<Integer> visited;
private int index;
public BSTIterator(TreeNode root) {
stack = new Stack<>();
visited = new ArrayList<>();
index = 0;
while (root != null) {
stack.push(root);
root = root.left;
}
}
public boolean hasNext() {
return !stack.isEmpty() || index < visited.size();
}
public int next() {
int val;
if (index < visited.size()) {
val = visited.get(index);
} else {
TreeNode curr = stack.pop();
val = curr.val;
visited.add(val);
curr = curr.right;
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
}
index++;
return val;
}
public boolean hasPrev() {
// index is pointing to the next value
return index - 2 >= 0;
}
public int prev() {
return visited.get(--index - 1);
}
}
/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator obj = new BSTIterator(root);
* boolean param_1 = obj.hasNext();
* int param_2 = obj.next();
* boolean param_3 = obj.hasPrev();
* int param_4 = obj.prev();
*/
一刷 05/2022
Version #2 Binary Search To Find The Left Bound[TODO]
Time O(log(n - k) + k)
Space O(1)
Not working version
有一个反例就是当 mid= 3, mid + k = 6的时候他们同时指向element 2
但是此时需要我们选择larger index
就没懂
index [0,1,2,3,4,5,6,7,8]
arr [1,1,2,2,2,2,2,3,3]
[1,1,2,2,2,2,2,3,3]
3
3
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
if (arr == null) {
return new ArrayList<>();
}
// Binary search to find the left bound
int start = 0, end = arr.length - k;
System.out.printf("start: %d, end: %d", start, end);
while (start + 1 < end) {
int mid = start + (end - start) / 2;
// arr[mid] and arr[mid + k] there can only 1 be in the final answer
if (Math.abs(arr[mid] - x) > Math.abs(arr[mid + k] - x)) {
start = mid + 1;
} else {
end = mid;
}
}
System.out.printf("start: %d, end: %d", start, end);
// ... start end ... start + k, end + k
if (start + k < arr.length && Math.abs(arr[start] - x) > Math.abs(arr[start + k] - x)) {
start = end;
}
List<Integer> res = new ArrayList<>();
while (k-- > 0) {
res.add(arr[start]);
start++;
}
return res;
}
}
Version #1 Binary Search + Sliding window
一遍bug free就过了,我真棒
重点是在算insertion index的时候考虑到各种Corner case
Time O(logN + k)
Space O(1)
Memory Usage: 62.6 MB, less than 40.35% of Java online submissions for Find K Closest Elements.
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
if (arr == null) {
return new ArrayList<>();
}
// It's possible that x is not in the array
// Find the insertion index of x in array -> find the 1st index where arr[index] >= x
int insertionIndex = findIndex(arr, x);
int left = insertionIndex - 1, right = insertionIndex;
while (k > 0) {
int leftDiff = left >= 0 ? x - arr[left] : Integer.MAX_VALUE;
int rightDiff = right < arr.length ? arr[right] - x : Integer.MAX_VALUE;
if (leftDiff <= rightDiff) {
left--;
} else {
right++;
}
k--;
}
// 1,2,3,4,5 x = 3 -> insertinIndex = 2, k = 4
// l r
// l r k = 3
// l r k = 2
// l r k = 1
//l r k = 0
List<Integer> res = new ArrayList<>();
for (int i = left + 1; i < right; i++) {
res.add(arr[i]);
}
return res;
}
private int findIndex(int[] arr, int x) {
int start = 0, end = arr.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (arr[mid] < x) {
start = mid + 1;
} else {
end = mid;
}
}
if (arr[start] >= x) {
return start;
}
if (arr[end] >= x) {
return end;
}
// All elements are smaller than x, insert to the end of the array
return arr.length;
}
}
一刷 05/2022
Time O(logk) -> k is the index of the target number
Space O(1)
/**
* // This is ArrayReader's API interface.
* // You should not implement it, or speculate about its implementation
* interface ArrayReader {
* public int get(int index) {}
* }
*/
class Solution {
public int search(ArrayReader reader, int target) {
// Find a upper bound of the range in which we can search for the target
int end = 1;
while (reader.get(end) < target) {
end = end << 1;
}
int start = end >> 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (reader.get(mid) == target) {
return mid;
}
if (reader.get(mid) < target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return -1;
}
}
一刷
我觉得做法是对的但是没有过OC
感觉OC有问题
Time O(n)
Space O(1)
一刷 05/2022
Time O(nlogk)
Space O(1)
一刷 05/2022
Time O(n)
Space O(n)
class Solution {
public int[] rearrangeArray(int[] nums) {
if (nums == null || nums.length == 0) {
return nums;
}
int[] res = new int[nums.length];
int pos = 0, neg = 1;
for (int num : nums) {
if (num < 0) {
res[neg] = num;
neg += 2;
} else {
res[pos] = num;
pos += 2;
}
}
return res;
}
}
一刷 05/2022
Time O(nlogn)
Space O(1)
class Solution {
public int arrayPairSum(int[] nums) {
// make them as close as possible
if (nums == null || nums.length == 0) {
return 0;
}
Arrays.sort(nums);
int sum = 0;
for (int i = 0; i < nums.length; i += 2) {
sum += nums[i];
}
return sum;
}
}