秋招笔试惨痛经历之——动态规划

1. 面试高频

  1. 正则匹配
class Solution {
    public boolean isMatch(String s, String p) {
        /*
        正则表达式匹配
        7.22
        */
        //动态规划

        char[] str = s.toCharArray();
        char[] pstr = p.toCharArray();

        int len1 = str.length;
        int len2 = pstr.length;

        boolean[][] dp = new boolean[len1+1][len2+1];
        dp[len1][len2] = true;

        for(int i=len1;i>=0;i--){
            for(int j=len2-1;j>=0;j--){
                boolean cur = i
  1. 打家劫舍3问
//线性
class Solution {
    public int rob(int[] nums) {
        /*
        打家劫舍,数组
        7.25
        */
        //动态规划

        //判断空
        if(nums.length == 0){
            return 0;
        }

        //如果只有1个元素,返回第一个元素
        if(nums.length == 1){
            return nums[0];
        }

        //提取first和second
        int first = nums[0];
        int second = Math.max(nums[0],nums[1]);

        //因为不能偷相邻的,从2开始遍历
        for(int i=2;i
  1. 股票3问
//一次交易,直接贪心
class Solution {
    public int maxProfit(int[] prices) {
        /*
        买卖股票的最佳时机,一次购买
        7.25
        */
        //只能买一次,贪心遍历找到cost最小但prices最大

        int cost = prices[0];
        int result = 0;

        for(int i=1;i 0){
                profit += temp;
            }

        }

        return profit;
    }
}

//交易冷冻期
class Solution {
    public int maxProfit(int[] prices) {

        /*
        股票含冷冻期
        7.26
        */
        //使用dp数组表示三种状态
        //dp[i][0]表示不持股,初始化为0,可以由前一天是不持股和前一天冷冻期得到
        //dp[i][1]表示持股,初始化为-prices[0],可以由前一天不持股和前一天持股得到
        //dp[i][2]表示冷冻期,初始化为0,可以由前一天持股得到
        //比较不持股和冷冻期
        
        if(prices.length == 0){
            return 0;
        }

        int[][] dp = new int[prices.length][3];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;

        //从1开始遍历
        for(int i=1;i
  1. 凑硬币(巨经典)
//如果没有给定硬币面额,使用dp
class Solution {
    public int coinChange(int[] coins, int amount) {
        /*
        零钱兑换
        7.26
        */
        //一维dp

        //判断空
        if(coins.length == 0){
            return 0;
        }

        int[] dp = new int[amount+1];
        for(int i=1;i<=amount;i++){
            dp[i] = Integer.MAX_VALUE;
        }

        for(int i=1;i<=amount;i++){
            for(int j=0;j= 0 && dp[i-coins[j]] != Integer.MAX_VALUE){
                    dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
                }
            }
        }

        if(dp[amount] == Integer.MAX_VALUE){
            return -1;
        }else{
            return dp[amount];
        }
    }
}


//如果给定硬币面额,如:1,4,16,64。直接从大到小贪心递减
public int GetCoinCount(int N) {
    N = 1024 - N;
    int count = 0;
    while (N > 0) {
        if (N >= 64) {
            N -= 64;
        } else if (N >= 16) {
            N -= 16;
        } else if (N >= 4) {
            N -= 4;
        } else {
            N--;
        }
        //先从大的面额开始减,减完一次就+1
        count++;
    }
    return count;
}
  1. 爬楼梯(2步和3步)
//1和2步:f(n) = f(n-1) + f(n-2)
class Solution {
    public int climbStairs(int n) {
        /*
        爬楼梯(台阶)
        7.24
        */
        //递归,使用数组存小结果

        int[] result = new int[n+2];
        result[1] = 1;
        result[2] = 2;

        //从3开始
        for(int i=3;i<=n;i++){
            result[i] = result[i-1] + result[i-2];
        }

        return result[n];
    }
}

//贪心爬楼梯:f(n) = 2f(n-1)
public class Solution {
    public int JumpFloorII(int target) {
        
        int sum = 1;
        for(int i=1;i

2. 一维dp:背包问题

  1. 0-1背包
    有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
    第 i 种物品的体积是 vi,价值是 wi。
    求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
import java.util.*;

public class Main{
    public static void main(String[] args){
        //典型的背包问题描述。有最大限制量:背包容量。
        //每样物品只能用一次。0-1背包。
        //输入两列,分别代表不同值
        Scanner sc = new Scanner(System.in);
        
        int nums = sc.nextInt();
        
        int bag = sc.nextInt();
        
        int[] weights = new int[nums];
        int[] values = new int[nums];
        
        for(int i=0;i=weight[i];j--){
                dp[j] = Math.max(dp[j],dp[j-weight[i]] + value[i]);
            }
        }
        System.out.println(dp[bag]);
    }
}
  1. 0-1背包策略数
    给定N个正整数A1,A2,…,AN,从中选出若干个数,使它们的和为M,求有多少种选择方案。
4 4
1 1 2 2
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);

        //每个数只能用一次,且数字顺序不同,结果不相同
        //最大限制:sum值

        int num = sc.nextInt();
        
        int sum = sc.nextInt();
        
        int[] nums = new int[num];
        for(int i=0;i=nums[i];j--){
                dp[j] += dp[j-nums[i]];
            }
        }
        
        System.out.println(dp[sum]);
    }
}
  1. 完全背包
    有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
    第 i 种物品的体积是 vi,价值是 wi。
    求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
    输出最大价值。
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        //背包问题,有最大限制量:背包容量
        //每样物品可以用无限次,完全背包
        //两列输入,分别代表不同值

        int nums = sc.nextInt();
        
        int bag = sc.nextInt();
        
        int[] weights = new int[nums];
        int[] values = new int[nums];
        
        for(int i=0;i
  1. 单词拆分
class Solution {
    public boolean wordBreak(String s, List wordDict) {
        /*
        单词拆分
        7.25
        */
        //动态规划,使用hashset去重wordDict

        //将wordDict传入set进行去重
        Set set = new HashSet<>(wordDict);

        boolean[] dp = new boolean[s.length()+1];
        dp[0] = true;

        //一维dp
        for(int i=1;i<=s.length();i++){

            //i到j区间搜索
            for(int j=0;j
  1. 丑数
class Solution {
    public int nthUglyNumber(int n) {
        /*
        丑数,dp
        8.17
        */

        int a = 0;
        int b = 0;
        int c = 0;

        int[] dp = new int[n+1];
        dp[0] = 1;

        for(int i=1;i<=n;i++){
            //本次丑数:
            int n2 = 2 * dp[a];
            int n3 = 3 * dp[b];
            int n5 = 5 * dp[c];

            //本次最先丑数
            dp[i] = Math.min(n2,Math.min(n3,n5));

            if(n2 == dp[i]){
                a++;
            }
            if(n3 == dp[i]){
                b++;
            }
            if(n5 == dp[i]){
                c++;
            }
        }

        return dp[n-1];
    }
}
  1. 剪绳子(分割整数)
class Solution {
    public int integerBreak(int n) {
        /*
        整数拆分(剪绳子)
        7.26
        */
        //一维dp

        //长度小于2时,返回n
        if(n < 2){
            return 0;
        }

        //初始化dp数组
        int[] dp = new int[n+1];
        dp[2] = 1;

        for(int i=3;i<=n;i++){
            for(int j=0;j

3. 二维dp:

  1. 俄罗斯套娃:降维成一维的最长上升子序列
class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        /*
        俄罗斯套娃,最长上升子序列的二维版本,可以通过Arrays.sort()进行降维
        8.15
        */
        //动态规划,Arrays.sort(envelopes,(a,b) -> (a[0] - b[0]))进行降维

        if(envelopes.length == 0 || envelopes[0].length == 0){
            return 0;
        }

        //创建dp数组
        int[] dp = new int[envelopes.length];
        //初始化为1
        Arrays.fill(dp,1);

        //降维
        Arrays.sort(envelopes,(a,b) ->(a[0] - b[0]));

        int result = 0;
        //一维dp做法
        for(int i=0;i envelopes[j][0] && envelopes[i][1] > envelopes[j][1]){
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }

            //本次i遍历的result
            result = Math.max(result,dp[i]);
        }

        return result;
    }
}
  1. 最大矩形:先初始化,然后从当前行往左搜,提取高和宽
class Solution {
    public int maximalRectangle(char[][] matrix) {

        /*
        8.17,二维动态规划
        */

        //二维dp,可以先初始化dp数组,矩阵中为1,dp[i][j] = dp[i-1][j] + 1。将dp数组第一行设置为1,叠加high
        if(matrix.length == 0 || matrix[0].length == 0){
            return 0;
        }

        int[][] dp = new int[matrix.length][matrix[0].length];

        //初始化dp
        for(int i=0;i=0 && dp[i][k] != 0;k--){
                    //min维持high是i这一层
                    curHigh = Math.min(curHigh,dp[i][k]);
                    int width = j - k + 1;
                    result = Math.max(result,curHigh*width);
                }
            }
        }

        return result;
    }
}
  1. 编辑距离
class Solution {
    public int minDistance(String word1, String word2) {
        /*
        8.17,二维dp
        */

        //dp数组,行为word1,列为word2,保留[0,0]
        int[][] dp = new int[word1.length()+1][word2.length()+1];

        //word1为空,word1要进行word2.length次添加操作,初始化第一行
        for(int i=1;i<=word2.length();i++){
            dp[0][i] = dp[0][i-1] + 1;
        }

        //word2为空,word1要进行word1.length次删除操作,初始化第一列
        for(int i=1;i<=word1.length();i++){
            dp[i][0] = dp[i-1][0] + 1;
        }

        //从[1,1]开始填表
        for(int i=1;i<=word1.length();i++){
            for(int j=1;j<=word2.length();j++){
                //当word1.charAt(i-1) == word2.charAt(j-1)时,dp[i][j] = dp[i-1][j-1]
                if(word1.charAt(i-1) == word2.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i][j-1])) + 1;
                }
            }
        }

        return dp[word1.length()][word2.length()];
    }   
}
  1. 不同路径(有无障碍)
//无障碍
class Solution {
    public int uniquePaths(int m, int n) {
        /*
        不同路径,无障碍
        7.24
        */
        //动态规划,初始化dp为1,叠加上和左即可得到路径

        //判断空
        if(m == 0 || n == 0){
            return 0;
        }

        //m为列,n为行
        int[][] dp = new int[n][m];

        for(int i=0;i
  1. 最大正方形
class Solution {
    public int maximalSquare(char[][] matrix) {
        /*
        最大正方形
        7.26
        */
        //二维dp,

        //判断空
        if(matrix.length == 0 || matrix[0].length == 0){
            return 0;
        }

        int[][] dp = new int[matrix.length][matrix[0].length];

        int side = 0;
        for(int i=0;i
  1. 三角形最小路径和:自底向上
class Solution {
    public int minimumTotal(List> triangle) {
        /*
        三角形最小路径和
        7.25
        */
        //二维dp,自底向上

        int len = triangle.size();
        int[][] dp = new int[len+1][len+1];

        //往上搜索,当前行 + 下一行的min
        for(int i=len-1;i>=0;i--){
            for(int j=0;j<=i;j++){
                dp[i][j] = Math.min(dp[i+1][j],dp[i+1][j+1]) + triangle.get(i).get(j);
            }
        }

        return dp[0][0];
    }
}
  1. 最小路径和
class Solution {
    public int minPathSum(int[][] grid) {
        /*
        最小路径和
        7.23
        */
        //二维dp,叠加原矩阵,求和

        //判断空
        if(grid.length == 0 || grid[0].length == 0){
            return 0;
        }

        for(int i=0;i
  1. 最大路径和
class Solution {
    public int maxValue(int[][] grid) {
        /*
        礼物的最大价值(最大路径和)
        7.27
        */
        //二维dp,可直接叠加原矩阵

        if(grid.length == 0 || grid[0].length == 0){
            return 0;
        }

        for(int i=0;i

4. 笔试原题

  1. 奇安信笔试:凑硬币(3步)
public static int CalulateMethodCount (int num_money) {
    // write code here
 
    int[] result = new int[num_money + 3];
    result[1] = 1;
    result[2] = 2;
    result[3] = 4;
    for (int i = 4; i <= num_money; i++) {
        result[i] = result[i - 1] + result[i - 2] + result[i - 3];
    }
 
    return result[num_money];
}
  1. B站笔试:凑硬币(2步),给定了硬币面额,直接贪心从大到小递减。硬币面额:1,4,16,64.
public int GetCoinCount(int N) {
    N = 1024 - N;
    int count = 0;
    while (N > 0) {
        if (N >= 64) {
            N -= 64;
        } else if (N >= 16) {
            N -= 16;
        } else if (N >= 4) {
            N -= 4;
        } else {
            N--;
        }
        //先从大的面额开始减,减完一次就+1
        count++;
    }
    return count;
}
  1. 大疆笔试:0-1背包
    有许多程序员都热爱玩游戏,而小J自称为游戏王,曾玩过几百种游戏,几乎所有能玩到的游戏大作都玩遍了。随着时间的推移,他发觉已经没有游戏可以让他玩了!于是他想改玩一些古老的游戏,以成为真正的“游戏王”。他希望在接下来的一段时间内将过去出的游戏全部玩一遍,但是毕竟时间有限,因此他感到很苦恼。于是他想到一个计划,他先将每个游戏标上一个成就值,同时对每个游戏都估算一个通关所需要的天数,他计划在未来X天内让自己玩游戏的成就达到最大,那么他应该怎么做计划呢?(假设每个游戏最多只计划玩一遍,而且每个游戏必须玩完通关才能取得成就值,且通关每个游戏最小时间单位是1天)
样例输入
2 2
10 1
20 2
样例输出
20
提示
输入样例二:
3 4
10 2
18 3
10 2
输出样例二:
20
// 有限制条件,求最值,两组输入,游戏只能玩一次——0-1背包
import java.util.Scanner;
 
public class Main{
    public static void main(String[] args) {
        //有限制条件时间,两组输入求最值,背包问题
        //每个游戏只能玩一次,0-1背包
 
        Scanner sc = new Scanner(System.in);
 
        //数量
        int num = sc.nextInt();
        //限制条件:时间
        int time = sc.nextInt();
 
        //成就值
        int[] values = new int[num];
        //花费时间
        int[] times = new int[num];
        for(int i=0;i=times[i];j--){
                dp[j] = Math.max(dp[j],dp[j-times[i]] + values[i]);
            }
        }
 
        System.out.println(dp[time]);
    }
}

你可能感兴趣的:(秋招笔试惨痛经历之——动态规划)