劍指offer
阿新 • • 發佈:2020-07-02
1、剪繩子
給你一根長度為n的繩子,請把繩子剪成整數長的m段(m、n都是整數,n>1並且m>1,m<=n),每段繩子的長度記為k[1],...,k[m]。請問k[1]x...xk[m]可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別為2、3、3的三段,此時得到的最大乘積是18。輸入描述:
輸入一個數n,意義見題面。(2 <= n <= 60)
輸出描述:
輸出答案。示例1
輸入
8
輸出
18
/**
* 解題思路,找出最優解的規律
* 當target等於1,2,3的時候,結果是固定的
* 當target大於3的時候,可以看以下資料
* target=4, 最優解:2 2
* target=5, 最優解:3 2
* target=6, 最優解:3 3
* target=7, 最優解:3 2 2
* target=8, 最優解:3 3 2
* target=9, 最優解:3 3 3
* target=10,最優解:3 3 2 2
* target=11,最優解:3 3 3 2
* target=12,最優解:3 3 3 3
* target=13,最優解:3 3 3 2 2
* target=14,最優解:3 3 3 3 2
* target=15,最優解:3 3 3 3 3
*
* 所以不難發現3和2的個數規律
*/
//動態規劃
public class Solution {
public int cutRope(int target) {
int[] dp=new int[target+1];
if(target<=3)return target-1;
/*
下面3行是n>=4的情況,跟n<=3不同,4可以分很多段,比如分成1、3,
這裡的3可以不需要再分了,因為3分段最大才2,不分就是3。記錄最大的。
第二個迴圈為什麼j<=i/2是因為1*3和3*1是一樣的,沒必要計算在內,只要計算到1*3和2*2就好了
*/
dp[1]=1;
dp[2]=2;
dp[3]=3;
for(int i=4;i<=target;i++){
for(int j=1;j<=i/2;j++){
dp[i]=Math.max(dp[i],dp[j]*dp[i-j]);
}
}
return dp[target];
//找規律
/*if(target<=3)return target-1;
int a=target/3;
int b=target%3;
if(b==2)
return (int)Math.pow(3,a)*2;
if(b==1)
return (int)Math.pow(3,a-1)*4;
if(b==0)
return (int)Math.pow(3,a);
return 0; */
}
}
2、機器人的運動範圍
地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k為18時,機器人能夠進入方格(35,37),因為3+5+3+7 = 18。但是,它不能進入方格(35,38),因為3+5+3+8 = 19。請問該機器人能夠達到多少個格子?
package arrays;
public class movingCount_JZ66 {
public static void main(String[] args) {
System.out.println(movingCount(2,3,3));
}
public static int movingCount(int threshold, int rows, int cols){
boolean[][] flag = new boolean[rows][cols];
return move(0,0,threshold,rows,cols,flag);
}
public static int move(int i,int j,int threshold, int rows, int cols,boolean[][] flag){
if(i<0||i>=rows||j<0||j>=cols||sum(i)+sum(j)>threshold||flag[i][j]==true)return 0;
flag[i][j]=true;
return move(i,j-1,threshold,rows,cols,flag)
+ move(i,j+1,threshold,rows,cols,flag)
+move(i-1,j,threshold,rows,cols,flag)
+ move(i+1,j,threshold,rows,cols,flag)+1;
}
public static int sum(int i){
int res=0;
while(i!=0){
res+=i%10;
i/=10;
}
return res;
}
}
3. 單詞搜尋(二維陣列)
給定一個二維網格和一個單詞,找出該單詞是否存在於網格中。
單詞必須按照字母順序,通過相鄰的單元格內的字母構成,其中“相鄰”單元格是那些水平相鄰或垂直相鄰的單元格。同一個單元格內的字母不允許被重複使用。
示例:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
給定 word = "ABCCED", 返回 true
給定 word = "SEE", 返回 true
給定 word = "ABCB", 返回 false
package leetcode;
public class wordSearch_80 {
public static void main(String[] args) {
char[][] board = { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'E', 'S' }, { 'A', 'D', 'E', 'E' } };
String word = "ABE";
System.out.println(exist(board, word));
}
public static boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
boolean[][] flag = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (find(i, j, board, word, 0, flag)) {
return true;
}
}
}
return false;
}
public static boolean find(int i, int j, char[][] board, String word, int x, boolean[][] flag) {
if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || word.charAt(x) != board[i][j]
|| flag[i][j] == true)
return false;
if (x == word.length() - 1)
return true;
flag[i][j] = true;
if (find(i - 1, j, board, word, x + 1, flag) || find(i + 1, j, board, word, x + 1, flag)
|| find(i, j - 1, board, word, x + 1, flag) || find(i, j + 1, board, word, x + 1, flag)) {
return true;
}
flag[i][j] = false;
return false;
}
}
4、矩陣中的路徑(和第3題一樣,區別是給出的是一維陣列)
請設計一個函式,用來判斷在一個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。 例如
矩陣中包含一條字串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因為字串的第一個字元b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//標誌位,初始化為false
boolean[] flag = new boolean[matrix.length];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
//迴圈遍歷二維陣列,找到起點等於str第一個元素的值,再遞迴判斷四周是否有符合條件的----回溯法
if(judge(matrix,i,j,rows,cols,flag,str,0)){
return true;
}
}
}
return false;
}
//judge(初始矩陣,索引行座標i,索引縱座標j,矩陣行數,矩陣列數,待判斷的字串,字串索引初始為0即先判斷字串的第一位)
private boolean judge(char[] matrix,int i,int j,int rows,int cols,boolean[] flag,char[] str,int k){
//先根據i和j計算匹配的第一個元素轉為一維陣列的位置
int index = i*cols+j;
//遞迴終止條件
if(i<0 || j<0 || i>=rows || j>=cols || matrix[index] != str[k] || flag[index] == true)
return false;
//若k已經到達str末尾了,說明之前的都已經匹配成功了,直接返回true即可
if(k == str.length-1)
return true;
//要走的第一個位置置為true,表示已經走過了
flag[index] = true;
//回溯,遞迴尋找,每次找到了就給k加一,找不到,還原
if(judge(matrix,i-1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i+1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i,j-1,rows,cols,flag,str,k+1) ||
judge(matrix,i,j+1,rows,cols,flag,str,k+1) )
{
return true;
}
//走到這,說明這一條路不通,還原,再試其他的路徑
flag[index] = false;
return false;
}
}