Each number in candidates may only be used once in the combination.
与 LeetCode 39. Combination Sum 不同的是
本题包含重复元素,且每个位置的元素只能用一次
JAVA
① 排序 + 剪枝(2ms)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Solution {
List<Integer> combine = new ArrayList<Integer>(); // 相当于全局变量,函数括号内就不用加数组了
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates, 0, target);
return ans;
}
public void dfs(int[] candidates, int begin, int target) {
if (target == 0) {
ans.add(new ArrayList<Integer>(combine));
return;
}
for (int idx = begin; idx < candidates.length; idx++) {
if (idx > begin && candidates[idx] == candidates[idx - 1]) continue; //因为题目中有重复元素
int tmp = target - candidates[idx];
if (tmp >= 0) {
combine.add(candidates[idx]);
dfs(candidates, idx + 1, tmp);
combine.remove(combine.size() - 1);
} else {break;}
}
}
}
② 排序 + 剪枝 + 哈希映射(5ms)😅
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Solution {
List<int[]> freq = new ArrayList<int[]>(); // 相当于全局变量,函数括号内就不用加数组了
List<List<Integer>> ans = new ArrayList<List<Integer>>();
List<Integer> sequence = new ArrayList<Integer>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
for (int num : candidates) { // 奇妙的数组元素的表达方式
int size = freq.size();
if (freq.isEmpty() || num != freq.get(size - 1)[0]) {
freq.add(new int[]{num, 1});
} else {
++freq.get(size - 1)[1]; // 二维数组表示哈希
}
}
dfs(0, target);
return ans;
}
public void dfs(int begin, int rest) {
if (rest == 0) {
ans.add(new ArrayList<Integer>(sequence));
return;
}
for (int idx = begin; idx < freq.size(); idx++) { // 其实不用 for循环还快一点,有点玄学
int most = Math.min(rest / freq.get(idx)[0], freq.get(idx)[1]); //最多可以接收的 和 现共有的 取最少
for (int i = 1; i <= most; ++i) {
sequence.add(freq.get(idx)[0]);
dfs(idx + 1, rest - i * freq.get(idx)[0]);
}
for (int i = 1; i <= most; ++i) {
sequence.remove(sequence.size() - 1);
}
}
}
}
Python
① 排序 + 剪枝(44ms)
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
def dfs(begin, target, combine, length):
if target == 0:
ans.append(combine)
for idx in range(begin, length):
if idx > begin and candidates[idx] == candidates[idx-1]:
continue
tmp = target-candidates[idx]
if tmp < 0:
break
dfs(idx+1, tmp, combine + [candidates[idx]], length)
ans = []
combine = []
length = len(candidates)
candidates.sort()
dfs(0, target, combine, length)
return ans
② 排序 + 剪枝 + 哈希映射(52ms)😅
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
def dfs(pos: int, rest: int):
nonlocal sequence
if rest == 0:
ans.append(sequence[:])
return
if pos == len(freq) or rest < freq[pos][0]:
return
dfs(pos + 1, rest)
most = min(rest // freq[pos][0], freq[pos][1]) # // 表示整除
for i in range(1, most + 1):
sequence.append(freq[pos][0])
dfs(pos + 1, rest - i * freq[pos][0])
sequence = sequence[:-most] # 相当于删掉了后 most个元素
freq = sorted(collections.Counter(candidates).items()) # 这个真的太秀了,详细看下面
ans = list()
sequence = list()
dfs(0, target)
return ans
fre = collections.Counter('hello world')
print(fre)
fre = sorted(collections.Counter('hello world').items())
print(fre)
for i in range(len(fre)):
print(fre[i][0],end=" ")
print(fre[i][1])
output:
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
[(' ', 1), ('d', 1), ('e', 1), ('h', 1), ('l', 3), ('o', 2), ('r', 1), ('w', 1)]
1
d 1
e 1
h 1
l 3
o 2
r 1
w 1