1. 程式人生 > 其它 >【lLeetCode】動歸

【lLeetCode】動歸

一維

70 爬樓梯E


198 小偷E

  1. 解法:
dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i-1]);

413 等差數列劃分M

  1. 題意:找出陣列中等差數列的數量(最少為3個元素算一個等差數列)
  2. 解法:
  • 差分:
        for(int i = 2; i < n; ++i){
            if(nums[i-1] - nums[i] == d){
                t++;
            }else{
                d = nums[i-1] - nums[i];
                t = 0;
            }
            ans += t;
  • 滑動視窗:
        for(int i = 2; i < n; ++i){
            int d = nums[i] - nums[i-1];
            if(d == pred){
                L++; //滑動視窗增加
            }else{
                res += (L-1)*(L-2)/2; //規律
                L = 2; //滑動視窗重新設為2
                pred = d;
            }
        }
        //對最後一組滑動視窗再計算一次
        res += (L-1)*(L-2)/2;
  • 動態規劃:
        for(int i = 2; i < n; ++i){
            if(nums[i] - nums[i-1] == nums[i-1] - nums[i-2]){
                dp[i] = dp[i-1] + 1; //等差數列相關的狀態轉移方程
                res += dp[i];
            }
        }

二維

64 最小路徑和M

  1. 題意:非負二維陣列,從左上到右下角的最小路徑和
  2. 解法:
  • 動態規劃:
    狀態轉移方程:dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];


    但是i=0和j=0的時候要判斷

  • 動態規劃(二維變一維):

        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                if(i == 0 && j == 0){
                    dp[j] = grid[i][j];
                }else if(i == 0){
                    dp[j] = dp[j-1] + grid[i][j];
                }else if(j == 0){
                    dp[j] = dp[j] + grid[i][j];
                }else{
                    dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j];
                }
            }
        }

542 01矩陣M

  1. 題意:輸出由01組成的矩陣每個元素與0的距離(0是0,1要看離它最近的0)
  2. 解法:
  • bfs:讓所有的0入隊,遍歷一圈找到離它們最近的1入隊,並dist++,
        //bfs
        while(!queue.isEmpty()){
            int[] cell = queue.poll();
            int x = cell[0];
            int y = cell[1];

            for(int[] di : dirs){
                int nx = x + di[0];
                int ny = y + di[1];
                if(nx >= 0 && ny >= 0 && nx < m && ny < n && !visited[nx][ny]){
                    if(mat[nx][ny] != 0){
                        dist[nx][ny] = dist[x][y] + 1;
                        visited[nx][ny] = true;
                        queue.offer(new int[]{nx, ny});
                    }
                }
            }
        }
  • 動態規劃:從左上右上右下左下四種方向,設定移動方向,比較距離最小值。
//左上。即後來的dist值與左邊和上邊的dist值進行比較。
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                if(i-1 >= 0){
                    dist[i][j] = Math.min(dist[i][j], dist[i-1][j] + 1);
                }
                if(j-1 >= 0){
                    dist[i][j] = Math.min(dist[i][j], dist[i][j-1] + 1);
                }
            }
        }

221 最大正方形M

  1. 題意:找出01矩陣中包含的最大的正方形,輸出面積
  2. 思路:
  • 暴力法:找到一個1就當做正方形的左上角,在剩餘可圍成的最大矩形中,先判斷斜線上的元素是否為1,若為1,則判斷該元素行和列上的元素是否為1,都為1則記錄邊長
                //遍歷到1將其作為正方形左上角
                if(matrix[i][j] == '1'){
                    res = Math.max(res, 1);

                    //還剩下的最大矩陣邊長reMain
                    int reMain = Math.min(m-i, n-j);
                    //遍歷斜線
                    for(int k = 1; k < reMain; ++k){
                        boolean flag = true;
                        if(matrix[i+k][j+k] == '0'){
                            break;
                        }

                        //當斜線上的元素符合時,再檢查該處行和列上的元素
                        for(int x = 0; x < k; ++x){
                            if(matrix[i+x][j+k] == '0' || matrix[i+k][j+x] == '0'){
                                flag = false;
                                break;
                            }
                        }

                        //每多在斜線上前進一格並判斷成功,記錄res
                        if(flag == true){
                            res = Math.max(k+1, res);
                        }else{
                            break;
                        }
  • 動態規劃:
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                //當前位置為‘0’
                if(matrix[i][j] == '0'){
                    dp[i][j] = 0;
                }else{
                    if(i == 0 || j == 0){
                        dp[i][j] = 1;
                    }else{
                    //狀態轉移方程
                        dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i-1][j-1]), dp[i][j-1]) + 1;
                    }
                }
                res = Math.max(dp[i][j], res); 
            }

279 完全平方數M

  1. 題意:等價於給定若干個數字,每個數字可以被使用無限次,求能湊出n使用的數字最少個數
  2. 沒有限制數字只能用一次,所以是完全揹包問題
  • 動歸:一維
for(int i = 1; i <= n; ++i){
  for(int j = 1; j*j < i; ++j){
    dp[i] = Math.min(dp[i], dp[i-j*j] + 1);
  }
} 

+ 動歸:**二維完全揹包**
***
### 91 解碼方法M


***