算法学习笔记----暴力递归改记忆化搜索改动态规划 (对数器对比)

目录

机器人移动

选硬币

两个绝顶聪明的人

棋盘马跳位置

鲍勃走格子

选货币每种可以选无限张


递归尝试->记忆化搜索->动态规划

暴力递归有重复计算,二叉展开,时间复杂度O(2^k)

记忆化搜索:递归时带入一张表,先获取表中信息,没计算过为-1,遇到重复计算直接获取答案 时间复杂度O(K*N)

递归(尝试)->记忆化搜索(加入缓存)->动态规划: 1、分析可变参数变化范围 2、标出计算的终止位置 3、标出不用计算就可知道的答案 4、普遍位置是如何依赖其他位置 5、确定计算顺序

机器人移动

给定1~N个长度,机器人初始在start位置,每一步必须移动,经过k步到达end的方法有多少种。

package com.wtp.基础提升.暴力递归改动态规划;
​
public class 机器人移动 {
​
    
    /**
     * 
     * @param N     1~N的位置
     * @param E     最终到达E
     * @param rest  还剩多少步
     * @param cur   当前位置
     * @return
     */
    public static int f1(int N,int E,int rest,int cur) {//二叉展开 时间复杂度O(2^rest)
        if(rest == 0) {
            return cur == E ? 1 : 0;
        }
        if(cur == 1) {
            return f1(N,E,rest - 1,2);
        }
        if(cur == N) {
            return f1(N,E,rest - 1,N - 1);
        }
        return f1(N,E,rest - 1,cur + 1) + f1(N,E,rest - 1,cur - 1); 
    }
    
    public static int w(int N,int E,int rest,int cur){
        
        int[][] dp = new int[N+1][rest+1];
        for(int i = 0;i <= N;i++) {
            for(int j = 0;j<=rest;j++) {
                dp[i][j] = -1;
            }
        }
        return f1(N,E,rest,cur,dp);
    }
    
    //记忆化搜索 剪枝,已经计算过的直接从缓存种取 时间复杂度:O(N*rest)
    public static int f1(int N,int E,int rest,int cur,int[][] dp) {
        
        if(dp[cur][rest] != -1) {
            return dp[cur][rest];
        }
        
        if(rest == 0) {
            dp[cur][rest] = cur == E ? 1 : 0;
            return dp[cur][rest];
        }
        if(cur == 1) {
            dp[cur][rest] = f1(N,E,rest - 1,2);
        }else if(cur == N) {
            dp[cur][rest] = f1(N,E,rest - 1,N - 1);
        }else {
            dp[cur][rest] = f1(N,E,rest - 1,cur + 1) + f1(N,E,rest - 1,cur - 1);
        }
        
        return dp[cur][rest]; 
    }
    
    //严格表结构动态规划 时间复杂度于记忆化搜索相同
    public static int dpWay(int N,int start,int end,int K) {
        int[][] dp = new int[K + 1][N+1];
        dp[0][end] = 1;
        
        for(int rest = 1;rest <= K;rest++) {
            for(int cur = 1;cur <= N;cur++) {
                if(cur == 1) {
                    dp[rest][cur] = dp[rest-1][2];
                }else if(cur == N) {
                    dp[rest][cur] = dp[rest-1][cur-1];
                }else {
                    dp[rest][cur] = dp[rest-1][cur+1] + dp[rest-1][cur-1];
                }
            }
        }
        return dp[start][K];    
    }
}
​
选硬币

给定一个硬币数组,求拼成target的最少硬币数

package com.wtp.基础提升.暴力递归改动态规划;
​
public class 选硬币 {
​
    public static void main(String[] args) {
        
        int[] arr = {2,7,3,5,3,4};
        System.out.println(minCount1(arr,11));
        System.out.println(process(arr,11));
        System.out.println(process(arr,11,0));
    }
    
    public static int minCount(int[] arr,int target) {
        return  process(arr,target,0);
    }
    public static int minCount1(int[] arr,int target) {
        
        int[][] dp = new int[arr.length+1][target+1];
        for(int i = 0;i<=arr.length;i++) {
            for(int j = 0;j<=target;j++) {
                dp[i][j] = -2;
            }
        }
        
        int res = process(arr,target,0,dp);
        return  res != -1 ? res : 0; 
    }
    
