首页 > 其他分享 >数组分成两个最接近集合问题

数组分成两个最接近集合问题

时间:2022-12-09 21:56:09浏览次数:67  
标签:分成 arr p1 int rest 累加 数组 集合 dp

数组分成两个最接近集合问题

作者:Grey

原文地址:

博客园:数组分成两个最接近集合问题

CSDN:数组分成两个最接近集合问题

问题描述

给定一个正数数组 arr, 请把 arr 中所有的数分成两个集合,尽量让两个集合的累加和接近;

返回:最接近的情况下,较小集合的累加和。

主要思路

首先把数组之和求出来,假设为 sum,那么sum/2就是累加和的一半,定义递归函数

int process(int[] arr, int i, int rest)

递归含义表示:数组 arr 从 i 开始,一直到最后,随意选取进行累加,得到的最接近 rest 且较小的集合的累加和。

接下来是 base case,i 到数组 arr 的结尾位置,显然返回 0。

if (i == arr.length) {
    return 0;
}

接下来是普遍位置

        int p1 = process(arr, i + 1, rest);
        if (rest - arr[i] >= 0) {
            p1 = Math.max(process(arr, i + 1, rest - arr[i]) + arr[i], p1);
        } 

其中 p1 表示:不选取 i 位置的值进行累加,得到的最接近 rest 且较小的集合的累加和。

process(arr, i + 1, rest - arr[i]) + arr[i]表示:选取了 i 位置的值进行累加,得到的最接近 rest 且较小的集合的累加和。

注:选取 i 位置的值进行累加有条件,即rest - arr[i] > 0,否则选取之后,会得到较大的那个集合的累加和。

递归方法的完整代码见(含对数器)


    public static int splitSumClosed(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }
        int aim = sum / 2;
        return process(arr, 0, aim);
    }

    public static int process(int[] arr, int i, int rest) {
        if (i == arr.length) {
            return 0;
        }
        int p1 = process(arr, i + 1, rest);
        if (rest - arr[i] >= 0) {
            p1 = Math.max(process(arr, i + 1, rest - arr[i]) + arr[i], p1);
        }
        return p1;
    }

以上暴力递归可以改成动态规划,由于递归函数的可变参数有两个,一个是 i,一个是 rest,且其变化范围是固定的,所以可以定义一个二维数组来存所有的递归过程值,

int[][] dp = new int[arr.length + 1][aim + 1];

接下来根据递归函数可知dp表的最后一行均为 0;

dp[i][rest]依赖于dp[i+1][rest]dp[i+1][rest - arr[i]]两个位置的值,所以整个 dp 表可以从最后一行开始依次往上递推。

      for (int i = arr.length - 1; i >= 0; i--) {
            for (int j = 0; j < aim + 1; j++) {
                int p1 = dp[i + 1][j];
                if (j - arr[i] >= 0) {
                    p1 = Math.max(dp[i + 1][j - arr[i]] + arr[i], p1);
                }
                dp[i][j] = p1;
            }
        }

动态规划方法完整代码如下

    public static int splitSumClosed2(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }
        int aim = sum / 2;
        int[][] dp = new int[arr.length + 1][aim + 1];
        // last row == 0
        for (int i = arr.length - 1; i >= 0; i--) {
            for (int j = 0; j < aim + 1; j++) {
                int p1 = dp[i + 1][j];
                if (j - arr[i] >= 0) {
                    p1 = Math.max(dp[i + 1][j - arr[i]] + arr[i], p1);
                }
                dp[i][j] = p1;
            }
        }
        return dp[0][aim];
    }

更多

算法和数据结构笔记

标签:分成,arr,p1,int,rest,累加,数组,集合,dp
From: https://www.cnblogs.com/greyzeng/p/16970094.html

相关文章

  • 【LeeCode】剑指 Offer 42. 连续子数组的最大和
    【题目描述】输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)​​https://leetcode.cn/problems/lian-xu-zi-......
  • Android常用代码集合
    这篇文章主要记录一些常用的一些代码段,方便以后查阅,不断更新中。1:调用浏览器,载入某网址123Uriuri=Uri.parse("​​http://www.android-study.com​​");Intenti......
  • Vue中关于数组与对象修改触发页面更新的机制与原理简析
    Vue中关于数组与对象修改触发页面更新的机制与原理简析相关问题数组使用索引直接赋值与直接修改数组length时,不会触发页面更新。例如:<script>exportdefault{n......
  • python集合
    python集合集合同dict类似也由{}表示,但是他只包含键,而没有对应的值,同时元素也不能重复集合的创建只能用set():a=set()print(type(a))#<class'set'>内置方法(1)se......
  • JAVA集合类汇总
    一、集合与数组数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用。集合(只能存储对象,对象类型可以不一样)的长度可变,可......
  • JS 判断数组包含另一个数组
    ES6方法:1、findIndex (跟find类似,返回值不一样,findIndex找到则返回元素下标,否则返回-1)functiongetInclude(arr1,arr2){lettemp=[]for(constitemofa......
  • Java使用Steam流对数组进行排序
    原文地址:Java使用Steam流对数组进行排序-Stars-One的杂货小窝简单记下笔记,不是啥难的东西sorted()方法里传了一个比较器的接口Filefile=newFile("D:\\temp\\db_ba......
  • 【数据结构】二维树状数组
    一、二维树状数组二维树状数组,其实就是一维的树状数组上的节点再套个树状数组,就变成了二维树状数组了。constintN=1e3+10;inttr[N][N],n,m;#definelowbit(x......
  • 【Python】数据入库出库处理/list列表/数组/转字符串
     #!/usr/bin/envpython#-*-coding:utf-8-*-"""@Time:@Author:@File:dbDataTool.py@Version:1.0数据入库出库处理相关工具@Function:"""importha......
  • Vue 官方文档2.x教程学习笔记 1 基础 1.8 列表渲染 1.8.1 用 v-for 把一个数组对应为
    OverridetheentrypointofanimageIntroducedinGitLabandGitLabRunner9.4.Readmoreaboutthe extendedconfigurationoptions.Beforeexplainingtheav......