将数组分为两部分,使得这两部分和最接近,返回这两部分的差值

【问题】将数组分为两部分,使得两部分的和最接近,返回两部分的差值。例如:

int[] array={1,0,1,7,2,4},分为两部分为{1,0,1,2,4},{7},差值为1。

参考1:《编程之美》第2.18节,不过问题有所不同,2.18节要求长度为2n的数组分为两个长度为n的数组,使得两部分和最接近。

参考2:http://www.tuicool.com/articles/ZF73Af

【思路】动态规划的解法。求得array的和sum,问题转化为:在array中选取若干个元素,使得这些元素的和<=sum/2,且是最接近sum/2的元素集合。

开一个数组:int[][]f=new int[length+1][sum/2+1]

状态方程:f[i][j]=Max(f[i-1][j-array[i]]+array[i],f[i-1][j])

解释:f[i][j]表示array中i个元素的和<=j,且是最接近j的元素集合。f[i-1][j-array[i]]表示array中i-1个元素的和最接近j-array[i],所以f[i][j]应该是[i-1][j-array[i]]+array[i]和f[i-1][j]中最大的那个。有点像0-1背包问题。

**
 * 创建时间:2014年10月7日 下午8:52:57 项目名称:Test
 *
 * @author Cao Yanfeng
 * @since JDK 1.6.0_21 类说明:将数组分为两部分,使得这两部分和最接近,返回这两部分的差值 注意:不要求将数组平均分
 */
public class DivideArrayTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] array = { 1, 0, 1, 7, 2, 4 };
		System.out.println(getMaxDiff(array));

	}

	/* f[i][j]表示i个元素装容量为j的背包能装的最大容量 */
	public static int getMaxDiff(int[] array) {
		int sum = getSum(array);
		int length = array.length;
		int[][] f = new int[length + 1][sum / 2 + 1];
		for (int i = 0; i < length; i++) {
			for (int j = 1; j <= sum / 2; j++) {
				f[i + 1][j] = f[i][j];
				if (array[i] <= j && f[i][j - array[i]] + array[i] > f[i][j]) {
					f[i + 1][j] = f[i][j - array[i]] + array[i];
				}
			}
		}
		return sum - 2 * f[length][sum / 2];
	}

	public static int getSum(int[] array) {
		int sum = 0;
		for (int i = 0; i < array.length; i++) {
			sum += array[i];
		}
		return sum;
	}

}
时间: 2024-10-24 23:47:13

将数组分为两部分,使得这两部分和最接近,返回这两部分的差值的相关文章

【华为OJ】201301 JAVA 题目0-1级 将数组分为相等的两组

描述:  编写一个函数,传入一个int型数组,返回该数组能否分成两组,使得两组中各元素加起来的和相等,并且,所有5的倍数必须在其中一个组中,所有3的倍数在另一个组中(不包括5的倍数),能满足以上条件,返回true:不满足时返回false. 知识点: 语言基础,字符串,循环,函数,指针,枚举,位运算,结构体,联合体,文件操作,递归    题目来源: 内部整理  练习阶段: 初级  运行时间限制: 10Sec 内存限制: 128MByte 输入: 输入输入的数据个数 输入一个int型数组 输出: 返

n个数分为两组,两组数的个数尽可能相等,差值最小

题目描述:对于有n个数的数组,分为两组,这两组的数的个数尽可能相等(不超过1),同时两组的数之和的差值最小. 这个题目使用类似0-1背包问题,思路:从k个数中选i个数,求所有可能的和,并把这些和放在flag中用true表示.(k,i,flag见代码) 1 public static void main(String[] args){ 2 int[] arr = {1 , 2 , 3 , 5 , 7 , 8 , 9}; 3 int n = 7; 4 int sum = 0; 5 for(int i

Single Number 数组中除了某个元素出现一次,其他都出现两次,找出这个元素

Given an array of integers, every element appears twice except for one. Find that single one. Note:Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 数组中除了某个元素出现一次,其他都出现两次,找出只出现一次的元素. 一个数字和自己异或

交换两个数组的元素使之总和的差值最小

题目描述: 有两个数组a,b,大小都为n,数组元素的值任意整型数,无序: 要求:通过交换a,b中的元素,使数组a元素的和与数组b元素的和之间的差最小. #include "stdafx.h" #include <math.h> #include <time.h> #include <stdlib.h> void print_arr(int a[], int b[], int n) { printf("a: "); for (int

剑指Offer36 数组所有数字出现两次,只有两个出现了一次,找出这两个数字

1 /************************************************************************* 2 > File Name: 38_NumbersAppearOnce.cpp 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年09月03日 星期六 10时50分32秒 6 *******************************

阿里 2014-08-29 校招机试题 求一个存放整数的二叉树相差最大的两节点差值绝对值

题目:写一个函数,输入一个二叉树,树中每个节点存放了一个整数值,函数返回这颗二叉树中相差最大的两个节点间的差值绝对值.请注意程序效率. 如果是数值之差,感觉怎么着也得遍历一遍,直接修改下二叉树的基本遍历代码就可以. #include<stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node * left; struct Node * right; } BitNode, *BiTree; /* 求

android 返回键两次退出

返回键两次退出 private long exitTime = 0; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){ if((System.currentTimeMillis()-exitTime) > 2000){ Toast.make

大小最接近的那两个数(位操作)

主要是熟悉位操作,寻找一个数二进制1位相同,且大小最相近的数. //题目描述 // //有一个正整数,请找出其二进制表示中1的个数相同.且大小最接近的那两个数.(一个略大,一个略小) //给定正整数int x,请返回一个vector,代表所求的两个数(小的在前).保证答案存在. //测试样例: //2 //返回:[1, 4] // //思路: //取得略大的数: //c0 是拖尾0的个数,c1是紧邻拖尾0左方连续位为1的个数, p为最右边但非拖尾的0 等于 c0 + c1 //1 把位p置为1

求二叉树中相差最大的两个节点间的差值绝对值

题目描述: 写一个函数,输入一个二叉树,树中每个节点存放了一个整数值,函数返回这棵二叉树中相差最大的两个节点间的差值绝对值.请注意程序效率. solution: int findMinMax(BTNode *T) { if(!T) return 0; int max = INT_MIN; int min = INT_MAX; stack<BTNode*> s; s.push(T); while (!s.empty()) { BTNode *tmp = s.top(); if(tmp->d