需要考虑时间复杂度和空间度,有时递归导致栈的深度太大
77. Combinations
题目地址
https://leetcode.com/problems/combinations/
题目描述
Given two integers n and k, return all possible combinations of k numbers out of 1 … n.
For example,
If n = 4 and k = 2, a solution is:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
dfs回溯,直接一个一个查找
377. Combination Sum IV
题目地址
https://leetcode.com/problems/combination-sum-iv/
题目描述
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.
nums = [1, 2, 3]
target = 4
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
Note that different sequences are counted as different combinations.
Therefore the output is 7.
思路 – 动归
有点k-sum问题,但此题是给定是数字,每个数字是可以重复的,采用dfs回溯直接超时,此题采用了动态规划做法
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int len = nums.size();
sort(nums.begin(), nums.end());
vector<int> dp(target + 1, 0); // dp[i] 表示 能组成 等于i的个数 dp[i - num] + num(num <= i) 可以凑成 dp[i]
dp[0] = 1;
for (int i = 1; i <= target; i++)
{
for (int j = 0; j < len; j++)
{
if (nums[j] <= i)
dp[i] += dp[i - nums[j]];
else
break;
}
}
return dp[target];
}
};
416. Partition Equal Subset Sum
题目地址
https://leetcode.com/problems/partition-equal-subset-sum/
题目描述
Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Note:
Each of the array element will not exceed 100.
The array size will not exceed 200.
Example 1:
Input: [1, 5, 11, 5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: [1, 2, 3, 5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.
类似 根据给定的值找能否组合的问题
同样采用dfs这种方法,会出现超时现象,采用动归,因为题目只要求给出是否
class Solution {
public:
bool canPartition(vector<int>& nums) {
int len = nums.size();
int sums = 0;
int maxVal = -1;
for (int i = 0; i < len; i++)
{
sums += nums[i];
if (nums[i] > maxVal){
maxVal = nums[i];
}
}
if (sums % 2 == 1)
return false;
int m = sums / 2;
if (maxVal > m)
return false;
if (maxVal == m)
return true;
vector<bool> dp(m + 1, false); //dp[i] 表示能租构成值为i的子集合
dp[0] = true;
for (int i = 0; i < len; ++i)
{
/*
nums[i] 只会影响 dp[j - nums[i]]到dp[m],
因为这其间的数 dp[] 可以选择使用它,那么看dp[j - nums[i]] 是否是真的
(或不使用用)还是看dp[j]自身
组成m时,每个数字只能使用一次
例如m = 14 ,nums[0] = 7第一次遍历,dp[7] = true,dp[14] = false
j应该从大到小,大的数不会影响前面的数
*/
for (int j = m; j >= nums[i]; --j)
{
dp[j] = dp[j] || dp[j - nums[i]];
}
}
return dp[m];
}
};