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
- 打家劫舍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
- 股票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
- 凑硬币(巨经典)
//如果没有给定硬币面额,使用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;
}
- 爬楼梯(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:背包问题
- 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]);
}
}
- 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]);
}
}
- 完全背包
有 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
- 单词拆分
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
- 丑数
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];
}
}
- 剪绳子(分割整数)
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:
- 俄罗斯套娃:降维成一维的最长上升子序列
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;
}
}
- 最大矩形:先初始化,然后从当前行往左搜,提取高和宽
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;
}
}
- 编辑距离
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()];
}
}
- 不同路径(有无障碍)
//无障碍
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
- 最大正方形
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
- 三角形最小路径和:自底向上
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];
}
}
- 最小路径和
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
- 最大路径和
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. 笔试原题
- 奇安信笔试:凑硬币(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];
}
- 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;
}
- 大疆笔试: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]);
}
}