刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com
目录
给你一个非负整数数组 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
- char ch=str.charAt(i);
- if(ch=='0'){
- zeroNum++;
- }else {
- oneNum++;
- }
- }
- //倒叙遍历---遍历背包
- for (int i =m; 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];
- }
- }
518. 零钱兑换 II - 力扣(LeetCode)
给你一个整数数组 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];
-
- }
- }
377. 组合总和 Ⅳ - 力扣(LeetCode)
给你一个由 不同 整数组成的数组 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];
- }
- }
70. 爬楼梯 - 力扣(LeetCode)
假设你正在爬楼梯。需要 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];
- }
- }