LeetCode——动态规划(三)

刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com 

目录

494. 目标和 - 力扣(LeetCode)

474. 一和零 - 力扣(LeetCode)

518. 零钱兑换 II - 力扣(LeetCode)

377. 组合总和 Ⅳ - 力扣(LeetCode)

70. 爬楼梯 - 力扣(LeetCode)


 

494. 目标和 - 力扣(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];
	}
}

474. 一和零 - 力扣(LeetCode)

给你一个二进制字符串数组 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];
	}
}

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];
	}
}

你可能感兴趣的:(做题总结,leetcode,动态规划,算法,java)