    //暴力尝试
    public static int process(int[] arr,int target,int i) {
        
        if(target == 0) {//有解返回0个硬币
            return 0;
        }
        if(target < 0 || i == arr.length) {
            return -1;
        }
        
        int p1;
        int p2;
        p1 = process(arr,target - arr[i],i+1);
        p2 = process(arr,target,i+1);
        
        if(p1 == -1 && p2 == -1) {
            return -1;
        }
        
        int res = Integer.MAX_VALUE;
        res = p1 != -1 ? Math.min(res, p1 + 1) : res;
        res = p2 != -1 ? Math.min(res, p2) : res;
        
        return res;
    }
    
    //记忆化搜索
    public static int process(int[] arr,int target,int index,int[][] dp) {
        
        if(target < 0) {
            return -1;
        }
        
        if(dp[index][target] != -2) {
            return dp[index][target];
        }
        
        if(target == 0) {//有解返回0个硬币
            dp[index][target] = 0;
            return 0;
        }
        
        if(index == arr.length) {
            dp[index][target] = -1;
            return -1;
        }
        
            
        int p1;
        int p2;
        p1 = process(arr,target - arr[index],index+1,dp);
        p2 = process(arr,target,index+1,dp);
        
        int res = Integer.MAX_VALUE;
        if(p1 == -1 && p2 == -1) {
            res = -1;
        }else {
            res = p1 != -1 ? Math.min(res, p1+1) : res;
            res = p2 != -1 ? Math.min(res, p2) : res;
        }
        
        dp[index][target] = res; 
        return res;
    }
    
    //动态规划
    public static int process(int[] arr,int aim) {
        
        int[][] dp = new int[arr.length + 1][aim + 1];
        int N = arr.length;
        for (int row = 0; row <= N; row++) {
            dp[row][0] = 0;
        }
        for (int col = 1; col <= aim; col++) {
            dp[N][col] = -1;
        }
​
        for (int index = N - 1; index >= 0; index--) {
            for (int rest = 1; rest <= aim; rest++) {
​
                int p1 = dp[index + 1][rest];// 不拿
                int p2 = -1;// 拿的后续
                if (rest - arr[index] >= 0) {
                    p2 = dp[index + 1][rest - arr[index]]; 
                }
                if (p1 == -1 && p2 == -1) {
                    dp[index][rest] = -1;
                } else if (p1 == -1) {
                    dp[index][rest] = p2 + 1;
                } else if (p2 == -1) {
                    dp[index][rest] = p1;
                } else {
                    dp[index][rest] = Math.min(p1, p2 + 1);
                }
​
            }
        }
        return dp[0][N];
    }
}
​
两个绝顶聪明的人

两个绝顶聪明的人选牌,只能选数组两侧的牌,都选对自己最有利的,返回最后获胜的人的值

package com.wtp.基础提升.暴力递归改动态规划;
​
public class 两个绝顶聪明的人选牌 {
​
    public static void main(String[] args) {
    
        int[] arr = {3,100,2,50};
        System.out.println(process1(arr));
        System.out.println(process2(arr));
        System.out.println(process3(arr));
    }
    
    public static int process1(int[] arr) {
        if(arr == null || arr.length == 0) {
            return 0;
        }
        return Math.max(f(arr,0,arr.length - 1), p(arr,0,arr.length - 1));
    }
    //范围尝试 先手函数
    public static int f(int[] arr,int l,int r) {
        if(l == r) {
            return arr[r];
        }
        return Math.max(arr[l] + p(arr,l+1,r), arr[r] + p(arr,l,r-1));
    }
    //范围尝试 后手函数
    public static int p(int[] arr,int l,int r) {
        if(l == r) {
            return 0;
        }
        return Math.min(f(arr,l+1,r), f(arr,l,r-1));
    }
    
    //记忆化搜索
    public static int process2(int[] arr) {
        if(arr == null || arr.length == 0) {
            return 0;
        }
        int N = arr.length ;
        int[][] dp1 = new int[N + 1][N + 1];
        int[][] dp2 = new int[N + 1][N + 1];
        
        for(int i = 0; i <= N;i++) {
            for(int j = 0;j <= N;j++) {
                dp1[i][j] = -1;
                dp2[i][j] = -1;
            }
        }
        
        return Math.max(f2(arr,0,arr.length - 1,dp1), p2(arr,0,arr.length - 1,dp2));
    }
    public static int f2(int[] arr,int l,int r,int[][] dp) {
        
        if(dp[l][r] != -1) {
            return dp[l][r];
        }
        
        if(l == r) {
            dp[l][r] = arr[r];
            return arr[r];
        }
        dp[l][r] = Math.max(arr[l] + p2(arr,l+1,r,dp), arr[r] + p2(arr,l,r-1,dp));
        return dp[l][r];
    }
    
