当前位置: 首页 > article >正文

Python面试宝典第50题:分割等和子集

题目

        给你一个只包含正整数的非空数组nums,请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

        示例 1:

输入:nums = [1, 5, 11, 5]
输出:True
解释:数组可以分割成[1, 5, 5]和[11]。

        示例 2:

输入:nums = [1, 2, 3, 5]
输出:False
解释:数组不能分割成两个元素和相等的子集。

备忘录法

        备忘录法的基本思想是:在递归过程中缓存已计算的结果,避免重复计算相同子问题。这样可以显著减少递归树的分支,提高算法效率。使用备忘录法求解本题的主要步骤如下。

        1、定义递归函数can_partition_helper。该函数接受四个参数:数组nums、目标和target、当前索引index、备忘录memo。其中,备忘录memo用于存储已计算过的子问题的结果。

        2、基本情况。

        (1)如果target为0,则表示找到了一个子集,返回True。

        (2)如果target小于0,或者index超出了数组范围,则表示无法找到合适的子集,返回False。

        (3)如果target和index的组合已经存在于备忘录memo中,则直接返回备忘录中的结果。

        3、进行递归。

        (1)对于每个元素nums[index],有两种选择:包含或不包含该元素。

        (2)如果包含nums[index],则递归调用can_partition_helper函数,计算剩余元素是否可以构成目标和target - nums[index]。

        (3)如果不包含nums[index],则递归调用can_partition_helper 函数,计算剩余元素是否可以构成目标和target。

        (4)如果任一递归路径返回True,则更新备忘录memo,并返回True。

        4、如果所有递归路径都返回False,则表示无法分割成两个子集,返回False。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def partition_equal_subset_sum_by_memoization(nums):
    total_sum = sum(nums)
    # 如果总和不是偶数,则无法分割成两个子集
    if total_sum % 2 != 0:
        return False
    
    target = total_sum // 2
    memo = {}

    def can_partition_helper(nums, target, index):
        # 如果target为0,则表示找到了一个子集
        if target == 0:
            return True
        
        # 如果target小于0,或者index超出了数组范围,则表示无法找到合适的子集
        if target < 0 or index >= len(nums):
            return False
        
        # 如果target和index的组合已经存在于备忘录中,则直接返回备忘录中的结果
        if (target, index) in memo:
            return memo[(target, index)]

        # 包含nums[index]
        include = can_partition_helper(nums, target - nums[index], index + 1)
        # 不包含nums[index]
        exclude = can_partition_helper(nums, target, index + 1)

        # 更新备忘录memo
        memo[(target, index)] = include or exclude
        # 返回结果
        return include or exclude

    return can_partition_helper(nums, target, 0)

nums = [1, 5, 11, 5]
print(partition_equal_subset_sum_by_memoization(nums))

nums = [1, 2, 3, 5]
print(partition_equal_subset_sum_by_memoization(nums))

动态规划法

        使用动态规划法时,我们需要构建一个一维数组dp来存储达到每个子集和的可能性。数组dp的索引表示子集和,dp[i]表示能否通过选择数组中的元素达到和为i的子集。使用动态规划法求解本题的主要步骤如下。

        1、初始化。计算数组nums的总和total_sum,如果total_sum不是偶数,则无法分割成两个子集,直接返回False。否则,计算目标和target为total_sum // 2。

        2、构建DP数组。创建一个长度为target + 1的布尔型数组dp,其中dp[0]初始化为True,表示总和为0的子集始终存在,其他位置初始化为False。

        3、填充DP数组。对于每个元素num,从target到num的每个子集和i,更新dp[i]为dp[i]或dp[i - num]。

        4、返回dp[target],表示是否存在和为目标和target的子集。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def partition_equal_subset_sum_by_dp(nums):
    total_sum = sum(nums)
    # 如果总和不是偶数,则无法分割成两个子集
    if total_sum % 2 != 0:
        return False
    
    target = total_sum // 2
    # 创建一个长度为target + 1的布尔型数组
    dp = [False] * (target + 1)
    dp[0] = True
    
    # 填充DP数组
    for num in nums:
        # 从target到num的每个子集和i
        for i in range(target, num - 1, -1):
            # 更新dp[i]
            dp[i] = dp[i] or dp[i - num]
    
    return dp[target]

nums = [1, 5, 11, 5]
print(partition_equal_subset_sum_by_dp(nums))

nums = [1, 2, 3, 5]
print(partition_equal_subset_sum_by_dp(nums))

总结

        使用备忘录法时,每个子问题只被计算一次,子问题的数量与数组nums的长度、目标和target成正比。总的时间复杂度为O(N * target),其中N是数组nums的长度,target是目标和的一半。备忘录的最大大小为N * target,故其空间复杂度为O(N * target)。相比纯递归法,备忘录法通过避免重复计算相同的子问题,大大提升了效率。


http://www.kler.cn/news/314548.html

相关文章:

  • Vscode、插件历史版本下载
  • [数据结构与算法·C++] 笔记 1.4 算法复杂性分析
  • [附源码]SpringBoot+VUE+Java实现人脸识别系统
  • 实战指南:深度剖析Servlet+JSP+JDBC技术栈下的用户CRUD操作
  • 探秘 Web Bluetooth API:连接蓝牙设备的新利器
  • 828华为云征文|Flexus X实例GitLab部署构建流水线-私人一体化代码仓库~
  • AWS账号可以共用吗?
  • vue 中互相不关联的两个组件怎么进行通信(数据传输)
  • MFC获取网页的html文本
  • 视频V4改进
  • 锐捷 睿易路由器存在RCE漏洞
  • 会声会影2025视频剪辑教学
  • 开源集成开发环境搭建之VSCode安装部署教程
  • MySQL:基本查询操作
  • java计算机毕设课设—土地档案管理系统(附源码、文章、相关截图、部署视频)
  • 基于Java的SSM(Spring、Spring MVC、MyBatis)框架构建的远程诊断系统
  • 论文阅读 - MDFEND: Multi-domain Fake News Detection
  • 探索iPhone一键删除重复照片的方法
  • Kafka 为什么这么快?
  • 某乐指数爬虫逆向分析
  • Qemu开发ARM篇-2、uboot交叉编译
  • Android14 手机蓝牙配对后阻塞问题解决
  • python 自动化测试接口
  • 递归快速获取机构树型图
  • 【赵渝强老师】基于ZooKeeper实现Hadoop HA
  • DELPHI编译软件时带上当前IDE的版本号
  • 2024/9/21 leetcode 21.合并两个有序链表 2.两数相加
  • Hive企业级调优[5]—— HQL语法优化之数据倾斜
  • [Vue] 从零开始使用 Vite 创建 Vue 项目
  • webrtc gclient sync报错问题解决