组合总和1-4

77. 组合 - 力扣(LeetCode)77. 组合 - 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。 示例 1:输入:n = 4, k = 2输出:[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4],]示例 2:输入:n = 1, k = 1输出:[[1]] 提示: * 1 <= n <= 20 * 1 <= k <= nhttps://leetcode.cn/problems/combinations/返回 [1,n]中所有可能的k个数的组合

class Solution:
    def __init__(self):
        self.ret = 0
        self.l = []

    def combine(self, n: int, k: int) -> List[List[int]]:
        if n == 1:
            return [[1]]
        nums = [i for i in range(1,n+1)]
        # print(nums)
        start, path = 0,[]
        self.backtrack(nums, k, start, path)
        return self.l

    def backtrack(self, nums , k, start, path):
        if k == len(path):
            self.ret+=1
            self.l.append(path.copy())
            return
        if k < len(path):
            return # 剪枝

        for i in range(start, len(nums)):
            # 天然排好序
            # 选择->递归->撤销
            path.append(nums[i])
            self.backtrack(nums,k, i+1, path)
            path.pop()

39. 组合总和 - 力扣(LeetCode)39. 组合总和 - 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 对于给定的输入,保证和为 target 的不同组合数少于 150 个。 示例 1:输入:candidates = [2,3,6,7], target = 7输出:[[2,2,3],[7]]解释:2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。7 也是一个候选, 7 = 7 。仅有这两种组合。示例 2:输入: candidates = [2,3,5], target = 8输出: [[2,2,2,2],[2,3,3],[3,5]]示例 3:输入: candidates = [2], target = 1输出: [] 提示: * 1 <= candidates.length <= 30 * 2 <= candidates[i] <= 40 * candidates 的所有元素 互不相同 * 1 <= target <= 40https://leetcode.cn/problems/combination-sum/

无重复元素的 整数数组 candidates 和目标值 target, 同一个数字可以 无限制重复被选取. 如果至少一个数字的被选数量不同, 则两种组合是不同的.

class Solution:
    def __init__(self):
        self.l = []
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        # candidates[i] >=2 
        # corner case
        if target<=1 :
            return self.l
        start,path = 0,[]
        candidates.sort()  # 排序下否则递归时不好去重
        # print(candidates)
        self.backtrack(candidates, target, start, path)
        return self.l
        

    def backtrack(self, candidates, target, start, path):
        if sum(path) == target:
            self.l.append(path.copy())
            return 
        if sum(path) > target:   # 优化 candidates >=2 都是正数 剪枝
            return 
        # 什么时候继续使用i ,什么时候使用i+1
        for i in range(start, len(candidates)):   # 允许重复使用当前元素就从start, 否则从start+1
            # 优化去重
            if i>0 and candidates[i] == candidates[i-1]:
                continue
            # 选择->递归->撤销选择
            path.append(candidates[i])
            self.backtrack(candidates,target,i,path)
            path.pop()

  40. 组合总和 II - 力扣(LeetCode)40. 组合总和 II - 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用 一次 。注意:解集不能包含重复的组合。  示例 1:输入: candidates = [10,1,2,7,6,1,5], target = 8,输出:[[1,1,6],[1,2,5],[1,7],[2,6]]示例 2:输入: candidates = [2,5,2,1,2], target = 5,输出:[[1,2,2],[5]] 提示: * 1 <= candidates.length <= 100 * 1 <= candidates[i] <= 50 * 1 <= target <= 30https://leetcode.cn/problems/combination-sum-ii/

 区别不能用重复数字了   

class Solution:
    def __init__(self):
        self.l = []

    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        # 1<=candidates[i]<=50
        candidates.sort() # 方便去重使用
        start, path = 0, []
        self.backtrack(candidates, target, path,start)
        return self.l

    def backtrack(self, candidates, target, path, start):
        if sum(path) == target:
            self.l.append(path.copy())
            return 
        if sum(path) > target:
            return 
        
        for i in range(start, len(candidates)):
            # 不能包含重复的组合
            if i>start and candidates[i] == candidates[i-1]:
                continue
            
            path.append(candidates[i])
            self.backtrack(candidates,target,path,i+1) # 每个数字只用1次
            path.pop()

