题解 | #农场的奶牛分组#

农场的奶牛分组

https://www.nowcoder.com/practice/bdb90a97a15d42f989e406080d88bed9?tpId=354&tqId=10595842&ru=/exam/oj&qru=/ta/interview-202-top/question-ranking&sourceUrl=%2Fexam%2Foj

先求得奶牛的总体重sum,然后找到一个目标值target,使得分成两组的奶牛体重和都等于target。

首先,我们需要检查是否满足可以将奶牛分成两组的条件。如果奶牛的总数小于2,或者总体重不能被2整除,那么无法分成两组,直接返回false。

然后,我们可以定义一个二维数组dp,dp[i][j]表示在前i头奶牛中是否存在一个分组,使得体重之和等于j。

初始状态为dp[0][0] = true,表示前0头奶牛的体重之和为0,是成立的。

接下来,我们可以进行动态规划的转移。对于第i头奶牛,我们有两种选择:将其加入一个组,或者不加入组。如果加入组,那么相应的状态变化为dp[i][j] = dp[i-1][j-weight[i]](前i头牛的状态=前i-1头牛在(体重=j-第i头牛的体重)的状态),

其中weight[i]表示第i头奶牛的体重。如果不加入任何组,状态保持不变,即dp[i][j] = dp[i-1][j]。

最终,我们需要检查dp[n][target]是否为true,其中n为奶牛数量

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param weights int整型一维数组
     * @return bool布尔型
     */
    public boolean canPartition (int[] weights) {
        // write code here
        int n = weights.length;
        int sum = Arrays.stream(weights).sum();
        // 无法分为两组
        if (n < 2 || sum % 2 != 0) {
            return false;
        }
        int target = sum / 2;
        // dp[i][j]表示在前i头奶牛中是否存在一个分组,使得体重之和为j
        boolean[][] dp = new boolean[n + 1][target + 1];
        // 表示前0头牛的体重之和为0可以分组
        dp[0][0] = true;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= target; j++) {
                // 第i头牛不加入分组
                dp[i][j] = dp[i - 1][j];// 与上一次保持一致
                if (j >= weights[i - 1]) {// 第i头牛的体重<=j<=target
                    // 加入分组,状态=dp[i-1][j-weights[i-1]](前i-1头牛在(j-当前牛的体重)的分组状态)
                    dp[i][j] |= dp[i - 1][j - weights[i - 1]];
                }
            }
        }
        return dp[n][target];
    }
}

计算整个数组的元素和。如果和为奇数,那么无法分为两个和相等的子集,因此返回false。

然后,要将问题转换为是否存在一个子集,使得它的和等于整个数组的和的一半,也就是target。

使用动态规划的方法来解决这个问题。定义一个布尔数组dp,其中dp[i]表示是否存在一个子集的和等于i。初始时,设置dp[0]为true,因为和为0的子集总是存在的。

接下来,遍历整个weights数组。对于数组中的每个元素weight,从target开始逆序更新dp数组。如果dp[i-weight]为true,那么说明存在一个子集的和等于i-weight,那么将dp[i]设置为true。

最后,返回dp[target]的值,表示是否存在一个子集的和等于target。

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param weights int整型一维数组
     * @return bool布尔型
     */
    public boolean canPartition (int[] weights) {
        // write code here
        int n = weights.length;
        int sum = Arrays.stream(weights).sum();
        // 无法分为两组
        if (n < 2 || sum % 2 != 0) {
            return false;
        }
        int target = sum / 2;
        // 是否存在一组的和=i
        boolean[] dp = new boolean[target + 1];
        // 和为0的子集存在
        dp[0] = true;
        for(int weight:weights){
            // 若dp[i-weight]==true,则dp[i]=true
            // i<weight时,和为i的子集不存在
            for(int i=target;i>=weight;--i){
                dp[i] |= dp[i-weight];
            }
        }
        return dp[target];
    }
}

面试高频TOP202 文章被收录于专栏

面试高频TOP202题解

全部评论

相关推荐

喜欢吃蛋糕仰泳鲈鱼是我的神:字节可以找个hr 给你挂了,再放池子捞
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务