Advertisement
Guest User

Untitled

a guest
Sep 22nd, 2017
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.56 KB | None | 0 0
  1. import static org.assertj.core.api.Assertions.assertThat;
  2.  
  3. /**
  4. * Given an array which consists of non-negative integers and an integer m,
  5. * you can split the array into m non-empty continuous subarrays.
  6. * Write an algorithm to minimize the largest sum among these m subarrays.
  7.  
  8. Note:
  9. If n is the length of array, assume the following constraints are satisfied:
  10.  
  11. 1 ≤ n ≤ 1000
  12. 1 ≤ m ≤ min(50, n)
  13. Examples:
  14.  
  15. Input:
  16. nums = [7,2,5,10,8]
  17. m = 2
  18.  
  19. Output:
  20. 18
  21.  
  22. Explanation:
  23. There are four ways to split nums into two subarrays.
  24. The best way is to split it into [7,2,5] and [10,8],
  25. where the largest sum among the two subarrays is only 18.
  26. */
  27.  
  28. public class SplitArrayLargestSum {
  29. /**
  30. * 算法描述如下:
  31. * 给定任意一个数组,举例:
  32. * 【1, 2, 3】
  33. * 如果把这个数组分成三份,那么我们能得到的最小的数组和即是这个数组中的最大元素,这里是3
  34. * 如果把这个数组分成一份,那么我们能得到的最大的数组和就是这个数组中所有元素的和,这里是6
  35. * 所以对任意数组来说,我们要找的答案肯定在[最大元素,所有元素和]这个范围内
  36. * 那么具体如何缩小这个范围?
  37. * 1. 因为题目要求找出"连续数组和",所以我们可以从某个数字开始(这里选择(max+min)/ 2),看看如果我们每次都尽量多的取数字求和,
  38. * 使得尽可能多的数字小于这个中值,然后看看最后能分成多少组。
  39. * 2. 如果可以分成m组,那么说明我们的M值有可能是所求的答案,也有可能是当前的中值取得太小了,所以我们把 max = mid - 1 后继续
  40. * 3. 如果不能分成m组,那说明这个m太小了,不能是所求答案,所以我们要更新 min = mid + 1 然后再继续
  41. * 最后的min就是我们要求的答案
  42. *
  43. */
  44. public int splitArray(int[] nums, int m) {
  45. if(nums == null || nums.length == 0) {
  46. return 0;
  47. }
  48. int min = 0, max = 0;
  49. //找出可能出现的最大和最小值
  50. for(int num : nums) {
  51. min = Math.max(min, num);
  52. max += num;
  53. }
  54. if(m == 1) return max;
  55. //二分查找
  56. while(min <= max) {
  57. int mid = min + (max - min) / 2;
  58. if(canFit(mid, nums, m)) {
  59. //如果这些数字可以分成大小为mid的m组,说明有可能这个数字取的太大了,再减小
  60. max = mid - 1;
  61. } else {
  62. //如果不能分成大小为mid的m组,那么一定是这个mid数值取的太小了
  63. min = mid + 1;
  64. }
  65. }
  66. return min;
  67. }
  68.  
  69. private boolean canFit(int size, int[] nums, int m) {
  70. int numGroups = 1;
  71. int sum = 0;
  72. for(int num : nums) {
  73. sum += num;
  74. //一直更新sum,直到比size大,此时sum自动成为当前的num,然后这个sum就是下一个分组的第一个数字
  75. if(sum > size) {
  76. sum = num;
  77. numGroups++;
  78. if(numGroups > m) {
  79. return false;
  80. }
  81. }
  82. }
  83. return true;
  84. }
  85.  
  86. public void test() {
  87. int[] nums1 = {7, 2, 5, 10, 8};
  88. assertThat(splitArray(nums1, 2)).isEqualTo(18);
  89.  
  90. int[] nums2 = {1, 1, 1, 1, 1};
  91. assertThat(splitArray(nums2, 2)).isEqualTo(3);
  92. }
  93.  
  94. public static void main(String[] args) {
  95. SplitArrayLargestSum o = new SplitArrayLargestSum();
  96. o.test();
  97. }
  98. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement