1、 矩阵中的路径
1.1 题目描述:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
1.2 题解
1.2.1 深度优先搜索 DFS
public boolean exist(char[][] board, String word) {
char[] words = word.toCharArray();
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;
}
/**
* @param board 矩阵
* @param word 目标字符串
* @param i 矩阵行
* @param j 矩阵列
* @param k
* @return
*/
public boolean dfs(char[][] board, char[] word, int i, int j, int k) {
if (i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
if (k == word.length - 1) return true;
char temp = board[i][j];
board[i][j] = '/';//标记已读
boolean result = 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] = temp;//将标记取消
return result;
}
2、机器人的运动范围
2.1 题目描述:
地上有一个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。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
2.2 题解
2.2.1 深度优先
public int movingCount(int m, int n, int k) {
if (m <= 0 || n <= 0 || k < 0)
return 0;
int[] visit = new int[m * n];
return help(0, 0, k, m, n, visit);
}
/**
* @param row 行
* @param col 列
* @param k
* @param m
* @param n
* @param visit 是否已经计算过
* @return
*/
public int help(int row, int col, int k, int m, int n, int[] visit) {
if (row < 0 || col < 0 || row >= m || col >= n || visit[row*n+col] == 1 || sum(row, col) > k)
return 0;
visit[row * n + col] = 1;
return 1 + help(row + 1, col, k, m, n, visit)
+ help(row - 1, col, k, m, n, visit)
+ help(row, col + 1, k, m, n, visit)
+ help(row, col - 1, k, m, n, visit);
}
/**
* 计算和
* @param m
* @param n
* @return
*/
public int sum(int m, int n) {
int sum = 0;
while (m != 0) {
sum += m % 10;
m /= 10;
}
while (n != 0) {
sum += n % 10;
n /= 10;
}
return sum;
}
2.2.2 广度优先
public int movingCount(int m, int n, int k) {
boolean[] visited = new boolean[m * n];
int res=0;
Queue<int[]> queue=new LinkedList<>();
queue.add(new int[]{0,0});
while(queue.size()>0){
int[] x=queue.poll();
int row = x[0], col =x[1],sum=sum(row)+sum(col);
if(row>=m||col>=n||sum>k||visited[row*n+col]==true)continue;
visited[row*n+col]=true;
res++;
queue.add(new int[]{row+1,col});
queue.add(new int[]{row,col+1});
}
return res;
}
/**
* 计算和
*
* @param m
* @return
*/
public int sum(int m) {
int sum = 0;
while (m != 0) {
sum += m % 10;
m /= 10;
}
return sum;
}
3、剪绳子
3.1 题目描述:
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
3.2 题解
3.2.1 找规律
找出最大值:
3:2x1=2;4:2x2=4;
5:3x2=6;6:3x3=9;
7:3x2x2=12;8::3x3x2=18
9:3x3x3=27;10:3x3x2x2=36;
由以上可得出,大于3的数的最大值都是由2和3相乘所得;因此只要得出每个数可分为的3和2的个数即可
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
else {
int k = (n % 3 == 0 ? (n / 3) : ((n - 2) / 3));//k为3的个数
int j = (n + 2) / 3-k;//j为2的个数
int mul = 1;
while (k >0) {
mul*=3;
k--;
}
while(j>0){
mul*=2;
j--;
}
return mul;
}
}
3.2.2 贪心算法
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
long res=1L;
//贪心算法,优先切三,其次切二
while(n>4){
res=res*3;
n-=3;
}
//出来循环只有三种情况,分别是n=2、3、4
return res*n;
}