LeetCode 40. Combination Sum II

这篇博客讨论了两种不同的优化算法来解决LeetCode 39题的变体,即在包含重复元素的数组中找到所有可能的组合,使得组合内各数之和等于目标值。算法采用了排序和剪枝策略,第一种方法使用了递归,第二种方法结合了哈希映射,以提高效率。博客中展示了Java和Python的实现,并对每种方法的时间复杂度进行了说明。
摘要由CSDN通过智能技术生成

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

Python-collections模块

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值