ソードフィンガーオファー13.ロボットの可動域-幅優先探索、再帰

1.タイトル

座標[0,0]から座標[m-1、n-1]まで、地面にm行n列の正方形があります。ロボットは座標[0、0]のグリッドから移動を開始します。ロボットは、一度に1つのグリッドを左、右、上、下に移動でき(グリッドの外側には移動できません)、行座標の合計を入力できません。 k格子より大きい列座標。たとえば、kが18の場合、3 + 5 + 3 + 7 = 18であるため、ロボットは正方形[35、37]に入ることができます。ただし、3 + 5 + 3 + 8 = 19であるため、正方形[35、38]に入ることができません。ロボットはいくつのグリッドに到達できますか?

第二に、問題解決1-再帰的実現

4方向に検索

class Solution {
    
    

    public int dig_num(int target){
    
    
        int sum = 0;
        while(target>0){
    
    
            sum+=target%10;
            target/=10;
        }

        return sum;
    }

    public int dfsSolver(int startL,int startR,int m,int n,int k,int[][] visited){
    
    
        if(startL<0||startR<0||startL>=m||startR>=n||dig_num(startL)+dig_num(startR)>k||visited[startL][startR]==1){
    
    
            return 0;
        }
        visited[startL][startR]=1;
        return 1+dfsSolver(startL-1,startR,m,n,k,visited)+dfsSolver(startL+1,startR,m,n,k,visited)+dfsSolver(startL,startR-1,m,n,k,visited)+dfsSolver(startL,startR+1,m,n,k,visited);
    }

    public int movingCount(int m, int n, int k) {
    
    
        int[][] visited = new int[m][n];
        return dfsSolver(0,0,m,n,k,visited);
    }
}

問題解決手順

行座標と列座標がkより大きいグリッドを障害物と見なします。この質問は非常に伝統的な検索質問です。幅優先探索または深さ優先探索を使用して解決できます。この記事では、幅優先探索を使用します。説明されています。

では、数字の桁の合計を計算する方法は?毎回xから10までの余りをとるだけで、xの単位桁がわかり、xを10で割ることができます。この操作は、xの10進数を1桁シフトするのと同じです。右に移動して削除する桁数(バイナリの>>右シフト演算子と同様)は、xの終わりが0になるまで繰り返されます。

同時に、この問題には隠れた最適化があります。検索プロセス中に、上下に検索する代わりに、検索方向を右と下に減らすことができます。下の図に示すように、制限条件kを拡大した16 * 16マップ、実行可能な正方形の変化傾向を示します。各正方形の値は、行と列の座標の合計です。青い正方形は、障害物ではない正方形、つまり、その値は現在の制限条件k以下です。制限条件kが大きくなると、(0、0)が配置されている青い正方形の領域に新しく追加された障害物のない正方形は、上部または左側の正方形を1ステップ移動することで取得できることがわかります。kが増加すると、他の切断された青いグリッド領域が接続されます。接続されると、上または左のグリッドを1ステップ移動することによっても取得されるため、検索方向を右または下に減らすことができます。

3.問題解決2-幅優先探索

class Solution {
    
    

    public int dig_num(int target){
    
    
        int sum = 0;
        while(target>0){
    
    
            sum+=target%10;
            target/=10;
        }

        return sum;
    }

    public int movingCount(int m, int n, int k) {
    
    
        if(k==0){
    
    
            return 1;
        }

        int[] dx = {
    
    1,0};
        int[] dy = {
    
    0,1};
        int[][] visited = new int[m][n];
        visited[0][0] = 1;
        Queue<int[]> queue = new LinkedList<int[]>();

        queue.add(new int[]{
    
    0,0});
        int res=1;
        while(!queue.isEmpty()){
    
    
            int[] cell = queue.poll();
            int x = cell[0];
            int y = cell[1];

            for(int i=0;i<2;i++){
    
    
                int tx = x+dx[i];
                int ty = y+dy[i];
                if(tx<0||tx>=m||ty<0||ty>=n||dig_num(tx)+dig_num(ty)>k||visited[tx][ty]==1){
    
    
                    continue;
                }
                queue.offer(new int[]{
    
    tx,ty});
                visited[tx][ty] = 1;
                res++;
            }
        }

        return res;


    }
}

4、再帰

ここに画像の説明を挿入

class Solution {
    
    

    public int dig_num(int target){
    
    
        int sum = 0;
        while(target>0){
    
    
            sum+=target%10;
            target/=10;
        }

        return sum;
    }

    public int movingCount(int m, int n, int k) {
    
    
        if(k==0){
    
    
            return 1;
        }

        int[][] visited = new int[m][n];
        visited[0][0] = 1;

        int res=1;
        for(int i=0;i<m;i++){
    
    
            for(int j=0;j<n;j++){
    
    
                if(i==0&&j==0||dig_num(i)+dig_num(j)>k){
    
    
                    continue;
                }
                if(i-1>=0){
    
    
                    visited[i][j]|=visited[i-1][j];
                }
                if(j-1>=0){
    
    
                    visited[i][j]|=visited[i][j-1];
                }
                res+=visited[i][j]==1? 1:0;
            }
        }

        return res;
    }
}

おすすめ

転載: blog.csdn.net/Cxf2018/article/details/109586461