新农上路
- 积分
- 99
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2013-11-4
- 最后登录
- 1970-1-1
|
本帖最后由 maplain 于 2015-10-17 08:02 编辑
我的想法是:
1. sort;
2. 输出相同元素的个数,组成一个新的array;
3. 针对新的array做minmax partition;
minmax partition核心思想是二分法+贪心:
1. 找到每个bin中元素和(新的这个array里一个bin中的所有“元素和”表明原始array中对应bin中元素的个数)的可能区间范围;
1. min是新的array中最大值;
2. max是新的array中所有元素的和;
2. 二分搜索这个区间中的值v是否能够得到满足题意的划分,判断时只需要贪心地从左向右添加元素直至达到v;
代码如下:- import java.util.*;
- /* http://www.1point3acres.com/bbs/thread-144544-1-1.html
- */
- class OptimalPartition {
- public List<List<Integer>> partitions(int[] nums, int k) {
- List<List<Integer>> result = new ArrayList<>();
- if (nums == null || nums.length == 0) return result;
- int n = nums.length;
- // Sort array, then collapse it.
- Arrays.sort(nums);
- List<Integer> collapsed = new ArrayList<>();
- int[] info = collapse(nums, collapsed);
- int max = info[0], sum = info[1];
- // Use binary search to find appropriate value;
- int rangeMin = max; // The minimum value of number of elements in a given bin
- int rangeMax = sum; // The maximum value of number of elements in a given bin
- int num = binarySearch(collapsed, rangeMin, rangeMax, k);
- // Finish the partition using 'num';
- int i = 0;
- while (i < n) {
- List<Integer> item = new ArrayList<>();
- int counter = 0;
- while (counter++ < num && i<n) {
- item.add(nums[i++]);
- }
- result.add(item);
- }
- return result;
- }
- /* After sorting the original array, convert it into another array, element of which
- * is the number of consecutive equal number.
- */
- private int[] collapse(int[] nums, List<Integer> collapsed) {
- int prev = nums[0];
- int counter = 1;
- int sum = 0, max = 0;
- for (int i=1; i<nums.length; ++i) {
- if (nums[i] == prev) counter++;
- else {
- collapsed.add(counter);
- max = Math.max(max, counter);
- sum+=counter;
- counter = 1;
- prev = nums[i];
- }
- }
- collapsed.add(counter);
- max = Math.max(max, counter);
- sum+=counter;
- return new int[] {max, sum};
- }
- private int binarySearch(List<Integer> collapsed, int start, int end, int k) {
- if (start > end) return -1;
- int mid = start + (end - start)/2;
- if (partition(collapsed, mid, k)) {
- int left = binarySearch(collapsed, start, mid-1, k);
- if (left != -1) return left;
- return mid;
- }
- return binarySearch(collapsed, mid+1, end, k);
- }
- // Greedily allocate element from left to right using given 'maximum number of elements in a bin'
- private boolean partition(List<Integer> collapsed, int max, int k) {
- int n = collapsed.size();
- int counter = 0;
- int partitionNum = 0;
- for (int i=0; i<n; ++i) {
- if (counter+collapsed.get(i)<=max) {
- counter += collapsed.get(i);
- } else {
- counter = 0;
- i--;
- partitionNum++;
- }
- }
- partitionNum++;
- return partitionNum<=k;
- }
- public static void main(String[] args) {
- OptimalPartition o = new OptimalPartition();
- for (List<Integer> part: o.partitions(new int[] {5, 2, 3, 6, 1, 6}, 3)) {
- System.out.println(part);
- }
- for (List<Integer> part: o.partitions(new int[] {1, 1, 1, 1, 1, 1}, 3)) {
- System.out.println(part);
- }
- for (List<Integer> part: o.partitions(new int[] {1, 1, 1, 1, 2, 2, 3}, 2)) {
- System.out.println(part);
- }
- }
- }
复制代码 如果感觉我解释的不够清楚,可以参考这里:最大值最小值问题http://blog.csdn.net/nanjunxiao/article/details/8145971
不确定是否正确,求大神拍砖。 |
|