1.矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
解:从二维数组第一个位置开始遍历,每个位置都有四个方向可以进行查找,当有一个方向位置的字符和给定字符串中对应该位置的字符相等时,就将当前位置转移到下一位置重复操作。数组行为i,列为j,四个方向分别对应(i,j-1),(i-1,j),(i,j+1),(i+1,j)左上右下,使用递归循环进行判断是否有和给定字符串相等元素,越界条件为i,j<0,i >= board.length,j >= board[0].length,终止条件为字符串遍历到最后一位,或二维数组遍历结束
class Solution {
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;
}
public boolean dfs(char[][] board,char[] words,int i,int j,int k){
if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != words[k]){
return false;
}
if(k == words.length-1){
return true;
}
board[i][j] = '\0';
boolean res = dfs(board, words, i + 1, j, k + 1) || dfs(board, words, i - 1, j, k + 1) ||
dfs(board, words, i, j + 1, k + 1) || dfs(board, words, i , j - 1, k + 1);
board[i][j] = words[k];
return res;
}
}
2.机器人的运动范围
地上有一个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。请问该机器人能够到达多少个格子?
解:和上题类似,使用深度优先搜索,不同点在于,这里从第一个元素出发,每次判断右和下即可,如果不满足条件返回后每次只搜索右下两个方向就可完成遍历,还需要另写一个数位之和的方法进行判断数位之和是否满足要求。
时间复杂度 O(MN)O(MN) : 最差情况下,机器人遍历矩阵所有单元格,此时时间复杂度为 O(MN)O(MN) 。
空间复杂度 O(MN)O(MN) : 最差情况下,Set visited 内存储矩阵所有单元格的索引,使用 O(MN)O(MN) 的额外空间。
class Solution {
public int movingCount(int m, int n, int k) {
boolean[][] visit = new boolean[m][n];
return dfs(visit,m,n,k,0,0);
}
private int dfs(boolean[][] visit,int m,int n,int k,int i,int j){
if(i>=m||j>=n||visit[i][j]||getSum(i)+getSum(j)>k){
return 0;
}
visit[i][j] = true;
return 1 + dfs(visit,m,n,k,i+1,j) + dfs(visit,m,n,k,i,j+1);
}
private int getSum(int n){
int sum = 0;
while(n > 0){
sum += n%10;
n = n/10;
}
return sum;
}
}
**3.剪绳子 一 **
给你一根长度为 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。
解:数学推导法:
要先分析出2个问题,才能方便求解,①切多少段最好②每段多少长度
可以得出结论,①等分为a段乘积最大,a为n/x,x为每段长度
②尽可能将绳子以长度 3 等分为多段时,乘积最大。
时间复杂度 O(1): 仅有求整、求余、次方运算。
求整和求余运算:资料提到不超过机器数的整数可以看作是 O(1) ;
幂运算:查阅资料,提到浮点取幂为 O(1)。
空间复杂度 O(1): 变量 a 和 b 使用常数大小额外空间。
class Solution {
public int cuttingRope(int n) {
if(n <= 3){
return n-1;
}
int a = n / 3;
int b = n % 3;
if(b == 0){
return (int)Math.pow(3,a);
}else if(b == 1){
return (int)Math.pow(3,a-1)*4;
}else{
return (int)Math.pow(3,a)*2;
}
}
}
4.剪绳子 二
给你一根长度为 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。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
解:利用循环取余方法
class Solution {
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
long res=1L;
int p=(int)1e9+7;
//贪心算法,优先切三,其次切二
while(n>4){
res=res*3%p;
n-=3;
}
//出来循环只有三种情况,分别是n=2、3、4
return (int)(res*n%p);
}
}