    public static int p2(int[] arr,int l,int r,int[][] dp) {
        
        if(dp[l][r] != -1) {
            return dp[l][r];
        }
        
        if(l == r) {
            dp[l][r] = 0;
            return 0;
        }
        dp[l][r] = Math.min(f2(arr,l+1,r,dp), f2(arr,l,r-1,dp));
        return dp[l][r];
    }
    
    //动态规划
    public static int process3(int[] arr) {
        
        int N = arr.length;
        int[][] dp1 = new int[N + 1][N + 1];
        int[][] dp2 = new int[N + 1][N + 1];
        
        for(int i = 0;i < N;i++) {
            dp1[i][i] = arr[i];
            dp2[i][i] = 0;
        }
        
        int row = 0;
        int col = 1;
        while(col < N) {
            int i = row;
            int j = col;
            while(i < N && j < N) {
                dp1[i][j] = Math.max(dp2[i+1][j] + arr[i],dp2[i][j-1] + arr[j]);
                dp2[i][j] = Math.min(dp1[i+1][j],dp1[i][j-1]);
                i++;j++;
            }
            col++;
        }
​
        return Math.max(dp1[0][N-1], dp2[0][N-1]);
    }
}
​
棋盘马跳位置

一张9*10的棋盘,马初始在 0,0 跳 k 步跳到 i,j 有多少种方法

package com.wtp.基础提升.暴力递归改动态规划;
​
public class 棋盘马跳位置 {
​
    
    public static void main(String[] args) {
        
//      System.out.println(process1(7,5,10));
        //System.out.println(process3(7,5,10));
        
        test();
    }
    
    public static void test() {
        
        int maxCount = 1000;
        int i;
        int j;
        int k;
        long start = 0L;
        long l1 = 0L;
        long l2 = 0L;
        long l3 = 0L;
        long end = 0L;
        for(int z = 0;z < maxCount;z++) {
            i = (int)(Math.random() * 9);
            j = (int)(Math.random() * 10);
            k = (int)(Math.random() * 10);
            //System.out.println(i + "==" + j + "==" + k + "==");
            
            start = System.currentTimeMillis();
            int res1 = process1(i,j,k);
            end = System.currentTimeMillis();
            l1 += end - start;
            
            start = System.currentTimeMillis();
            int res2 = process2(i,j,k);
            end = System.currentTimeMillis();
            l2 += end - start;
            
            start = System.currentTimeMillis();
            process3(i,j,k);
            end = System.currentTimeMillis();
            l3 += end - start;
            
            if(res1 != res2) {
                System.out.println("error!");
                return;
            }
        }
        
        System.out.println("暴力递归用时:" + l1 + "毫秒");
        System.out.println("记忆化搜索用时:" + l2 + "毫秒");
        System.out.println("动态规划用时:" + l3 + "毫秒");
    }
    
    //9*10的棋盘
    public static int process1(int i,int j,int k) {
        
        if(i < 0 || i > 8 || j < 0 || j > 9) {
            return 0;
        }
        
        if(k == 0) {
            return i == 0 && j == 0 ? 1 : 0;
        }
        
        return process1(i + 1,j + 2,k-1)
                +process1(i + 1,j - 2,k-1)
                +process1(i - 1,j + 2,k-1)
                +process1(i - 1,j - 2,k-1)
                +process1(i + 2,j + 1,k-1)
                +process1(i + 2,j - 1,k-1)
                +process1(i - 2,j + 1,k-1)
                +process1(i - 2,j - 1,k-1);
    }
    
    public static int process2(int i,int j,int k) {
        int[][][] dp = new int[9][10][k+1];
        for(int x = 0;x < 9;x++) {
            for(int y = 0;y < 10;y++) {
                for(int z = 0;z <= k;z++) {
                    dp[x][y][z] = -1;
                }
            }
        }
        return process(i,j,k,dp);
    }
    