216. 组合总和 III - 力扣(LeetCode)216. 组合总和 III - 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件: * 只使用数字1到9 * 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。 示例 1:输入: k = 3, n = 7输出: [[1,2,4]]解释:1 + 2 + 4 = 7没有其他符合的组合了。示例 2:输入: k = 3, n = 9输出: [[1,2,6], [1,3,5], [2,3,4]]解释:1 + 2 + 6 = 91 + 3 + 5 = 92 + 3 + 4 = 9没有其他符合的组合了。示例 3:输入: k = 4, n = 1输出: []解释: 不存在有效的组合。在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。 提示: * 2 <= k <= 9 * 1 <= n <= 60https://leetcode.cn/problems/combination-sum-iii/

 感觉跟前面一样, 这有啥意义

class Solution:
    def __init__(self):
        self.l = []
    
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        # k个数, 总和n 
        nums = [i for i in range(1,10)]
        # nums 有序
        path,start = [],0
        self.backtrack(nums, k, n, path, start)
        return self.l

    def backtrack(self, nums, k, n, path, start):
        if len(path) ==k and sum(path) == n:
            self.l.append(path.copy())
            return # 一个结果
        if sum(path) > n or len(path) >k:
            return # 剪枝 
        
        for i in range(start, len(nums)):
            # if i>start and nums[i] == nums[i-1]:
                # continue
            if nums[i] in path:
                continue # 每个数字最多用一次
            path.append(nums[i])
            self.backtrack(nums,k,n,path,i+1) # 每个数字最多用一次
            path.pop()

377. 组合总和 Ⅳ - 力扣(LeetCode)377. 组合总和 Ⅳ - 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。题目数据保证答案符合 32 位整数范围。 示例 1:输入: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)请注意,顺序不同的序列被视作不同的组合。示例 2:输入:nums = [9], target = 3输出:0 提示: * 1 <= nums.length <= 200 * 1 <= nums[i] <= 1000 * nums 中的所有元素 互不相同 * 1 <= target <= 1000 进阶:如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?https://leetcode.cn/problems/combination-sum-iv/

 每个数字可以多次重复利用,    TLE 了, On^target  换思路吧

class Solution:
    def __init__(self):
        self.ret = 0  # 返回个数

    def combinationSum4(self, nums: List[int], target: int) -> int:
        # nums 中元素无序, 且互不相同
        nums.sort()
        path,start = [],0
        self.backtrack(nums, target, path, start)
        return self.ret
    
    def backtrack(self, nums, target, path, start):
        if sum(path) > target:
            return 
        if sum(path) == target:
            self.ret +=1  
            return # 都是正数
        for i in range(0 ,len(nums)):   # 每个数字可重复使用 
            if sum(path) + nums[i] > target:
                break
            path.append(nums[i])
            self.backtrack(nums, target, path,i ) # 可以重复使用当前元素
            path.pop()

 dp On*tartget  

class Solution:
    def __init__(self):
        self.ret = 0  # 返回个数

    def combinationSum4(self, nums: List[int], target: int) -> int:
        # dp 是和为 target 的排列数 
        # dp[target] = dp[target-x] + dp[target]
        # x 为nums 中的值
        dp = [0] * (target+1)

        dp[0] = 1 # target=0 是为0
        for i in range(1,target+1):
            for x in nums:
                if x<=i:
                    dp[i] = dp[i] + dp[i-x]
        # print(dp)
        return dp[target]

dp, 回溯 啥时候用?  

计数用dp, 穷举用回溯

17. 电话号码的字母组合 - 力扣(LeetCode)17. 电话号码的字母组合 - 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。[https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2021/11/09/200px-telephone-keypad2svg.png] 示例 1:输入:digits = "23"输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]示例 2:输入:digits = ""输出:[]示例 3:输入:digits = "2"输出:["a","b","c"] 提示: * 0 <= digits.length <= 4 * digits[i] 是范围 ['2', '9'] 的一个数字。https://leetcode.cn/problems/letter-combinations-of-a-phone-number/

