深&广度优先搜索
- leetcode200岛屿数量
- leetcode695岛屿的最大面积
- leetcode108将有序数组转化成二叉排序树
- leetcode959由斜杠划分区域🔐
- leetcode124二叉树中的最大路径和
- leetcode99恢复二叉搜索树
- leetcode979在二叉树中分配硬币🔐
- leetcode834树中距离之和🔐
- leetcode102二叉树的层序遍历
- leetcode107二叉树的层序遍历2
- leetcode199二叉树的右视图
- leetcode114二叉树展开为链表🔐
- leetcode109有序链表转换成二叉搜索树
- leetcode116填充每个节点的下一个右侧节点指针
- leetcode279完全平方数
- leetcode101对称二叉树
- leetcode133克隆图
- leetcode103二叉树的锯齿形层序遍历🔐
- leetcode111二叉树的最小深度
- leetcode130被环绕的区域
- leetcode52401矩阵
- leetcode529扫雷游戏
- leetcode524通过删除字母匹配到字典里最长单词
- leetcode207课程表🔐
- leetcode847访问所有节点的最短路径🔐🔐
- leetcode773滑动谜题🔐
leetcode200岛屿数量
class Solution {
char[][] grid;
int M, N;
public int numIslands(char[][] grid) {
M = grid.length;
if (M == 0) return 0;
N = grid[0].length;
if (N == 0) return 0;
this.grid = grid;
int num = 0;
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
if (grid[i][j] == '1') {
modify(i, j);
++num;
}
}
}
return num;
}
private void modify(int i, int j) {
if (i < 0 || i >= M || j < 0 || j >= N) return;
if (grid[i][j] != '1') return;
grid[i][j] = '2';
modify(i + 1, j);
modify(i - 1, j);
modify(i, j - 1);
modify(i, j + 1);
}
}
leetcode695岛屿的最大面积
class Solution {
int[][] grid;
int M, N;
public int maxAreaOfIsland(int[][] grid) {
M = grid.length;
N = grid.length;
int res = 0;
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
res = Math.max(res, modify(i, j));
}
}
return res;
}
private int modify(int i, int j) {
if (i < 0 || i >= M || j < 0 || j >= N) return 0;
if (grid[i][j] != '1') return 0;
grid[i][j] = '0';
int count = 0;
count += modify(i + 1, j);
count += modify(i - 1, j);
count += modify(i, j - 1);
count += modify(i, j + 1);
return count;
}
}
leetcode108将有序数组转化成二叉排序树
- 主要是根节点的选择
/**
* 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 Solution {
int[] arr;
public TreeNode sortedArrayToBST(int[] nums) {
this.arr = nums;
return modify(0, arr.length-1);
}
private TreeNode modify(int left, int right) {
if (left > right) return null;
int mid = (right + left) / 2;
TreeNode node = new TreeNode(arr[mid], modify(left, mid - 1), modify(mid + 1, right));
return node;
}
}
leetcode959由斜杠划分区域🔐
- 深度优先搜索
class Solution {
char[][] g;
int N;
public int regionsBySlashes(String[] grid) {
N = grid.length * 3;
g = new char[N][N];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid.length; j++) {
if (grid[i].charAt(j) == '\\')
g[i * 3][j * 3] = g[i * 3 + 1][j * 3 + 1] = g[i * 3 + 2][j * 3 + 2] = '1';
else if (grid[i].charAt(j) == '/')
g[i * 3][j * 3 + 2] = g[i * 3 + 1][j * 3 + 1] = g[i * 3 + 2][j * 3] = '1';
}
}
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (g[i][j] != '1') {
dfs(i, j);
count++;
}
}
}
return count;
}
private void dfs(int i, int j) {
if (i < 0 || i >= N || j < 0 || j >= N) return;
if (g[i][j] == '1') return;
g[i][j] = '1';
dfs(i, j + 1);
dfs(i, j - 1);
dfs(i + 1, j);
dfs(i - 1, j);
}
}
- 并查集
class Solution {
public int regionsBySlashes(String[] grid) {
int regions = 1;
int N = grid.length;
//每行节点数
int nodesPerLine = N + 1;
//N*N的图, 节点数是 (n+1) * (n+1)
UnionFind uf = new UnionFind(nodesPerLine * nodesPerLine);
for (int i = 0; i < N + 1; i++) {
//把边都合并起来, 以2*2为例
//合并0行, 0, 1, 2
uf.union(0, i);
//合并0列, 0, 3, 6
uf.union(0, i * nodesPerLine);
//合并最后行 6, 7, 8
uf.union(N * nodesPerLine, N * nodesPerLine + i);
//合并最后列 2, 5, 8
uf.union(N, (i + 1) * nodesPerLine - 1);
}
for (int i = 0; i < N; i++) {
char[] ca = grid[i].toCharArray();
for (int j = 0; j < ca.length; j++) {
char c = ca[j];
//左上角点
int leftTop = i * nodesPerLine + j;
int top;
int bottom;
if (c == '/') {
top = leftTop + 1;
bottom = leftTop + nodesPerLine;
} else if (c == '\\') {
top = leftTop;
bottom = leftTop + nodesPerLine + 1;
} else {
continue;
}
if (!uf.union(top, bottom)) {
//合并失败 说明成环了, 这时候就 区域数 + 1
regions++;
}
}
}
return regions;
}
private static class UnionFind {
private final int[] roots;
public UnionFind(int n) {
this.roots = new int[n];
for (int i = 0; i < n; i++) {
roots[i] = i;
}
}
int findRoot(int i) {
int root = roots[i];
if (root == i) {
return root;
} else {
roots[i] = findRoot(root);
return roots[i];
}
}
boolean union(int i, int j) {
int root1 = findRoot(i);
int root2 = findRoot(j);
if (root1 != root2) {
roots[root2] = root1;
return true;
}
return false;
}
}
}
leetcode124二叉树中的最大路径和
/**
* 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 Solution {
int maxNum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
process(root);
return maxNum;
}
private int process(TreeNode root) {
if (root == null) return 0;
int leftMax = Math.max(0, process(root.left));
int rightMax = Math.max(0, process(root.right));
maxNum = Math.max(maxNum, leftMax + rightMax + root.val);
return Math.max(leftMax, rightMax) + root.val;
}
}
leetcode99恢复二叉搜索树
- 两种情况1.两个值相临2.不相邻
/**
* 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 Solution {
TreeNode tail_1, tail_2;
public void recoverTree(TreeNode root) {
process(root);
int n = tail_1.val;
tail_1.val = tail_2.val;
tail_2.val = n;
}
TreeNode pre = null;
private void process(TreeNode root) {
if (root.left != null) process(root.left);
if (pre!=null&&root.val <= pre.val) {
if (tail_1 == null) tail_1 = pre;
tail_2 = root;
}
pre = root;
if (root.right != null) process(root.right);
}
}
leetcode979在二叉树中分配硬币🔐
- 转换成路径向上传递
/**
* 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 Solution {
int res = 0;
public int distributeCoins(TreeNode root) {
process(root);
return res;
}
private int process(TreeNode root) {
if (root == null) return 0;
int left = process(root.left);// 左边缺少或多出的个数
int right = process(root.right);// 右边缺少或多出的个数
res += Math.abs(left) + Math.abs(right);// 向root节点传递时,移动的步数
return left + right + root.val - 1;// 整体缺少或多出的个数
}
}
leetcode834树中距离之和🔐
- 戳一戳 — >解题思路
class Solution {
private List<List<Integer>> graph = new ArrayList<>();//邻接表
int[] distSum; //距离和
int[] nodeNum; //子树节点个数(包括自己)
public int[] sumOfDistancesInTree(int N, int[][] edges) {
for(int i = 0; i < N; i++) {
graph.add(new ArrayList<>());
}
for (int[] edge : edges) {
int src = edge[0];
int dst = edge[1];
graph.get(src).add(dst);
graph.get(dst).add(src);
}
distSum = new int[N];
nodeNum = new int[N];
Arrays.fill(nodeNum, 1);
postOrder(0, -1);
preOrder(0, -1);
return distSum;
}
//求root到子树所有节点的距离和
private void postOrder(int root, int parent) {
List<Integer> neighbors = graph.get(root);
for(Integer neighbor : neighbors) {
if(neighbor == parent)
continue; //如果邻接点是父节点,则跳过
postOrder(neighbor, root);
nodeNum[root] += nodeNum[neighbor];
distSum[root] += distSum[neighbor] + nodeNum[neighbor];
}
}
//根据root计算其邻居到所在子树之外的节点的距离和(包括root节点)
private void preOrder(int root, int parent) {
List<Integer> neighbors = graph.get(root);
for(Integer neighbor : neighbors) {
if(neighbor == parent)
continue;
// 这转化看似平平无奇,实际上是动态存储的思想,这样就可以只使用一个公式解决了,不用记录路径长度
distSum[neighbor] = distSum[root] - nodeNum[neighbor] + (graph.size() - nodeNum[neighbor]);
preOrder(neighbor, root);
}
}
}
leetcode102二叉树的层序遍历
/**
* 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 Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List list = new ArrayList<List<Integer>>();
if (root == null) return list;
Queue<TreeNode> queue = new ArrayDeque<>();
queue.add(root);
TreeNode pre = root;
TreeNode next = null;
List<Integer> o = new ArrayList<>();
while (!queue.isEmpty()) {
TreeNode x = queue.poll();
o.add(x.val);
if (x.left != null) {
queue.add(x.left);
next = x.left;
}
if (x.right != null) {
queue.add(x.right);
next = x.right;
}
if (x == pre) {
list.add(o);
o = new ArrayList<>();
pre = next;
next = null;
}
}
return list;
}
}
leetcode107二叉树的层序遍历2
/**
* 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 Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List list = new ArrayList<List<Integer>>();
if (root == null) return list;
Queue<TreeNode> queue = new ArrayDeque<>();
queue.add(root);
TreeNode pre = root;
TreeNode next = null;
List<Integer> o = new ArrayList<>();
while (!queue.isEmpty()) {
TreeNode x = queue.poll();
o.add(x.val);
if (x.left != null) {
queue.add(x.left);
next = x.left;
}
if (x.right != null) {
queue.add(x.right);
next = x.right;
}
if (x == pre) {
list.add(0,o);
o = new ArrayList<>();
pre = next;
next = null;
}
}
return list;
}
}
leetcode199二叉树的右视图
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null) return list;
TreeNode thisFloorLastNode = root;
TreeNode nextFloorLastNode = null;
Queue<TreeNode> deque = new ArrayDeque<>();
deque.add(root);
while (!deque.isEmpty()) {
TreeNode x = deque.poll();
if (x.left != null) {
deque.add(x.left);
nextFloorLastNode = x.left;
}
if (x.right != null) {
deque.add(x.right);
nextFloorLastNode = x.right;
}
if (x == thisFloorLastNode) {
list.add(x.val);
thisFloorLastNode = nextFloorLastNode;
nextFloorLastNode = null;
}
}
return list;
}
}
leetcode114二叉树展开为链表🔐
/**
* 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 Solution {
public void flatten(TreeNode root) {
root = process(root);
}
private TreeNode process(TreeNode root) {
if (root == null) return null;
TreeNode l = process(root.left);
TreeNode r = process(root.right);
root.left = null;
root.right = l;
if (l != null) {
while (l.right != null) {
l = l.right;
}
l.right = r;
} else {
root.right = r;
}
return root;
}
}
leetcode109有序链表转换成二叉搜索树
- 根本上还是分治思想
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
/**
* 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 Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) return null;
if (head.next == null) return new TreeNode(head.val);
if (head.next.next==null)return new TreeNode(head.next.val,new TreeNode(head.val),null);
ListNode pre = null, slow = head, quick = head;
while (quick.next != null && quick.next.next != null) {
pre = slow;
slow = slow.next;
quick = quick.next.next;
}
if (pre != null)
pre.next = null;
TreeNode node = new TreeNode(slow.val);
node.left = sortedListToBST(head);
node.right = sortedListToBST(slow.next);
return node;
}
}
leetcode116填充每个节点的下一个右侧节点指针
- 最开始用的层序遍历
class Solution {
public Node connect(Node root) {
if (root == null) return root;
Node thisFloorLastNode = root;
Node nextFloorLastNode = null;
Node pre= root;
Queue<Node> deque = new ArrayDeque<>();
deque.add(root);
while (!deque.isEmpty()) {
Node x = deque.poll();
if (x.left != null) {
deque.add(x.left);
nextFloorLastNode = x.left;
pre.next=x.left;
pre=x.left;
}
if (x.right != null) {
deque.add(x.right);
nextFloorLastNode = x.right;
pre.next=x.right;
pre=x.right;
}
if (x == thisFloorLastNode) {
thisFloorLastNode = nextFloorLastNode;
nextFloorLastNode = null;
x.next=null;
}
}
return root;
}
}
- 递归实现(太妙了)
class Solution {
public Node connect(Node root) {
if (root == null || root.left == null) return root;
root.left.next = root.right;
if (root.next != null)
root.right.next = root.next.left;
connect(root.left);
connect(root.right);
return root;
}
}
leetcode279完全平方数
- 经典DP
class Solution {
public int numSquares(int n) {
int maxN = (int) Math.sqrt(n);
int[][] dp = new int[maxN + 2][n + 1];
for (int i = 0; i <= n; i++) {
dp[maxN + 1][i] = 10;
}
for (int i = 0; i <= maxN + 1; i++) {
dp[i][0] = 0;
}
for (int i = maxN; i > 0; i--) {
for (int j = 1; j <= n; j++) {
int thisNum = 10;
for (int x = 0; i * i * x <= j; x++) {
thisNum = Math.min(thisNum, x + dp[i + 1][j - i * i * x]);
}
dp[i][j] = thisNum;
}
}
return dp[1][n];
}
}
- 压缩DP
class Solution {
public int numSquares(int n) {
int maxN = (int) Math.sqrt(n);
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
dp[i] = 10;
}
for (int i = maxN; i > 0; i--) {
for (int j = 1; j <= n; j++) {
if (i * i <= j) {
dp[j] = Math.min(dp[j - i * i] + 1, dp[j]);
}
}
}
return dp[n];
}
}
class Solution {
public int numSquares(int n) {
if (isPerfectSquare(n)) {
return 1;
}
if (checkAnswer4(n)) {
return 4;
}
for (int i = 1; i * i <= n; i++) {
int j = n - i * i;
if (isPerfectSquare(j)) {
return 2;
}
}
return 3;
}
// 判断是否为完全平方数
public boolean isPerfectSquare(int x) {
int y = (int) Math.sqrt(x);
return y * y == x;
}
// 判断是否能表示为 4^k*(8m+7)
public boolean checkAnswer4(int x) {
while (x % 4 == 0) {
x /= 4;
}
return x % 8 == 7;
}
}
leetcode101对称二叉树
/**
* 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 Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null)return true;
return pro(root.left,root.right);
}
boolean pro(TreeNode r1,TreeNode r2){
if(r1==null&&r2==null)return true;
if(r1==null||r2==null)return false;
return r1.val==r2.val&&pro(r1.right,r2.left)&&pro(r1.left,r2.right);
}
}
leetcode133克隆图
- 注意map.put位置,要在深搜访问处put
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> neighbors;
public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}
public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}
*/
class Solution {
HashMap<Node, Node> map;
public Node cloneGraph(Node node) {
map = new HashMap<>();
if(node==null)return map;
dfs(node);
return map.get(node);
}
private void dfs(Node node) {
if (map.containsKey(node)) return;
map.put(node, new Node(node.val, new ArrayList<>()));
for (Node n : node.neighbors) {
dfs(n);
map.get(node).neighbors.add(map.get(n));
}
}
}
leetcode103二叉树的锯齿形层序遍历🔐
/**
* 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 Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
ArrayList<List<Integer>> lists = new ArrayList<>();
if (root == null) {
return lists;
}
// 创建两个栈结构
Stack<TreeNode>[] stack = new Stack[]{new Stack<>(), new Stack<>()};
int current = 0;// 当前需要遍历的层需要的栈索引
int next = 1;// 遍历(删除)stack[current]时,填充stack[next]位置的栈空间
stack[current].push(root);// 将根节点放入当前栈中
List<Integer> l=new ArrayList<>();
while (!stack[0].isEmpty() || !stack[1].isEmpty()) {
TreeNode tempNode = stack[current].pop();
l.add(tempNode.val);
// 由于遍历不同层所需要的填入stack[next]顺序不同,所以要分开。
if (current == 0) {
// 不为空就要入栈
if (tempNode.left != null) {
stack[next].push(tempNode.left);
}
if (tempNode.right != null) {
stack[next].push(tempNode.right);
}
} else {
// 不为空就要入栈
if (tempNode.right != null) {
stack[next].push(tempNode.right);
}
if (tempNode.left != null) {
stack[next].push(tempNode.left);
}
}
// 若当前栈空,说明该层节点结束,进行遍历另一个栈结构
if (stack[current].isEmpty()) {
lists.add(l);
l=new ArrayList<>();
// 转换栈结构的索引
current = 1 - current;
next = 1 - next;
}
}
return lists;
}
}
leetcode111二叉树的最小深度
/**
* 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 Solution {
public int minDepth(TreeNode root) {
if (root == null) return 0;
int l = minDepth(root.left), r = minDepth(root.right);
// 若又一边为0表示一边为空,返回不为零的,若均不为0,就返回最小的一方
return (l == 0 || r == 0 ? Math.max(l, r) : Math.min(l, r)) + 1;
}
}
leetcode130被环绕的区域
class Solution {
char[][] grid;
int M,N;
public void solve(char[][] board) {
grid = board;
M = grid.length;
N = grid[0].length;
for (int i = 0; i < M; i++) {
dfs(i, 0);
dfs(i, N - 1);
}
for (int j = 1; j < N - 1; j++) {
dfs(0, j);
dfs(M - 1, j);
}
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
if (grid[i][j] == 'O') {
grid[i][j] = 'X';
} else if (grid[i][j] == 'A') {
grid[i][j] = 'O';
}
}
}
}
private void dfs(int i, int j) {
if(i<0||i>=M||j<0||j>=N)return;
if (grid[i][j] != 'O') return;
grid[i][j] = 'A';
dfs(i, j + 1);
dfs(i, j - 1);
dfs(i + 1, j);
dfs(i - 1, j);
}
}
leetcode52401矩阵
- 贪心思想
- 若用深搜广搜就要从每一个0为起始位置进行深广搜。过程中记录数据最小值即可
class Solution {
public int[][] updateMatrix(int[][] mat) {
int M = mat.length;
if (M==0)return mat;
int N = mat[0].length;
if (N==0)return mat;
mat[0][0] = mat[0][0] == 0 ? 0 : 100000;
for (int i = 1; i < N; i++) {
mat[0][i] = mat[0][i] == 1 ? mat[0][i - 1] + 1 : 0;
}
for (int i = 1; i < M; i++) {
mat[i][0] = mat[i][0] == 1 ? mat[i - 1][0] + 1 : 0;
}
for (int i = 1; i < M; i++) {
for (int j = 1; j < N; j++) {
mat[i][j] = mat[i][j] == 1 ? Math.min(mat[i][j - 1], mat[i - 1][j]) + 1 : 0;
}
}
for (int i = N - 2; i >= 0; i--) {
mat[M - 1][i] = mat[M - 1][i] == 0 ? 0 : Math.min(mat[M - 1][i], mat[M - 1][i + 1] + 1);
}
for (int j = M - 2; j >= 0; j--) {
mat[j][N - 1] = mat[j][N - 1] == 0 ? 0 : Math.min(mat[j][N - 1], mat[j + 1][N - 1] + 1);
}
for (int i = M - 2; i >= 0; i--) {
for (int j = N - 2; j >= 0; j--) {
mat[i][j] = mat[i][j] == 0 ? 0 : Math.min(mat[i][j], Math.min(mat[i][j + 1], mat[i + 1][j]) + 1);
}
}
return mat;
}
}
leetcode529扫雷游戏
class Solution {
private int n, m;
private char[][] matix;
// 相邻的方块坐标、左、右、下、上、左上、右上、左下、右下
int[] X = {0, 0, -1, 1, -1, -1, 1, 1};
int[] Y = {-1, 1, 0, 0, -1, 1, -1, 1};
public char[][] updateBoard(char[][] board, int[] click) {
int x = click[0], y = click[1];
n = board.length;
m = board[0].length;
this.matix = board;
// 若为 E 则 搜索
if (matix[x][y] == 'E') dfs(x, y);
// 若为 M 则 标记为 X 、游戏结束
else if (matix[x][y] == 'M') matix[x][y] = 'X';
return matix;
}
public void dfs(int i, int j) {
// 检查坐标是否 合理
if (!check(i, j) || matix[i][j] != 'E') return;
// 首先查找相邻方块的炸弹数
int num = findM(i, j);
// 无炸弹,标记为 B、 继续递归相邻方块
if (num == 0) {
matix[i][j] = 'B';
for (int p = 0; p < 8; ++p)
dfs(i + X[p], j + Y[p]);
} else {// 有炸弹, 标记为周围的炸弹数
matix[i][j] = (char) (num + 48);
}
}
// 判断坐标是否合理
public boolean check(int i, int j) {
return i >= 0 && j >= 0 && i < n && j < m;
}
// 查找周围的炸弹数
public int findM(int i, int j) {
// 上下左右 、 对角线
int ans = 0;
for (int p = 0; p < 8; ++p)
if (check(i + X[p], j + Y[p]) && matix[i + X[p]][j + Y[p]] == 'M')
++ans;
return ans;
}
}
leetcode524通过删除字母匹配到字典里最长单词
class Solution {
public String findLongestWord(String s, List<String> dictionary) {
String res = "";
for (String each : dictionary) {
if (res.length() > each.length()) continue;
if (isVaild(s, each)) {
if (!(res.length() == each.length() && res.compareTo(each) < 0)) {
res = each;
}
}
}
return res;
}
private boolean isVaild(String s, String each){
int i = 0;
int j = 0;
while (i < s.length() && j < each.length()) {
while (i < s.length() && s.charAt(i) != each.charAt(j)) {
i++;
}
if (i==s.length())return false;// 出现越界,就结束,若没有这句话,若在此时j==each.length()-1,并且未匹配成功,经过后面j++,就会造成结果错误
i++;
j++;
}
return j == each.length();
}
}
leetcode207课程表🔐
- 本质是宽度优先搜索,通过遍历每次的入度进行判断,也是大学里教的,但是是最慢的方法
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[] inNum = new int[numCourses];
for (int[] i : prerequisites) {
inNum[i[0]]++;// 记录入度
}
Queue<Integer> queue = new ArrayDeque<>();
for (int i = 0; i < numCourses; i++) {
if (inNum[i] == 0) {
queue.add(i);// 将入度为0的进入队列
}
}
int num = 0;
while (!queue.isEmpty()) {
int pop = queue.poll();// 删除课程表示当前可以做的
num++;
for (int[] prerequisite : prerequisites) {//pop为谁的前驱,就减一,造成新课程入度为零就入队列
if (prerequisite[1] == pop) {
inNum[prerequisite[0]]--;
if (inNum[prerequisite[0]] == 0) {
queue.add(prerequisite[0]);
}
}
}
}
return num == numCourses;
}
}
- 深度优先搜索,判断有无环的经方式
class Solution {
boolean res = true;
int[] isVisited;
List<List<Integer>> list;// 下标为课程,内部List为后继结点
public boolean canFinish(int numCourses, int[][] prerequisites) {
list = new ArrayList<>();
for (int i = 0; i < numCourses; i++) {
list.add(new ArrayList<>());
}
// 建图
for (int[] i : prerequisites) {
list.get(i[1]).add(i[0]);
}
isVisited = new int[numCourses];
for (int i = 0; i < numCourses && res; i++) {
if (isVisited[i] == 0) {
dfs(i);
}
}
return res;
}
private void dfs(int i) {
isVisited[i] = 1;// 标记,说明为1时指该条路经上正在深搜的边
for (int x : list.get(i)) {
if (isVisited[x] == 0) {
dfs(x);
} else if (isVisited[x] == 1) {// 回到了该条路上深搜的边,说明有环不能上完
res = false;
return;
}
}
// 标记2表示该路劲已经遍历,并且从该点出发无环
isVisited[i] = 2;
}
}
leetcode847访问所有节点的最短路径🔐🔐
class Solution {
public int shortestPathLength(int[][] graph) {
int n = graph.length;
// 1.初始化队列及标记数组,存入起点
Queue<int[]> queue = new LinkedList<>(); // 三个属性分别为 idx, mask, dist
boolean[][] vis = new boolean[n][1 << n]; // 节点编号及当前状态
for (int i = 0; i < n; i++) {
//存入起点(指向方向作用),标记(已经走过的节点记录),从起始节点走过标记节点并且到i的距离
queue.offer(new int[]{i, 1 << i, 0});
vis[i][1 << i] = true;
}
// 开始搜索
while (!queue.isEmpty()) {
int[] tuple = queue.poll(); // 弹出队头元素
int idx = tuple[0], mask = tuple[1], dist = tuple[2];
// 找到答案,返回结果
if (mask == (1 << n) - 1) return dist;
// 扩展
for (int x : graph[idx]) {
int next_mask = mask | (1 << x);
if (!vis[x][next_mask]) {// 若存在,说明定存在有一条其他最优路路,距离不超过dist
queue.offer(new int[]{x, next_mask, dist + 1});
vis[x][next_mask] = true;
}
}
}
return 0;
}
}
leetcode773滑动谜题🔐
- 宽度优先搜索
class Solution {
class Node {
//当前 board 对应的字符串,例如 [[1,2,3],[4,5,0]] ==> 123450, 采用典型的二维数组映射到一维数组的方式
String str;
//当前 board 中 0 的横纵坐标
int row, column;
Node(String str, int row, int column) {
this.str = str;
this.row = row;
this.column = column;
}
}
// 2 X 3 的板
int rows = 2;
int columns = 3;
// 输入的 board 转化后得到的字符串
String inputStr;
// 目标字符串
String targetStr = "123450";
// 输入的 board 中 0 的横、纵坐标
int initRow, initColumn;
// 方向数组
int[][] dirs = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public int slidingPuzzle(int[][] board) {
inputStr = "";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
inputStr += board[i][j];
if (board[i][j] == 0) {
initRow = i;
initColumn = j;
}
}
}
int ans = bfs();
return ans;
}
int bfs() {
Queue<Node> queue = new LinkedList<>();
//记录由原字符串(即输入的 board 转化成的初始字符串)滑动到当前字符串需要移动的次数
Map<String, Integer> map = new HashMap<>();
//典型 bfs 算法,把初始节点添加到队列中
Node root = new Node(inputStr, initRow, initColumn);
queue.offer(root);
// 从 inputStr 滑动到 inputStr 需要移动 0 次
map.put(inputStr, 0);
while (!queue.isEmpty()) {
Node poll = queue.poll();
int step = map.get(poll.str);
//取出队列头节点,如果节点中的字符串已经满足条件,则直接返回
if (poll.str.equals(targetStr)) return step;
//获取节点字符串中 0 元素的横、纵坐标,分别尝试和四个方向的元素交互位置
int currRow = poll.row, currColumn = poll.column;
for (int[] dir : dirs) {
int nextRow = currRow + dir[0], nextColumn = currColumn + dir[1];
//如果下标越界,跳过本次循环
if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns) continue;
// 交换 board[currRow][currColumn] 和 board[nextRow][nextColumn]
String newStr = update(poll.str, currRow, currColumn, nextRow, nextColumn);
// 如果已经处理过 newStr ,则跳过本次循环
if (map.containsKey(newStr)) continue;
//构建新节点并放入队列中,等待下一轮处理
Node next = new Node(newStr, nextRow, nextColumn);
queue.offer(next);
//更新从 inputStr 到 newStr 的滑动次数
map.put(newStr, step + 1);
}
}
return -1;
}
/**
* 交换 board[currRow][currColumn] 和 board[nextRow][nextColumn], 采用典型的二维数组映射到一维数组的方式
*/
String update(String cur, int currRow, int currColumn, int nextRow, int nextColumn) {
char[] cs = cur.toCharArray();
char tmp = cs[currRow * columns + currColumn];
cs[currRow * columns + currColumn] = cs[nextRow * columns + nextColumn];
cs[nextRow * columns + nextColumn] = tmp;
return String.valueOf(cs);
}
}