    public static int process(int i,int j,int k,int[][][] dp) {
        
        if(i < 0 || i > 8 || j < 0 || j > 9) {
            return 0;
        }
        
        if(dp[i][j][k] != -1) {
            return dp[i][j][k];
        }
        
        if(k == 0) {
            dp[i][j][k] = i == 0 && j == 0 ? 1 : 0;
            return dp[i][j][k];
        }
        
        dp[i][j][k] = process(i + 1,j + 2,k-1,dp)
                +process(i + 1,j - 2,k-1,dp)
                +process(i - 1,j + 2,k-1,dp)
                +process(i - 1,j - 2,k-1,dp)
                +process(i + 2,j + 1,k-1,dp)
                +process(i + 2,j - 1,k-1,dp)
                +process(i - 2,j + 1,k-1,dp)
                +process(i - 2,j - 1,k-1,dp);
        
        return dp[i][j][k];
    }
    
    public static int process3(int i,int j,int k) {
        
        int[][][] dp = new int[9][10][k+1];
        dp[0][0][0] = 1;
        
        int[] xx = {1,1,-1,-1,2,2,-2,-2};
        int[] yy = {2,-2,2,-2,1,-1,1,-1};
        
        
        for(int z = 1;z <= k;z++) {//有多少层 x*y的平面
            for(int x = 0;x < 9;x++) {
                for(int y = 0;y < 10;y++) {
                    for(int n = 0;n < xx.length;n++) {
                        int x1 = x + xx[n];
                        int y1 = y + yy[n];
                        if(x1 > -1 && x1 < 9 && y1 > - 1 && y1 < 10 && z -1 >= 0) {
                            dp[x][y][z] += dp[x1][y1][z-1];
                        }
                    }
                }
            }
        }
        
        
        return dp[i][j][k];
    }
}
​
鲍勃走格子

给定长宽N、M的矩阵,越界死亡,求等概率随机走k步最后的存活率

package com.wtp.基础提升.暴力递归改动态规划;
​
public class 鲍勃走格子 {
    
    public static void main(String[] args) {
        
//      int[] res = process1(3,4,5,5,3);
//      System.out.println(res[0] + "/" + res[1] + "=" + res[0] * 1.0 / res[1]);
//      
//      System.out.println(bob1(5,5,3,4,3));
//      System.out.println(bob2(5,5,3,4,3));
//      System.out.println(bob3(5,5,3,4,3));
        
        test();
    }
    
    public static void test() {
        
        int maxCount = 10000;
        int i;
        int j;
        int k;
        int N;
        int M;
        long start = 0L;
        long l1 = 0L;
        long l2 = 0L;
        long l3 = 0L;
        long end = 0L;
        for(int z = 0;z < maxCount;z++) {
            N = (int)(Math.random() * 10) + 1;
            M = (int)(Math.random() * 10) + 1;
            i = N / 2;
            j = M / 2;
            k = (int)(Math.random() * 10);
            //System.out.println(i + "==" + j + "==" + k + "==");
            
            start = System.currentTimeMillis();
            String res1 = bob1(N,M,i,j,k);
            end = System.currentTimeMillis();
            l1 += end - start;
            
            start = System.currentTimeMillis();
            String res2 = bob2(N,M,i,j,k);
            end = System.currentTimeMillis();
            l2 += end - start;
            
            start = System.currentTimeMillis();
            String res3 = bob3(N,M,i,j,k);
            end = System.currentTimeMillis();
            l3 += end - start;
            
            if(!res1.equals(res2)) {
                System.out.println("error!");
                System.out.println(res1);
                System.out.println(res2);
                System.out.println(res3);
                return;
            }
        }
        
        System.out.println("暴力递归用时:" + l1 + "毫秒");
        System.out.println("记忆化搜索用时:" + l2 + "毫秒");
        System.out.println("动态规划用时:" + l3 + "毫秒");
    }
    
    public static String bob1(int N,int M,int i,int j,int k) {
        long all = (long)Math.pow(4, k);
        long live = process(N, M, i, j, k);
        long gcd = gcd(all,live);
        return String.valueOf((live / gcd) + "/" + (all / gcd));
    }
    
