刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com
目录
494. 目标和 - 力扣(LeetCode)
474. 一和零 - 力扣(LeetCode)
518. 零钱兑换 II - 力扣(LeetCode)
377. 组合总和 Ⅳ - 力扣(LeetCode)
70. 爬楼梯 - 力扣(LeetCode)
给你一个非负整数数组 nums
和一个整数 target
。
向数组中的每个整数前添加 '+'
或 '-'
,然后串联起所有整数,可以构造一个 表达式 :
nums = [2, 1]
,可以在 2
之前添加 '+'
,在 1
之前添加 '-'
,然后串联起来得到表达式 "+2-1"
。返回可以通过上述方法构造的、运算结果等于 target
的不同 表达式 的数目。
输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
import java.util.Scanner;
/**
* @author light
* @Description 目标和
*
*(思路:可以将数组分为两部分left和right,
* 即有left-right=target;
* 又有left+right=sum;
* 转化为left=(sum+target)/2
* 所以有两个解法---1.回溯求目标和;2.转化维持01背包问题---背包容量为left;
* @create 2023-09-26 10:13
*/
public class FindTargetSumWaysTest {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n= input.nextInt();
int[] nums=new int[n];
for (int i = 0; i < n; i++) {
nums[i]=input.nextInt();
}
int target=input.nextInt();
System.out.println(findTargetSumWays(nums, target));
}
public static int findTargetSumWays(int[] nums, int target) {
int sum=0;
for (int num : nums) {
sum+=num;
}
if(Math.abs(target)>sum){
return 0; //找不到组合
}
int left=(sum+target)/2;
if((sum+target)%2!=0){
return 0; //找不到组合
}
//动规
//dp[j]:装满容量为j的背包共有dp[j]种方法
int[] dp=new int[left+1];
dp[0]=1;
for (int i = 0; i < nums.length; i++) { //先遍历物品
for(int j=left;j>=nums[i];j--){ //再遍历背包
dp[j]+=dp[j-nums[i]];
}
}
return dp[left];
}
}
给你一个二进制字符串数组 strs
和两个整数 m
和 n
。
请你找出并返回 strs
的最大子集的长度,该子集中 最多 有 m
个 0
和 n
个 1
。
如果 x
的所有元素也是 y
的元素,集合 x
是集合 y
的 子集 。
输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。
import java.util.Scanner;
/**
* @author light
* @Description 一和零
* 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
*
* 请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。
*
* 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
*
* (思路:转化为01背包问题
* @create 2023-09-26 10:58
*/
public class FindMaxFormTest {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String[] strs=input.next().split(",");
int m=input.nextInt();
int n=input.nextInt();
System.out.println(findMaxForm(strs, m, n));
}
public static int findMaxForm(String[] strs, int m, int n) {
//dp[i][j]:最多有i个0,j个1的str的最大子集长度为dp[i][j]
int[][] dp=new int[m+1][n+1];
int zeroNum;
int oneNum;
dp[0][0]=0;
//遍历物品
for (String str : strs) {
zeroNum=0;
oneNum=0;
for (int i = 0; i =zeroNum ; i--) {
for (int j = n; j >=oneNum; j--) {
dp[i][j]=Math.max(dp[i][j],dp[i-zeroNum][j-oneNum]+1);
}
}
}
return dp[m][n];
}
}
给你一个整数数组 coins
表示不同面额的硬币,另给一个整数 amount
表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
/**
* @author light
* @Description 零钱兑换II
*
* (思路:转化为完全背包问题
* @create 2023-09-26 11:45
*/
public class ChangeTest {
public int change(int amount, int[] coins) {
//dp[j]:凑成总金额为j的硬币组合数为dp[j]
int[] dp=new int[amount+1];
dp[0]=1;
for (int i = 0; i < coins.length; i++) {
for (int j = coins[i]; j <=amount; j++) {
dp[j]+=dp[j-coins[i]];
}
}
return dp[amount];
}
}
给你一个由 不同 整数组成的数组 nums
,和一个目标整数 target
。请你从 nums
中找出并返回总和为 target
的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
/**
* @author light
* @Description 组合总和IV
* 请注意,顺序不同的序列被视作不同的组合。---相当于求排列
* (思路:转化为完全背包问题,对于排列问题,先遍历背包,在遍历物品
* @create 2023-09-26 12:23
*/
public class CombinationSum4Test {
public int combinationSum4(int[] nums, int target) {
//dp[j]:总和为j的背包的元素排列个数为dp[j]
int[] dp=new int[target+1];
dp[0]=1;
for (int i = 0; i <=target ; i++) { //先背包
for (int j = 0; j < nums.length; j++) { //在物品
if(i>=nums[j]){
dp[i]+=dp[i-nums[j]];
}
}
}
return dp[target];
}
}
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
升级:
改为:一步一个台阶,两个台阶,三个台阶,.......,直到 m个台阶。
问有多少种不同的方法可以爬到楼顶呢?
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
/**
* @author light
* @Description 爬楼梯进阶版
*
* (思路:
* 1阶,2阶,.... m阶就是物品,楼顶就是背包。
*
* 每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。
*
* 问跳到楼顶有几种方法其实就是问装满背包有几种方法。
*
*这就是一个完全背包问题了
* @create 2023-09-26 14:54
*/
public class ClimbStairsProTest {
public int climbStairs(int n,int m) {
//dp[i]:爬到第i阶楼梯共有dp[i]种方法
int[] dp=new int[n+1];
dp[0]=1;
for (int i = 1; i <=n ; i++) { //先背包
for (int j = 1; j <=m; j++) { //再物品
if(i>=j){
dp[i]+=dp[i-j];
}
}
}
return dp[n];
}
}