leetcode 410. Split Array Largest Sum
来源:互联网 发布:unity3d 角色资源 编辑:程序博客网 时间:2024/06/07 20:08
Given an array which consists of non-negative integers and an integer m, you can split the array into m non-empty continuous subarrays. Write an algorithm to minimize the largest sum among these m subarrays.
Note:
If n is the length of array, assume the following constraints are satisfied:
- 1 ≤ n ≤ 1000
- 1 ≤ m ≤ min(50, n)
Examples:
Input:nums = [7,2,5,10,8]m = 2Output:18Explanation:There are four ways to split nums into two subarrays.The best way is to split it into [7,2,5] and [10,8],where the largest sum among the two subarrays is only 18.这道题很明显又是一道递归 with memo 或者 DP 的题。
这道题又一次印证了 map 没有 int[][]数组 快的结论!因为我使用 HashMap<Integer,HashMap<Integer,Integer> 华丽丽地TLE了,但是改成 int[][] 就AC了。
我的思路是:int[row][column] :row存储了当前数组的开始索引 left,column 存储了当前的 m。因此 memo[i][j] 就是:从 i 开始的数组要被划分为 j 个子数组时的结果值。
public int splitArray(int[] nums, int m) {int[][] memo=new int[nums.length][m+1];return split(nums, 0, nums.length-1, m, memo);}public int split(int[] nums,int left,int right,int m,int[][] memo){if(memo[left][m]>0){return memo[left][m];}int result;if(m==1){result=0;for(int i=left;i<=right;i++){result+=nums[i];}}else{result=Integer.MAX_VALUE;int sum=0;for(int i=left;i<=right-1;i++){sum+=nums[i];int min=Math.max(sum, split(nums, i+1, right, m-1, memo));result=Math.min(result, min);}}memo[left][m]=result;return result;}还有大神用 DP 来做。这里的 DP 是精简空间复杂度后的 DP 。
DP[i] 存储当前 m 状态下 从索引 i 开始将数组分割成 m 个子数组时的结果值。
DP[i] 初始化时的m=1,因此DP[i]就存储 i~length 的和。如 DP[0] 就是 0~length 的和,DP[length-1] = nums[length-1]。
然后从 m=2,一直计算到我们需要的 m。
从 i =0开始,一直算到 maxPart,这里的 maxPart 指:如果我们需要分为 m 个部分,那么到了某个索引就该停止。比如如果 m=2,那么到了 nums.length-1 就该停了,得留 1 个给剩下的 part。如果 m=3,那么到了 nums.length-2 就该停了,得留 2 个分给剩下的 2 个 part。
p是分割点(是从p和p+1之间砍一刀),leftSum派给左边,然后rightSum就看 dp[p+1] 。此时的 dp[p+1] 是从索引 p+1 开始将数组分割成 m-1 个子数组时的结果值。(因为p+1 还没有被当前 m 覆盖,还停留在之前循环 m-1 时的值)
public static int splitArray(int[] nums, int m) { int[] dp = new int[nums.length]; for(int i = nums.length-1; i>=0; i--) dp[i] = i== nums.length -1 ? nums[i] : dp[i+1] + nums[i]; for(int im = 2; im <= m; im ++) { int maxPart = nums.length + 1 - im; for(int i=0; i<maxPart; i++) { dp[i] = Integer.MAX_VALUE; int leftSum = 0; for(int p=i; p<maxPart; p++) { leftSum += nums[p]; if(leftSum > dp[i]) break; // There's no more better soluiton, stop the search. int val = Math.max(leftSum, dp[p+1]); if(val < dp[i]) dp[i] = val; } if(im == m) // The last round, get first one is enough break; } } return dp[0];}.
还有大神用了很奇特的思路:二分查找 来做。- 最后的结果介于 数组的最大元素值 和 数组所有元素的和 之间。
- 使用二分查找来获得正确结果。
l = max number of array; r = sum of all numbers in the array;
每次我们取mid = (l + r) / 2;
- 使用 greedy 算法来缩小 left 和 right 的边界。(把mid看做是我们需要求得的值)这个算法的思路在于:将数组从左开始遍历,累积加到sum,当发现sum>mid时,就切一刀,使得刀与刀之间的 元素sum<=mid。再继续开始从0累积sum。然后看一共切了多少刀。如果刀数>m,说明 mid 取得太小了,将左边界+1。如果刀数<m,说明 mid 取得太大了,将右边界+1。步骤如下:
3.1 将数组从左开始切
3.2 确保在每2个cut之间的元素的和(首尾全包括) 要小于等于mid
3.3 那么有两种结果: 要么我们能将该数组分割为超过 m 个子数组,要么不能。
如果我们能, 这意味着我们取的mid
太小了,以至于不能把数组分为 m 部分,并且每部分的和都不超过mid
。此时应当增加左边界l = mid + 1;
如果我们不能, 说明我们可以将数组分为 m 部分,并且每部分的和都不超过mid
。当前 mid 能够满足要求,但是我们需要得到最小的 mid。此时应当减少右边界r = mid - 1;
public class Solution { public int splitArray(int[] nums, int m) { int max = 0; long sum = 0; for (int num : nums) { max = Math.max(num, max); sum += num; } if (m == 1) return (int)sum; //binary search long l = max; long r = sum; while (l <= r) { long mid = (l + r)/ 2; if (valid(mid, nums, m)) { r = mid - 1; } else { l = mid + 1; } } return (int)l; } public boolean valid(long target, int[] nums, int m) { int count = 1; long total = 0; for(int num : nums) { total += num; if (total > target) { total = num; count++; if (count > m) { return false; } } } return true; }}
阅读全文
0 0
- 【Leetcode】410. Split Array Largest Sum
- leetcode 410.Split Array Largest Sum
- leetcode-410. Split Array Largest Sum
- 【LeetCode】410. Split Array Largest Sum
- Leetcode 410. Split Array Largest Sum
- [LeetCode]410. Split Array Largest Sum
- leetcode 410.Split Array Largest Sum(Hard)
- 【Leetcode】410. Split Array Largest Sum
- LeetCode 410. Split Array Largest Sum
- LeetCode 410. Split Array Largest Sum
- LeetCode 410. Split Array Largest Sum
- leetcode 410. Split Array Largest Sum
- [leetcode]410. Split Array Largest Sum
- Leetcode 410. Split Array Largest Sum
- Leetcode 410. Split Array Largest Sum
- LeetCode 410. Split Array Largest Sum
- leetcode 410. Split Array Largest Sum
- leetcode题解-410. Split Array Largest Sum
- React Native带你实现scrollable-tab-view(三)
- [ASP.NET]学习日志-问题篇
- SpringMVC学习笔记
- 面试题:查询部门最高工资的员工信息
- 插件收集
- leetcode 410. Split Array Largest Sum
- 安卓RecyclerView的简单实用
- NodeJs学习笔记_01
- 计算一组离散数据的标准偏差和中位数。函数的构建
- ajax版员工分页查询
- leetcode349. Intersection of Two Arrays
- 根据经纬度判断车辆是否进度电子围栏
- iOS 7以上原生二维码、条码扫描(ZXingObjC相册读取)
- yii2显示当前controller和action的名字