    public static long gcd(long m, long n) {//辗转相除法求最大公因数
        return n == 0 ? m : gcd(n, m % n);
    }
​
    //死了还能走 总共有4^rest走法
    public static long process(int N,int M,int row,int col,int rest) {//存活数
        if(row < 0 || row == N || col < 0 || col == M) {
            return 0;//出界了
        }
        if(rest == 0) {
            return 1;//没出界 走完了 存活
        }
        long live = process(N, M, row - 1, col, rest - 1);
        live += process(N, M, row + 1, col, rest - 1);
        live += process(N, M, row, col - 1, rest - 1);
        live += process(N, M, row, col + 1, rest - 1);
        return live;
    }
​
    //死了就不走了
    public static int[] process1(int i,int j,int N,int M,int k) {
        
        if(i < 0 || i >= N || j < 0 || j >= M) {
            return new int[] {0,1};//走一次死了
        }
        
        if(k == 0) {
            return new int[] {1,1};//走一次活了
        }
        
        int[] res = new int[2];
        int[] xx = {1,-1,0,0};
        int[] yy = {0,0,1,-1};
        
        for(int n = 0;n < xx.length;n++) {
            int[] p = process1(i+xx[n],j+yy[n],N,M,k-1);
            res[0] += p[0];
            res[1] += p[1];
        }
        
        return res;
    }
    
    public static String bob2(int N,int M,int i,int j,int k) {
        long all = (long)Math.pow(4, k);
        long live = process2(N, M, i, j, k);
        long gcd = gcd(all,live);
        return String.valueOf((live / gcd) + "/" + (all / gcd));
    }
    
    public static long process2(int N,int M,int i,int j,int k) {
        
        long[][][] dp = new long[N][M][k+1];
        for(int x = 0;x < N;x++) {
            for(int y = 0;y < M;y++) {
                for(int z = 0;z <= k;z++) {
                    dp[x][y][z] = -1;
                }
            }
        }
        return  process2(N,M,i,j,k,dp);
    }
    
    //记忆化搜索
    public static long process2(int N,int M,int row,int col,int rest,long[][][] dp) {//存活数
        if(row < 0 || row >= N || col < 0 || col >= M) {
            return 0;//出界了
        }
        
        if(dp[row][col][rest] != -1) {
            return dp[row][col][rest];
        }
        if(rest == 0) {
            dp[row][col][rest] = 1;
            return 1;//没出界 走完了 存活
        }
        
        long live = process2(N, M, row - 1, col, rest - 1,dp);
        live += process2(N, M, row + 1, col, rest - 1,dp);
        live += process2(N, M, row, col - 1, rest - 1,dp);
        live += process2(N, M, row, col + 1, rest - 1,dp);
        
        dp[row][col][rest] = live;
        return live;
    }
    
    public static String bob3(int N,int M,int i,int j,int k) {
        long all = (long)Math.pow(4, k);
        long live = process3(N, M, i, j, k);
        long gcd = gcd(all,live);
        return String.valueOf((live / gcd) + "/" + (all / gcd));
    }
    
    //动态规划
    public static long process3(int N,int M,int row,int col,int rest) {
        
        long[][][] dp = new long[N][M][rest + 1];
​
        for(int i = 0;i < N;i++) {//步数为0的时候在范围上就都存活
            for(int j = 0;j < M;j++) {
                dp[i][j][0] = 1;
            }
        }
        
        int[] xx = {1,-1,0,0};
        int[] yy = {0,0,1,-1};
        for(int z = 1;z <= rest;z++) {
            for(int i = 0;i < N;i++) {
                for(int j = 0;j < M;j++) {
                    for(int n = 0;n < xx.length;n++) {
                        int x1 = xx[n] + i;
                        int y1 = yy[n] + j;
                        if(x1 >= 0 && x1 < N && y1 >= 0 && y1 < M) {
                            dp[i][j][z] += dp[x1][y1][z-1]; 
                        }
                    }
                }
            }
        }
        return dp[row][col][rest];
    }
    
}
​
选货币每种可以选无限张

优化: 在存在枚举行为时,也许可以通过斜率优化,观察枚举行为是否能被邻近位置所替代。

必须有尝试(从左到右或者范围上的尝试) -> 记忆化搜索 -> 严格表结构动态规划 -> 优化

尝试:可变参数个数越少越好、单可变参数维度保持0维

package com.wtp.基础提升.暴力递归改动态规划;
​
import java.util.Arrays;
​
public class 选货币每种可以选无限张 {
    
    
    public static void main(String[] args) {
        
        test();
    }
    
