1. 程式人生 > 實用技巧 >劍指offer

劍指offer

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;
    }
 
 
}