leetcode-410. Split Array Largest Sum

来源:互联网 发布:php缓存技术有哪些 编辑:程序博客网 时间:2024/05/18 02:45

题目:

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:
Given m satisfies the following constraint: 1 ≤ m ≤ length(nums) ≤ 14,000.

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.
简单意思就是:给你一个含有n个元素的数组,让你把这数组划分成m段,那么每个段的所有元素就有一个sum,那么一次划分就会有一个最大的和(largest_sum),现在就是让你

求这个largest_sum的最小值!!!

方法一:

刚开始拿到这个题目,看到它的提示是动态规划,就一直想,就是想不出来后来在网上找到了大神们都用二分查找算法,但是这些博客没有对算法的思路有个详细的介绍,本文

就二分查找方法给出自己的理解!!

代码(模仿大神们的思想写的):

<pre name="code" class="cpp">class Solution {public:bool is_reach(vector<int>& arr, int m, long target_sum){long cur_sum = arr[0];int sections = 1;for (int i = 1; i < arr.size(); ++i){cur_sum += arr[i];if (cur_sum > target_sum){++sections;cur_sum = arr[i];}}if (sections > m)return false;//如果段计数器值大于m,假设题目要求m=3,而我们求得的段的大小为4,return true;}int splitArray(vector<int>& arr, int m) {int n = arr.size();long low = arr[0], high = arr[0];for (int i = 1; i < n; ++i){low = max(low, long(arr[i]));//数组的单个最大元素high += arr[i];//数组的所有元素}int res = 0;while (low < high){long mid = (low + high) / 2;if (is_reach(arr, m, mid)){high = mid;res = mid;}elselow = mid + 1;}return low;}};


Submission Result: Accepted  More Details 

Next challenges: (M) Unique Binary Search Trees (E) Closest Binary Search Tree Value (M) Count Numbers with Unique Digits

Share your acceptance!

解析(leetcode上大神给的解释):

1.我们可以这样对待数组,我们将数组分成每段小于或等于target_num的小组,那么每个小组的和肯定小于或等于target_sum,如果此时我们得到的分段数目小于或等于m,

那么确定最大子段和小于或等于target_sum,否则,最大子段和的最小值一定大于target_sum;

2. 在设计的时候一定要注意: 如果写成high=mid和low=mid的模式,则有可能陷入死循环的可能,因为我们最后low,mid和high的指针的转态如下图所示:

如果is_reach传回的值是true,那么执行low=mid,那么会陷入死循环!!!!

方法二:

利用动态规划思想:

版本1:

int splitArray1(vector<int>nums, int m){int L = nums.size();int *S = new int[L + 1];S[0] = 0;for (int i = 0; i<L; i++)S[i + 1] = S[i] + nums[i];int *dp = new int[L];for (int i = 0; i<L; i++)dp[i] = S[L] - S[i];for (int s = 1; s<m; s++){for (int i = 0; i<L - s; i++){dp[i] = INT_MAX;for (int j = i + 1; j <= L - s; j++){int t = max(dp[j], S[j] - S[i]);if (t <= dp[i])dp[i] = t;else break;}}}int re = dp[0];delete[]S;delete[]dp;return re;}

Submission Result: Accepted  More Details 

Next challenges: (H) Regular Expression Matching (M) Search Insert Position (M) Range Sum Query 2D - Immutable

版本2:

class Solution {public:int splitArray(vector<int>& nums, int m) {int size = nums.size();vector<int>row(size,0);vector<vector<int>>re;for (int i = 0; i <= m; i++)re.push_back(row);//二维数组//将数组分成1段的情况int sum = 0;for (int j = 0; j < size; j++){sum += nums[j];re[1][j] = sum;}//填表int temp, now;for (int i = 2; i <= m;i++){//i表示要分成的段数for (int j = i - 1; j < size;j++){temp = INT_MAX;for (int k = i - 2; k <= j - 1; k++){//re[i][j]表示将数组索引从0到j的元素分成i段now = max(re[i-1][k],re[1][j]-re[1][k]);if (now<=temp)temp = now;}re[i][j] = temp;}}return re[m][size - 1];}};
结果:

Status: 

Time Limit Exceeded

Submitted: 2 minutes ago


这个说明思想没有问题的,但是时间复杂度较高,运行超时,还要进一步优化!!!

算法思想:

re[s][j]:表示数组元素下标从0到j分成s段的结果;

re[s+1][j]:表示数组元素下标从0到j分成s+1段的结果,那么re[s+1][j]=min{max(d[s,k],a[k+1]+a[k+2]+....+a[j])},其中,s-2<=k<=j-1(见代码).

0 0