    public static void test() {
        
        int maxCount = 1000;
        int maxLength = 10;
        int maxValue = 20;
        int rest;
        
        long start = 0L;
        long end = 0L;
        long l1 = 0L;
        long l2 = 0L;
        long l3 = 0L;
        long l4 = 0L;
        for(int z = 0;z < maxCount;z++) {
        
            int[] arr1 = getRandomArr(maxLength,maxValue);
            int[] arr2 = getCopyArr(arr1);
            int[] arr3 = getCopyArr(arr1);
            rest = (int)(Math.random() * 100) + 1;
            
            start = System.currentTimeMillis();
            int res1 = process1(arr1,rest);
            end = System.currentTimeMillis();
            l1 += end - start;
            
            start = System.currentTimeMillis();
            int res2 = process2(arr2,rest);
            end = System.currentTimeMillis();
            l2 += end - start;
            
            start = System.currentTimeMillis();
            int res3 = process3(arr3,rest);
            end = System.currentTimeMillis();
            l3 += end - start;
            
            start = System.currentTimeMillis();
            int res4 = process4(arr3,rest);
            end = System.currentTimeMillis();
            l4 += end - start;
            
            if(res1 != res2 || res2 != res3 || res3 != res4) {
                System.out.println("error!");
                System.out.println(res1);
                System.out.println(res2);
                System.out.println(res3);
                
                System.out.println(Arrays.toString(arr1));
                System.out.println(rest);
                
                return;
            }
        }
        
        System.out.println("暴力递归用时:" + l1 + "毫秒");
        System.out.println("记忆化搜索用时:" + l2 + "毫秒");
        System.out.println("动态规划用时:" + l3 + "毫秒");
        System.out.println("动态规划(优化)用时:" + l3 + "毫秒");
    }
    
    public static int[] getCopyArr(int[] arr) {
        int[] copyArr = new int[arr.length];
        System.arraycopy(arr, 0, copyArr, 0, arr.length);
        return copyArr;
    }
    
    public static int[] getRandomArr(int maxLength,int maxValue) {
        
        int[] arr = new int[maxLength];
        for(int i = 0;i < arr.length;i++) {
            arr[i] = (int)(Math.random() * maxValue) + 1;
        }
        return arr;
    }
​
    //尝试
    public static int process1(int[] arr,int rest) {
        return process1(arr,0,rest);
    }
    
    public static int process1(int[] arr, int index, int rest) {
​
        if (index == arr.length) {
            return rest == 0 ? 1 : 0;
        }
​
        int r = 0;
        for (int zhang = 0; arr[index] * zhang <= rest; zhang++) {
            r += process1(arr, index + 1, rest - arr[index] * zhang);
        }
​
        return r;
    }
    
    //记忆化搜索
    public static int process2(int[] arr,int rest) {
        int N = arr.length;
        int[][] dp = new int[N + 1][rest+1];
        
        for(int i = 0;i <= N;i++) {
            for(int j = 0;j <= rest;j++) {
                dp[i][j] = -1;
            }
        }
        
        return process2(arr,0,rest,dp);
    }
    
    public static int process2(int[] arr,int index,int rest,int[][] dp) {
        
        if (index == arr.length) {
            dp[index][rest] = rest == 0 ? 1 : 0;
            return dp[index][rest];
        }
        
        if(dp[index][rest] != -1) {
            return dp[index][rest];
        }
​
        int r = 0;
        for (int zhang = 0; arr[index] * zhang <= rest; zhang++) {
            r += process2(arr, index + 1, rest - arr[index] * zhang,dp);
        }
​
        dp[index][rest] = r;
        return dp[index][rest];
    }
    
    //动态规划 0 rest
    public static int process3(int[] arr,int rest) {
        int N = arr.length;
        int[][] dp = new int[N+1][rest+1];
        
        dp[N][0] = 1;
        
        for(int i = N - 1;i >= 0;i--) {
            for(int j = 0;j <= rest;j++) {  
                for(int k = 0;k * arr[i] <= j;k++) {
                    dp[i][j] += dp[i+1][j - arr[i] * k];
                }
            }
        }
        
        return dp[0][rest];
    }
    
    //动态规划斜率优化
    public static int process4(int[] arr,int rest) {
        int N = arr.length;
        int[][] dp = new int[N+1][rest+1];
        
        dp[N][0] = 1;
        
        for(int i = N - 1;i >= 0;i--) {
            for(int j = 0;j <= rest;j++) {  
                dp[i][j] = dp[i+1][j];//每个格子首先依赖自己下方的格子
                if(j - arr[i] >= 0) {
                    dp[i][j] += dp[i][j-arr[i]];//其次依赖自己行左边的格子(左边已经先算完自己下面所有依赖的格子了)
                }
            }
        }
        
        return dp[0][rest];
    }
}
​
  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值