416. Partition Equal Subset Sum 分割两个和相等的子串

探讨如何判断一个正整数数组是否可以分割成两个子集,使两个子集的元素总和相等。通过分析问题转化为背包问题,介绍了一种动态规划解决方案。

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Note:

  1. Each of the array element will not exceed 100.
  2. The array size will not exceed 200.

Example 1:

Input: [1, 5, 11, 5]

Output: true

Explanation: The array can be partitioned as [1, 5, 5] and [11].

Example 2:

Input: [1, 2, 3, 5]

Output: false

Explanation: The array cannot be partitioned into equal sum subsets.

题意:将一个数组分成两个子数组,两个子数组各自累加的和能否相等。 

思路:

首先将数组所有的和相加,如果和是奇数,则肯定不能满足题意;若和时偶数,就要考虑数组中的数是否能满足部分和等于总数和的一半,这是背包问题,并且所有的数只能被使用一次或者不使用。

创建一个大小为总数和/2的布尔数组dp= new boolean[sum/2 + 1],表示从0到sum/2每个数是否能由数组中的数拼凑而成。

如数组nums中有[1、2、4、5]四个数,则sum/2=6,则 dp = {true,true,true,true,true,true,true},表示0-6都能用nums数组中的数凑成。

判断dp[]中某个数target是否能够被拼凑成的具体方法是,分别遍历nums中的数num,然后看target是否拼凑成功,或者target-num是否拼凑成功,如果target-num拼凑成功,则target-num + num就能拼凑成功。

以nums中的数为例:当遍历到1时,dp = {true,true,false,false,false,false,false}  (1能拼凑成1);

当遍历到2时,dp = {true,true,true,true,false,false,false}  (2能拼凑成2, 1、2能拼凑成3);

当遍历到4时,dp = {true,true,true,true,true,true,false}  (4能拼凑成4, 1、4能拼凑成5);

当遍历到5时,dp = {true,true,true,true,true,true,true}  (1、6或2、4能拼凑成6);

代码:

class Solution {
    public boolean canPartition(int[] nums) {
        int sum =0;
        for(int num : nums){
            sum += num;
        }
        
        if(sum%2 == 1)
            return false;
        
        sum /= 2;
        boolean[] dp = new boolean[sum+1];
        dp[0] =true;
        for(int num: nums){
            for(int j=sum;j>=num;j--){
                dp[j]=dp[j]||dp[j-num];    
            }
        }
        return dp[sum];
    }
}

 

在 Java 中,Guava 提供的 `Lists.partition(List, int)` 方法可以将一个 `List` 按照指定大小进行拆分,生成一个 `List<List<T>>` 的结构。然而,对于 `Set` 集合而言,Guava 并未直接提供类似的方法来实现相同的功能。为了对 `Set` 进行类似的分割操作,可以通过手动实现逻辑或借助其他工具类进行处理。 一种常见的方式是使用 `Iterators` 工具类中的 `partition(Iterator, int)` 方法,将 `Set` 转换为 `Iterator` 后进行分割,并封装成多个子集。这种方式适用于需要保持集合唯一性且不依赖顺序的场景。以下是一个示例代码: ```java import com.google.common.collect.Iterators; import java.util.*; public class SetPartitionExample { public static <T> List<Set<T>> partitionSet(Set<T> originalSet, int size) { Iterator<T> iterator = originalSet.iterator(); List<Set<T>> result = new ArrayList<>(); while (iterator.hasNext()) { Set<T> subset = new HashSet<>(); int count = 0; while (count < size && iterator.hasNext()) { subset.add(iterator.next()); count++; } result.add(subset); } return result; } public static void main(String[] args) { Set<String> originalSet = new HashSet<>(); originalSet.add("快"); originalSet.add("敲"); originalSet.add("代"); originalSet.add("码"); originalSet.add("去"); List<Set<String>> partitionedSets = partitionSet(originalSet, 2); System.out.println(partitionedSets); // 输出被分割后的 Set 列表 } } ``` 上述方法通过遍历原始 `Set` 并按指定大小逐个构建新的子集,最终返回一个包含多个子集的 `List<Set<T>>` 结构。该方式避免了对 `List` 的依赖,同时保留了集合元素的唯一性[^1]。 需要注意的是,由于 `Set` 不保证元素的顺序,在分割后无法确保子集中元素的排列顺序与原始集合一致。如果顺序至关重要,建议先将 `Set` 转换为有序集合(如 `LinkedHashSet`)再进行处理。 此外,也可以结合第三方库(如 Apache Commons Collections 或自定义工具类)实现更高效的集合分割功能,但 Guava 本身并未提供专门针对 `Set` 的 `partition` 方法,因此需手动实现相关逻辑[^2]。 ### 相关问题 1. 如何在 Java 中使用 Apache Commons Collections 对 Set 进行分区? 2. 使用 Guava 的 Iterators.partition 方法对 Set 分割时有哪些注意事项? 3. 如果 Set 中的元素数量不能被分割大小整除,剩余的元素如何处理? 4. 在高并发环境下对 Set 进行分割操作是否需要考虑线程安全?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值