Thoughts on leetcode 994
- About queue in java:
- Deque<int[]> queue = new ArrayDeque();
- queue.add(new int[]{i, j});
- queue.poll();
2. check whether there is a fresh orange left in the while loop (in case there are rotten oranges inserted into the queue but there is no more fresh oranges left)
3. check whether there is a fresh orange left in the end to see whether -1 need to be returned
Pay attention for (while queue.size() != 0 && fresh != 0)
for example only one rotten but no remaining fresh, so the day is 0
Solution for leetcode 994
class Solution {
public int orangesRotting(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int fresh = 0;
int[][] directions = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
Deque<int[]> queue = new ArrayDeque();
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j] == 2){
queue.add(new int[]{i, j});
}
else if(grid[i][j] == 1){
fresh++;
}
}
}
int day = 0;
while(queue.size() != 0 && fresh != 0){
int size = queue.size();
day += 1;
while(size != 0){
int[] cur = queue.poll();
size--;
for(int i = 0; i < directions.length; i++){
int curx = cur[0] + directions[i][0];
int cury = cur[1] + directions[i][1];
if(curx >= 0 && cury >= 0 && curx < m && cury < n && grid[curx][cury] == 1){
//don't forget to set this
grid[curx][cury] = 2;
fresh--;
queue.add(new int[]{curx, cury});
}
}
}
}
return fresh > 0 ? -1 : day;
}
}
Thoughts on leetcode 934
Use dfs to find the first island and insert every cell of it into a queue. In this way, we can use bfs later to find the shortest distance from a certain cell of the first island to the other island. We should remember both the dfs template and bfs template of this problem.
Some useful tricks:
- when we are inserting the cells into the queue, we already mark it as visited(2) to get rid of duplicate insertions, this also applies to dfs
- use flag to not further go through the loop
- when doing dfs, we can add surrounding 0 to the queue so that there is one less layer in bfs
Solution for leetcode 934
class Solution {
int[][] directions = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
Deque<int[]> queue = new ArrayDeque();
public int shortestBridge(int[][] grid) {
boolean flag = false;
for(int i = 0; i < grid.length && flag == false;i++){
for(int j = 0; j < grid[0].length; j++){
if(grid[i][j] == 1){
dfs(grid, i, j);
flag = true;
break;
}
}
}
int num = 0;
while(queue.size() != 0){
int size = queue.size();
num += 1;
while(size != 0){
int[] cur = queue.poll();
size--;
int x = cur[0];
int y = cur[1];
for(int[] direction: directions){
int newx = x + direction[0];
int newy = y + direction[1];
if(newx >= 0 && newy >= 0 && newx < grid.length && newy < grid[0].length){
if(grid[newx][newy] == 1){
return num;
}
if(grid[newx][newy] == 0){
queue.add(new int[]{newx, newy});
grid[newx][newy] = 2;
}
}
}
}
}
return num;
}
public void dfs(int[][]grid, int i, int j){
if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == 2){
return;
}
if(grid[i][j] == 0){
queue.add(new int[]{i, j});
return;
}
grid[i][j] = 2;
for(int[] direction: directions){
dfs(grid, i + direction[0], j + direction[1]);
}
}
}
Thoughts on leetcode 752
The only thing that is new is the way to generate the next string from the current string.
Also, we need to insert the deadends into a set so that the route containing the deadends will not be added to the queue.
Solution for leetcode 752
class Solution {
public int openLock(String[] deadends, String target) {
HashSet<String> dead = new HashSet<>(Arrays.asList(deadends));
Set<String> visited = new HashSet<>();
String start="0000";
Deque<String> dq = new ArrayDeque();
dq.add(start);
visited.add(start);
if(dead.contains(target) ||dead.contains("0000")){
return -1;
}
int step = 0;
while(dq.size() != 0){
int size = dq.size();
while(size != 0){
size--;
String cur = dq.poll();
if(cur.equals(target)){
return step;
}
List<String> list = getNexts(cur);
for(int i = 0; i < list.size(); i++){
String potential = list.get(i);
if(!dead.contains(potential) && !visited.contains(potential)){
dq.add(potential);
visited.add(potential);
}
}
}
step++;
}
return -1;
}
//for every slot in the current lock, move forward or move back to construct the next step
//pay attention to the edge case: 0 & 9
public static List<String> getNexts(String cur){
List<String> list = new ArrayList<>();
for(int i = 0; i < 4; i++){
StringBuilder cursb = new StringBuilder(cur);
cursb.setCharAt(i, cur.charAt(i) == '0' ? '9' : (char)(cur.charAt(i) - 1));
list.add(cursb.toString());
cursb.setCharAt(i, cur.charAt(i) == '9' ? '0' : (char)(cur.charAt(i) + 1));
list.add(cursb.toString());
}
return list;
}
}
Thoughts on leetcode 310
Any node that has already been a leaf cannot be the root of a MHT, because its adjacent non-leaf node will always be a better candidate. What we basically do is removing the leaves, updating the degrees of inner vertexes, and then remove the new leaves. Doing so level by level until there are 2 or 1 nodes left. What's left is our answer!
Solution for leetcode 310
class Solution {
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
int[] degree = new int[n];
List<Integer> res = new ArrayList<>();
if (n == 1) {
res.add(0);
return res;
}
//create a hashmap to store the edge relationship
HashMap<Integer, List<Integer>> map = new HashMap();
Deque<Integer> q = new ArrayDeque();
for(int[] edge : edges){
for(int i = 0; i < 2; i++){
int cur = edge[i];
degree[cur]++;
List<Integer> list = map.getOrDefault(cur,new ArrayList());
list.add(edge[1-i]);
map.put(cur, list);
}
}
//insert the leaf nodes
for(int i = 0; i < n; i++){
if(degree[i] == 1){
q.add(i);
}
}
while(q.size() != 0){
res = new ArrayList<>();
int size = q.size();
while(size != 0){
size--;
int cur = q.poll();
res.add(cur);
List<Integer> neighbours = map.get(cur);
for(int nb : neighbours){
degree[nb]--;
if(degree[nb] == 1){
q.add(nb);
}
}
}
}
//res is the last nodes remaining
return res;
}
}
Thoughts on leetcode 1654
We need to keep an extra integer for the element in the queue to check what the previous step is, because we can't go backward twice.
We need to add (pos + a) < 6000 because we can go beyond the end and come back
Check if the position is forbidden(visited)
If a position is reached by the forward movement, we mark it as forbidden(visited) because both pos + a and pos - b will be considered
If a position is reached by the backward movement, we don't mark it as forbidden because pos - b case will not be considered. We can reach this position again by the forward movement and explore the pos - b case.
class Solution {
public int minimumJumps(int[] forbidden, int a, int b, int x) {
if(x == 0){
return 0;
}
Set<Integer> forbiddenSet = new HashSet();
Deque<int[]> queue = new ArrayDeque();
for(int forbid : forbidden){
forbiddenSet.add(forbid);
}
int output = 0;
//-1 stands for backward and 1 stands for forward
queue.add(new int[]{0, -1});
while(!queue.isEmpty()){
int size = queue.size();
output++;
while(size != 0){
size--;
int[] cur = queue.poll();
int curx = cur[0];
int curdir = cur[1];
if(curdir == 1){
if(curx - b >= 0 && !forbiddenSet.contains(curx - b)){
if(curx - b == x){
return output;
}
queue.add(new int[]{curx - b, -1});
//this is unnecessary because we will not backward twice
// forbiddenSet.add(curx - b);
}
}
//cur + a < 6000 is necessary because we can go beyond and come back
if(!forbiddenSet.contains(curx + a) && curx + a < 6000){
if(curx + a == x){
return output;
}
queue.add(new int[]{curx + a, 1});
forbiddenSet.add(curx + a);
}
}
}
return -1;
}
}