Leetcode 805. 数组的均值分割
本文最后更新于317 天前,其中的信息可能已经过时,如有错误请发送邮件到2446865563@qq.com

1.题目基本信息

1.1.题目描述

给定你一个整数数组 nums

我们要将 nums 数组中的每个元素移动到 A 数组 或者 B 数组中,使得 A 数组和 B 数组不为空,并且 average(A) == average(B) 。

如果可以完成则返回true , 否则返回 false 。

注意:对于数组 arr , average(arr) 是 arr 的所有元素的和除以 arr 长度。

1.2.题目地址

https://leetcode.cn/problems/split-array-with-same-average/description/

2.解题方法

2.1.解题思路

思路1:二进制枚举+哈希表

  • 易知移动之后,A数组和B数组都非空,且均值都等于nums的均值,则题目可以等价于nums中是否存在一个集合,其长度为k,且和为k*avg(nums),从而将两个数组的问题转为一个数组的问题;

  • 又由于avg(nums)中可能存在分数,所以可以将nums所有元素乘以n=len(nums),然后减去sum(nums),得到nums2,题目就等价于从nums2中找出一个集合,使其和为0。

  • 将nums2分为两半,枚举前半部分的所有子集,每个子集进行求和,存储到集合set1中,后半部分枚举子集并求和,记为sum1,如果-sum1出现在set1中,则说明存在。

思路2:动态规划

2.2.解题步骤

二进制枚举+哈希表方法步骤:

  • 第一步,记n=len(nums),将nums中所有元素乘以n,并减去sum(nums),得到nums2

  • 第二步,枚举nums2的前半部分的子集,并求每个子集的和,记录到集合set1中

  • 第三步,枚举nums2的后半部分的子集,并求和,记为sum1,如果-sum1出现在set1中,则说明存在,返回True

动态规划方法步骤:

  • 第一步,剪枝。如果存在k个元素的和的平均值等于nums的平均值,即sum(nums)/n=sum1/k,则sum1=sum(nums)*k/n,且sum1为整数,所以枚举所有的k,如果不存在sum1为整数,则直接返回False

  • 第二步,状态定义。dp[i]表示nums中i个元素的和所有的可能的值的集合;这里规定dp[i][x]=True为x在集合dp[i]中,False则表示不在集合dp[i]中

  • 第三步,状态初始化。dp[0]=set([0])

  • 第四步,状态转移。dp[i][x]=dp[i-1][x-num]。(注意:这里i的遍历一定需要逆序遍历,因为dp[i]依赖的是当前num前面的所有num状态下的dp[i-1],如果将num的影响添加到dp[i-1],那么dp[i]就不正确了)

  • 第五步,如果存在dp[i][x]=True and isum(nums)==nx,则说明存在题目要求的组合

3.解题代码

二进制枚举方法代码

class Solution:
    def splitArraySameAverage(self, nums: List[int]) -> bool:
        # 思路1:二进制子集枚举+哈希表。易知移动之后,A数组和B数组都非空,且均值都等于nums的均值,则题目可以等价于nums中是否存在一个集合,其长度为k,且和为k*avg(nums),从而将两个数组的问题转为一个数组的问题;又由于avg(nums)中可能存在分数,所以可以将nums所有元素乘以n=len(nums),然后减去sum(nums),得到nums2,题目就等价于从nums2中找出一个集合,使其和为0。将nums2分为两半,枚举前半部分的所有子集,每个子集进行求和,存储到集合set1中,后半部分枚举子集并求和,记为sum1,如果-sum1出现在set1中,则说明存在
        # 第一步,记n=len(nums),将nums中所有元素乘以n,并减去sum(nums),得到nums2
        n = len(nums)
        if n == 1:
            return False
        totalSum = sum(nums)
        nums2 = [t * n - totalSum for t in nums]
        # 第二步,枚举nums2的前半部分的子集,并求每个子集的和,记录到集合set1中
        n1 = n // 2
        set1 = set()
        for mask in range(1, 1 << n1):
            sum1 = 0
            for i in range(n1):
                if (mask >> i) & 1 == 1:
                    sum1 += nums2[i]
            if sum1 == 0:
                return True
            set1.add(sum1)
        # print(set1)
        # 第三步,枚举nums2的后半部分的子集,并求和,记为sum1,如果-sum1出现在set1中,则说明存在,返回True
        n2 = n - n1
        rsum = sum(nums2[n1:])
        for mask in range(1, 1 << n2):
            sum1 = 0
            for i in range(n2):
                if (mask >> i) & 1 == 1:
                    sum1 += nums2[n1 + i]
            # 存在0元素时会触发前面的判断条件,导致返回True
            if sum1 == 0 or (rsum != sum1 and -sum1 in set1):
                return True
        return False

动态规划方法代码

class Solution:
    def splitArraySameAverage(self, nums: List[int]) -> bool:
        # 思路2:动态规划(0-1背包问题)
        # 第一步,剪枝。如果存在k个元素的和的平均值等于nums的平均值,即sum(nums)/n=sum1/k,则sum1=sum(nums)*k/n,且sum1为整数,所以枚举所有的k,如果不存在sum1为整数,则直接返回False
        n = len(nums)
        n2 = n // 2
        total = sum(nums)
        if all([k * total % n != 0 for k in range(1, n + 1)]):
            return False
        # 第二步,状态定义。dp[i]表示nums中i个元素的和所有的可能的值的集合;这里规定dp[i][x]=True为x在集合dp[i]中,False则表示不在集合dp[i]中
        dp = [set() for _ in range(n2 + 1)]
        # 第三步,状态初始化。dp[0]=set([0])
        dp[0].add(0)
        # 第四步,状态转移。dp[i][x]=dp[i-1][x-num]。(注意:这里i的遍历一定需要逆序遍历,因为dp[i]依赖的是当前num前面的所有num状态下的dp[i-1],如果将num的影响添加到dp[i-1],那么dp[i]就不正确了)
        for num in nums:
            for i in range(n2, 0, -1):
                for x1 in dp[i - 1]:
                    val = x1 + num
                    if i * total == n * val:
                        return True
                    dp[i].add(val)
        # 第五步,如果存在dp[i][x]=True and i*sum(nums)==n*x,则说明存在题目要求的组合
        return False

4.执行结果

觉得有帮助可以投喂下博主哦~感谢!

作者:geek007

转载请注明文章地址及作者哦~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