62 不同路径,用动态规划做很简单
class Solution {
int res = 0;
public int uniquePaths(int m, int n) {
int[][] matrix = new int[m][n];
//matrix是dp数组,因为从固定方向移动,所以可以这么初始化
//如果四个方向都可以移动,这么做不可以
for(int i = 0; i < m; i++) matrix[i][0] = 1;
for(int i = 0; i < n; i++) matrix[0][i] = 1;
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
//从0位置到i, j 位置i, j 有几条路径
//它可以是从两个方向得到的,从上,i- 1, 从左 j - 1
matrix[i][j] = matrix[i - 1][j] + matrix[i][j - 1];
}
}
return matrix[m - 1][n - 1];
}
}
63 不同路径
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length, n = obstacleGrid[0].length;
int[][] matrix = new int[m][n];
//在初始化第一行和第一列时也要注意如果遇到障碍物直接退出
for(int i = 0; i < m; i++) {
if(obstacleGrid[i][0]==1) break;
matrix[i][0] = 1;
}
for(int i = 0; i < n; i++){
if(obstacleGrid[0][i]==1) break;
matrix[0][i] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
//从0位置到i, j 位置i, j 有几条路径
//它可以是从两个方向得到的,从上,i- 1, 从左 j - 1
if(obstacleGrid[i][j] == 1) continue;
else matrix[i][j] = matrix[i - 1][j] + matrix[i][j - 1];
}
}
return matrix[m - 1][n - 1];
}
}
64 最小路径和
同剑指offer 47. 礼物的最大价值(动态规划)
题目说明:从棋盘的左上角开始拿格子里的礼物,并每次 向右 或者向下 移动一格、直到到达棋盘的右下角。
根据题目说明,易得某单元格只可能从上边单元格或左边单元格到达。
设 f(i, j)f(i,j) 为从棋盘左上角走至单元格 (i ,j)(i,j) 的礼物最大累计价值,易得到以下递推关系:f(i,j)f(i,j) 等于 f(i,j-1)f(i,j−1) 和 f(i-1,j)f(i−1,j) 中的较大值加上当前单元格礼物价值 grid(i,j)grid(i,j) 。
f(i,j) = max[f(i,j-1), f(i-1,j)] + grid(i,j)
class Solution {
public int maxValue(int[][] grid) {
int m = grid.length, n = grid[0].length;
for(int j = 1; j < n; j++) // 初始化第一行
grid[0][j] += grid[0][j - 1];
for(int i = 1; i < m; i++) // 初始化第一列
grid[i][0] += grid[i - 1][0];
for(int i = 1; i < m; i++)
for(int j = 1; j < n; j++)
//从上面和左面中选择最大的一个
grid[i][j] += Math.max(grid[i][j - 1], grid[i - 1][j]);
return grid[m - 1][n - 1];
}
}
剑指 Offer 04. 二维数组中的查找
行从左到右递增,列从上到下递增
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
//根据矩阵的性质可得,左下角/右上角的元素上边和左边/下边和右边呈现出不同的元素递增关系
//我这里边先的是从左下角
int i = matrix.length - 1, j = 0;
while(i >= 0 && j < matrix[0].length)
{
//如果它比目标元素大,向上一行
if(matrix[i][j] > target) i--;
//如果它比目标元素小,则向右移动一列
else if(matrix[i][j] < target) j++;
//如果存在直接返回真
else return true;
}
return false;
}
}
剑指offer 12. 矩阵中的路径( DFS + 剪枝 ,清晰图解)
board数组防止数据重复访问
class Solution {
public boolean exist(char[][] board, String word) {
char[] words = word.toCharArray();
//因为可以从矩阵中任意点开始,所以要两层for循环遍历所有节点
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
//如果有直接符合条件的,直接返回
if(dfs(board, words, i, j, 0)) return true;
}
}
return false;
}
boolean dfs(char[][] board, char[] word, int i, int j, int k) {
//超过边界4个边界,提前剪枝,当前元素和目标元素不同时也退出
if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
//如果遍历了word的长度,则说明找到了,直接返回,也属于提前剪枝
if(k == word.length - 1) return true;
board[i][j] = '\0';
//寻找四个方向的,有一个为真就可以
boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||
dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
board[i][j] = word[k];
return res;
}
}
剑指offer13机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
class Solution {
public int movingCount(int m, int n, int k) {
//标记当前格子是否被访问过
boolean[][] visited = new boolean[m][n];
//参数:visited数组、m、n、k、当前所处格子,只往右下走
return dfs(visited, m, n, k, 0, 0);
}
private int dfs(boolean[][] visited, int m, int n, int k, int i, int j){
//递归终止条件
if(i >= m || j >= n || bitSum(i) + bitSum(j) > k || visited[i][j]) return 0;
visited[i][j] = true;
//当前格 + 往下走 + 往右走
return 1 + dfs(visited, m, n, k, i + 1, j) + dfs(visited, m, n, k, i, j + 1);
}
private int bitSum(int x){
int sum = 0;
while(x != 0){
sum += x % 10;
x /= 10;
}
return sum;
}
}
剑指 Offer 29. 顺时针打印矩阵 做法:模拟
同54. 螺旋矩阵 59. 螺旋矩阵 II 类似
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
//设置矩阵四个边界的值
int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1, x = 0;
int[] res = new int[(r + 1) * (b + 1)];
while(true) {
//第一次,从左边到右边
for(int i = l; i <= r; i++) res[x++] = matrix[t][i]; // left to right.
//第二次,先遍历上边界++是否大于下边界,如果是再退出
if(++t > b) break;
for(int i = t; i <= b; i++) res[x++] = matrix[i][r]; // top to bottom.
//第三次,先遍历左边界是否比右边界--要大,如果是则退出
if(l > --r) break;
for(int i = r; i >= l; i--) res[x++] = matrix[b][i]; // right to left.
//第四次,先遍历上边界是否大于下边界--,如果是则退出
if(t > --b) break;
for(int i = b; i >= t; i--) res[x++] = matrix[i][l]; // bottom to top.
//第一次没有判断条件在这里了,判断左边界++是否大于右边界,如果是则退出
if(++l > r) break;
}
return res;
}
}
岛屿数量
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == '1'){
dfs(grid, i, j);
count++;
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j){
if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
//遍历完为1的区域让它变为0
grid[i][j] = '0';
dfs(grid, i + 1, j);
dfs(grid, i, j + 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
}
岛屿的最大面积
是200题的另一个问法,问这些岛屿中面积最大的是哪个?
class Solution {
public int maxAreaOfIsland(int[][] grid) {
if(grid == null || grid.length == 0) return 0;
int m = grid.length, n = grid[0].length;
int maxArea = 0; //记录最大岛屿面积,最终返回
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j] == 1){
//以陆地为中心向四周找
int curArea = dfs(grid, i, j);
//更新最大岛屿面积
maxArea = Math.max(maxArea, curArea);
}
}
}
return maxArea;
}
/**dfs向四周找陆地 */
private int dfs(int[][] grid, int i, int j){
//递归终止:越界 或者 走到了水域
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0;
grid[i][j] = 0; //标记为0,防止重复访问
//上下左右搜索
int up = dfs(grid, i - 1, j);
int down = dfs(grid, i + 1, j);
int left = dfs(grid, i, j - 1);
int right = dfs(grid, i, j + 1);
return up + down + left + right + 1;
}
}
矩阵中的最长递增路径
这个题,因为起点可以不是0,0 相对递归来説要简单
class Solution {
public int longestIncreasingPath(int[][] matrix) {
if(matrix.length == 1 && matrix[0].length == 1) return matrix[0][0];
int row = matrix.length, column = matrix[0].length;
int res = Integer.MIN_VALUE;
int[][] memo = new int[n][n];
int res = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
// 若没有搜索过才需要进行搜索
if(memo[i][j] == 0) {
res = Math.max(res, dfs(i, j,memo, matrix));
}
// 这里为什么没有比较memo[i][j]!=0的情况?
// 因为后面matrix[nextI][nextJ]为起点的路径总比matrix[i][j]为起点的短
// 满足matrix[nextI][nextJ]>matrix[i][j]才会进行dfs的
}
}
return res;
}
}
/*
返回以matrix[i][j]为起点的最长递增路径
*/
private static int dfs(int i, int j, int[][]memo,int[][] matrix) {
// 若之前搜索过了直接返回之前存储的最大长度
if(memo[i][j] != 0) {
return memo[i][j];
}
int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
// 以matrix[i][j]为起点的最长递增路径
int maxLen = 1;
int n = matrix.length;
for(int[] dir : dirs) {
int nextI = i + dir[0];
int nextJ = j + dir[1];
if(nextI >= 0 && nextI < n && nextJ >= 0 && nextJ < n
&& matrix[nextI][nextJ] > matrix[i][j]) {
// 选择4个方向的最大路径的最大值作为maxLen
maxLen = Math.max(maxLen, dfs(nextI, nextJ,memo ,matrix) + 1);
}
}
// 将以matrix[i][j]为起点的最长递增路径存储在memo[i][j]中
// 注意:在递归过程中将matrix[nextI,nextJ]为起点的最长路径都存储在memo了
memo[i][j] = maxLen;
// 返回该最长路径长度
return maxLen;
}
走迷宫的最短路径
public class Main {
private static int min=8888,total=0;
static int Dire[][]={{0,1},{1,0},{0,-1},{-1,0}};
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String input = "";
while (null != (input = reader.readLine())) {
int n = Integer.parseInt(input);
int[][] arr = new int[n][n];
//int res = 0;
for (int k = 0; k < n; k++) {
String[] tmp = reader.readLine().split(" ");
for (int j = 0; j < n; j++) {
arr[k][j] = Integer.parseInt(tmp[j]);
}
}
boolean[][] b = new boolean[n][n];
b[0][0] = true;
if (arr[0][0] == 0) {
System.out.println(0);
System.out.println(0);
}
if (n == 1 && arr[0][0] == 1) {
System.out.println(1);
System.out.println(1);
}
dfs(arr, 0, 0, 0, b);
System.out.println(min);
System.out.println(total);
}}
public static void dfs(int[][] matrix,int x,int y,int step,boolean[][] book){
int tx,ty;
if(x==matrix.length- 1 &&y==matrix.length - 1 ) {
if(min>step) {
min=step;
total=0;
}if(min == step) {
total++;
}
return;
}
else {
for(int i=0;i<4;i++){
tx=x+Dire[i][0]; //改变坐标
ty=y+Dire[i][1];
if(tx<matrix.length && tx>=0 && ty>=0 && ty<matrix.length &&matrix[tx][ty]==1&&book[tx][ty]==false){ //判断当前即将移动的坐标是否满足条件
book[tx][ty]=true; //递去过程中 标记当前位置已走过
dfs(matrix,tx,ty,step+1, book);
book[tx][ty]=false; //归来过程中 取消标记
}
}
return;
}
}
}