用回溯 On^target

class Solution:
    def __init__(self):
        self.l = []
        self.dict = {
            "2" : ["a","b","c"],
            "3" : ["d","e","f"],
            "4" : ["g","h","i"],
            "5" : ["j","k","l"],
            "6" : ["m","n","o"],
            "7" : ["p","q","r","s"],
            "8" : ["t","u","v"],
            "9" : ["w","x","y","z"]
        }

    def letterCombinations(self, digits: str) -> List[str]:
        if len(digits) ==0:
            return self.l
        # digits.length = k
        # digits[i] 对应的字母只能用一次
        # 回溯穷举所有结果
        start,path  = 0,[]
        self.backtrack(digits,start, path)
        return self.l

    def backtrack(self, digits, start, path):
        if len(path) == len(digits):
            self.l.append("".join(path.copy()))
            return 
        if len(path) > len(digits):
            return
        
        # for d in digits:
        for i in range(start,len(digits)): # 剪枝重复使用
            d = digits[i]
            for k in self.dict[d]:
                path.append(k)
                self.backtrack(digits, i+1, path)
                path.pop()
        

3014. 输入单词需要的最少按键次数 I - 力扣(LeetCode)3014. 输入单词需要的最少按键次数 I - 给你一个字符串 word,由 不同 小写英文字母组成。电话键盘上的按键与 不同 小写英文字母集合相映射,可以通过按压按键来组成单词。例如,按键 2 对应 ["a","b","c"],我们需要按一次键来输入 "a",按两次键来输入 "b",按三次键来输入 "c"。现在允许你将编号为 2 到 9 的按键重新映射到 不同 字母集合。每个按键可以映射到 任意数量 的字母,但每个字母 必须 恰好 映射到 一个 按键上。你需要找到输入字符串 word 所需的 最少 按键次数。返回重新映射按键后输入 word 所需的 最少 按键次数。下面给出了一种电话键盘上字母到按键的映射作为示例。注意 1,*,# 和 0 不 对应任何字母。[https://assets.leetcode.com/uploads/2023/12/26/keypaddesc.png] 示例 1:[https://assets.leetcode.com/uploads/2023/12/26/keypadv1e1.png]输入:word = "abcde"输出:5解释:图片中给出的重新映射方案的输入成本最小。"a" -> 在按键 2 上按一次"b" -> 在按键 3 上按一次"c" -> 在按键 4 上按一次"d" -> 在按键 5 上按一次"e" -> 在按键 6 上按一次总成本为 1 + 1 + 1 + 1 + 1 = 5 。可以证明不存在其他成本更低的映射方案。示例 2:[https://assets.leetcode.com/uploads/2023/12/26/keypadv1e2.png]输入:word = "xycdefghij"输出:12解释:图片中给出的重新映射方案的输入成本最小。"x" -> 在按键 2 上按一次"y" -> 在按键 2 上按两次"c" -> 在按键 3 上按一次"d" -> 在按键 3 上按两次"e" -> 在按键 4 上按一次"f" -> 在按键 5 上按一次"g" -> 在按键 6 上按一次"h" -> 在按键 7 上按一次"i" -> 在按键 8 上按一次"j" -> 在按键 9 上按一次总成本为 1 + 2 + 1 + 2 + 1 + 1 + 1 + 1 + 1 + 1 = 12 。可以证明不存在其他成本更低的映射方案。 提示: * 1 <= word.length <= 26 * word 仅由小写英文字母组成。 * word 中的所有字母互不相同。https://leetcode.cn/problems/minimum-number-of-pushes-to-type-word-i/一道算术题

class Solution:
    def minimumPushes(self, word: str) -> int:
        if len(word) < 8 :
            return len(word)
        # word 不同
        n,m = len(word)//8,len(word)%8
        l = [i*8 for i in range(1,n+1)]
        ret = sum(l) + (m * (n+1)) 
        # print(ret)
        return ret

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值