刷題程序員面試金典第9章

 

目錄

1、上樓梯

2、機器人走方格I

3、機器人走方格II

4、魔術索引 II



1、上樓梯

有個小孩正在上樓梯,樓梯有n階臺階,小孩一次可以上1階、2階、3階。請實現一個方法,計算小孩有多少種上樓的方式。爲了防止溢出,請將結果Mod 1000000007

給定一個正整數int n,請返回一個數,代表上樓的方式數。保證n小於等於100000。

測試樣例1:

1
返回:1

測試樣例2:

3
返回:4

測試樣例3:

4
返回:7

/*

思路:上1級有一種,2級上1級後再上1級,3級有上1級之後上2級或上2級之後上1級或直接上3級

4級有1級上3級,2級上2級,3級上1級

總結起來有:f(1)=1,f(2)=2,f(3)=4,f(4)=f(1)+f(2)+f(3);f(5)=f(2)+f(3)+f(4)

f(n)=f(n-1)+f(n-2)+f(n-3);

本來使用遞歸做的,結果遞歸做到最後超時了,只好用迭代了;

*/

public static int countWays(int n) {
        if(n<1) return 0;
        if(n==1) return 1;
        if(n==2) return 2;
        if(n==3) return 4;
        int array[] =new int[n];
        array[0] =1;
        array[1] =2;
        array[2] =4;
        for(int i=3;i<n;i++){
            array[i]=((array[i-1]+array[i-2])%1000000007+array[i-3]%1000000007)%1000000007;
        }
        return array[n-1];
    }

2、機器人走方格I

第一種解法:

由於題目中x+y<=12,所以不必擔心遞歸超時問題,對於每一步,只要沒有走到

邊緣(x==1||y==1)就會有兩種選擇:向下走(x-1)or 向右走(y-1),終

止條件即走到邊緣,只能一直走下去,即此時只有一種走法。

 public int countWays(int x, int y) {
        if(x<1||y<1){
            return 0;
        }
        if(x==1||y==1){
            return 1;
        }
        return countWays(x-1,y)+countWays(x,y-1);
    }

第二種解法:

基本動態規劃
 public int countWays(int x, int y) {
        int[][] dp = new int[x][y];
        dp[0][0] = 1;
        for(int i = 1; i < x; i++){
            dp[i][0] = dp[i-1][0];
        }
        for(int i = 1; i < y; i++){
            dp[0][i] = dp[0][i-1];
        }
        for(int i = 1; i < x; i++){
            for(int j = 1; j < y; j++){
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[x-1][y-1];
    }

第三種解法:

考慮原始DP問題爲二維數組表示當前位置的步數,顯然有: dp[i][j] = dp[i-1][j] + dp[i][j-1],
而容易發現dp數組可以壓縮爲1維存儲空間dp[y]。原dp[i-1][j]爲上一行當前列的步數,
而現dp[j]就存儲了上一次該列的步數,而現dp[j-1]爲左節點的步數即原dp[i][j-1]。
所以變爲:dp[j] = dp[j] + dp[j-1].
 public int countWays(int x, int y) {
        // write code here
        int dp[] =new int[y];
        for(int i = 0; i < y; i++)
            dp[i] = 1;
        for(int i = 1; i < x; i++){
            for(int j = 1; j< y; j++){
                dp[j] = dp[j] + dp[j-1];
            }
        }
        return dp[y-1];
    }

3、機器人走方格II

 /*

     * 1.判斷右下角的點以及起點自身是否爲障礙點,若是返回0;

     * 2.若右下角的點非障礙點,判斷上面和左邊是否爲障礙點

     *  1.若全都爲障礙點,返回0

     *  2.若一個爲障礙點,一個不是,則到該點的路徑數等於上一個點的路徑數(這是遞歸的思路)

     * 第2部分可以不用遞歸,而用循環:

     *  dp[i-1][j-1]表示從(0,0)到(i,j)的方法數,如果(i,j)非1,則爲障礙點,對應dp[i-1][j-1]爲0

     *  其餘情況與一般dp相同

     */

public int countWays(int[][] map, int x, int y) {
     if(map == null || map.length != x || map[0].length != y){
        return 0;
    }
    if(map[x-1][y-1] != 1 || map[0][0] != 1){//最後一個點爲障礙點
        return 0;
    }
    int dp[][] = new int[x][y];
    dp[0][0] = 1;
    for(int i = 1; i < x; i++){
        if(map[i][0] != 1){
            dp[i][0] = 0;
        }else{
            dp[i][0] = dp[i-1][0];
        }
    }
    for(int i = 1; i < y; i++){
        if(map[0][i] != 1){
            dp[0][i] = 0;
        }else{
            dp[0][i] = dp[0][i-1];
        }
    }
    for(int i = 1; i < x; i++){
        for(int j = 1; j < y; j++){
            if(map[i][j] != 1){
                dp[i][j] = 0;
            }else{
                dp[i][j] = dp[i-1][j]%1000000007 + dp[i][j-1]%1000000007;
            }
        }
    }
    return (dp[x-1][y-1]%1000000007);
    }

4、魔術索引 II

在數組A[0..n-1]中,有所謂的魔術索引,滿足條件A[i]=i。給定一個不下降序列,元素值可能相同,編寫一個方法,判斷在數組A中是否存在魔術索引。請思考一種複雜度優於o(n)的方法。

給定一個int數組A和int n代表數組大小,請返回一個bool,代表是否存在魔術索引。

測試樣例:

[1,1,3,4,5]
返回:true

二分法

   public boolean findMagicIndex(int[] A, int n) {
       return findMagic(A,0,n-1);
    }
    private boolean findMagic(int[] A,int start,int end){
        int mid=(start+end)>>1;
        if(start>end){
            return false;
        }
        if(A[start]==start||A[end]==end||A[mid]==mid){
            return true;
        }
        return findMagic(A,start+1,mid)||findMagic(A,mid+1,end-1);
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章