题解 | #数组分组#

数组分组

http://www.nowcoder.com/practice/9af744a3517440508dbeb297020aca86

目标和问题的变种,通过一定的转化之后就变成在数组中寻找目标大小的子数组,然后想使用动态规划来解决的,可是因为元素中存在小于0的数,动态规划变得不适用 于是改用递归解决了(在题解中copy了一份,加了注释)

/**
首先判断数据和是不是偶数
将所有三的倍数放在一起,五的倍数放在一起
然后问题就是将剩下的数分成两组,两组差是多少,
接着就变成剩下的数中找到和为多少的,存在小于0的数,所以使用动态规划不行
*/

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++){
            arr[i] = scanner.nextInt();
        }
        int sum3 = 0;
        int sum5 = 0;
        int sum = 0;
        int n35 = 0;
        for(int i = 0; i < n; i++){
            if(arr[i] % 5 == 0){
                sum5 += arr[i]; //所有5的倍数累加起来
                n35++;
            }else if(arr[i] %3 == 0){
                sum3 += arr[i]; //所有3的倍数(不包含5的倍数)累加起来
                n35++;
            }
            sum += arr[i];
        }
        if(sum % 2 != 0){
            System.out.println(false); //如果数据和不能平分,直接返回false
            return;
        }
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < n; i++){
            if(arr[i] % 3 != 0 && arr[i] % 5 != 0){
                list.add(arr[i]);
            }
        }
        // 如果数据和能够平分,如果需要满则条件,则在除去3,5的倍数的数中,应该能找到和为
        // sum / 2 - sum3的组合
        // sum / 2 - sum5的组合
        int target = sum / 2 - sum3;
        // 因为存在nums中存在数小于0,所以无法直接使用动态规划进行解决
        // 因此这边使用递归进行解决
        System.out.println(canPartition(list, target));
//         // 目标和问题 在arr_new中寻找目标和
//         boolean[][] dp = new boolean[n_new][target + 1];
//         // 使用dp[i][j]表示在arr_new[0:i]中是否存在和为j的组合
//         //先确定边界,存在负数
//         //dp[0][j]
//         for(int j = 0; j <= target; j++){
//             if(j == arr_new[0]){
//                 dp[0][j] = true;
//             }
//         }
//         for(int i = 1; i < n_new; i++){
//             for(int j = 0; j <= target ; j++){
//                 if(j >= arr_new[i]){
//                     dp[i][j] = dp[i][j - arr_new[i]] | dp[i - 1][j];
//                 }else{
//                     dp[i][j] = dp[i - 1][j];
//                 }
//             }
//         }
//         System.out.println(dp[n_new - 1][target]);
    }
    
    private static boolean canPartition(List<Integer> list, int target){
        // 从list中第0个元素开始选择
        return doCanPartition(0, list, target);
    }
    
    private static boolean doCanPartition(int index, List<Integer> list, int target){
        if(index == list.size()){
            return target == 0;
        }
        // 对list中第index个元素进行处理
        // 第index个元素可能会被选择,也可能不被选择,分两种情况
        // 递归的结束条件是遍历到列表的最后一个元素
        return doCanPartition(index + 1, list ,target - list.get(index)) | doCanPartition(index + 1, list ,target);
    }
}
全部评论

相关推荐

点赞 评论 收藏
分享
03-15 14:55
已编辑
门头沟学院 golang
bg:双非学院本&nbsp;ACM银&nbsp;go选手timeline:3.1号开始暑期投递3.7号第二家公司离职顽岩科技&nbsp;ai服务中台方向&nbsp;笔试➕两轮面试,二面挂(钱真的好多😭)厦门纳克希科技&nbsp;搞AI的,一面OC猎豹移动&nbsp;搞AIGC方向&nbsp;一面OC北京七牛云&nbsp;搞AI接口方向&nbsp;一面OC上海古德猫宁&nbsp;搞AIGC方向&nbsp;二面OC上海简文&nbsp;面试撞了直接拒深圳图灵&nbsp;搞AIGC方向一面后无消息懒得问了,面试官当场反馈不错其他小厂没记,通过率80%,小厂杀手😂北京字节&nbsp;具体业务不方便透露也是AIGC后端方向2.28约面&nbsp;(不知道怎么捞的我,我也没在别的地方投过字节简历哇)3.6一面&nbsp;一小时&nbsp;半小时拷打简历(主要是AIGC部分)剩余半小时两个看代码猜结果(经典go问题)➕合并二叉树(秒a,但是造case造了10分钟哈哈)一天后约二面3.12&nbsp;二面,让我挑简历上两个亮点说,主要说的docker容器生命周期管理和raft协议使用二分法优化新任leader上任后与follower同步时间。跟面试官有共鸣,面试官还问我docker底层cpu隔离原理和是否知道虚拟显存。之后一道easy算法,(o1空间解决&nbsp;给定字符串含有{和}是否合法)秒a,之后进阶版如何用10台机加快构建,想五分钟后a出来。面试官以为45分钟面试时间,留了18分钟让我跟他随便聊,后面考了linux&nbsp;top和free的部分数据说什么意思(专业对口了只能说,但是当时没答很好)。因为当时手里有7牛云offer,跟面试官说能否快点面试,马上另外一家时间到了。10分钟后约hr面3.13,上午hr面,下午走完流程offer到手3.14腾讯技术运营约面,想直接拒😂感受:&nbsp;因为有AIGC经验所以特别受AI初创公司青睐,AIGC后端感觉竞争很小(指今年),全是简历拷打,基本没有人问我八股(八股吟唱被打断.jpeg),学的东西比较广的同时也能纵向深挖学习,也运气比较好了哈哈可能出于性格原因,没有走主流Java路线,也没有去主动跟着课写项目,项目都是自己研究和写的哈哈
烤点老白薯:你根本不是典型学院本的那种人,贵了你这能力
查看7道真题和解析
点赞 评论 收藏
分享
评论
1
3
分享

创作者周榜

更多
牛客网
牛客企业服务