描述
给定一个整数数组,找出两个不重叠的子数组A和B,使两个子数组和的差的绝对值|SUM(A) - SUM(B)|最大。
返回这个最大的差值。
样例
给出数组[1, 2, -3, 1],返回 6
挑战
时间复杂度为O(n),空间复杂度为O(n)
解题思路
很久没刷题了,周末没事干,上lintcode刷刷题。
这道题第一眼大家应该都有一个思路,就是找左右的最大子数组然后相减。
我一直记得的一个处理连续型动规是要找global和local,太久没做题了手生了就直接这样做了。
后来发现两个问题,第一个是边界值难处理,比如local[0]是没有意义的(归根结底是不熟练);第二个是逻辑分的太细,一个函数就能解决的问题我写了四个函数解决;第三个是对local和global理解没有通透,有点太上层,如果好好往下层走就能发现有更直接的方式。先贴简洁版的code,后面的是繁琐但容易理解的code。
代码
简洁版本:
class Solution {
public:
/**
* @param nums: A list of integers
* @return: An integer indicate the value of maximum difference between two substrings
*/
int max_diff(vector<int>& nums){
int size = nums.size();
int* max = new int[size+1];
int* min_reverse = new int[size+1];
long sum = 0;
int max_num = INT_MIN;
for(int i=0; i<size; i++){
sum += nums[i];
max_num = max_num > sum ? max_num : sum;
if(sum < 0) sum = 0;
max[i] = max_num;
}
sum = 0;
int min_num = INT_MAX;
for(int i=size-1; i>=0; i--){
sum += nums[i];
min_num = min_num < sum ? min_num : sum;
if(sum > 0) sum = 0;
min_reverse[i] = min_num;
}
int res = 0;
for(int i=0; i<size-1; i++){
int tmp = abs(max[i] - min_reverse[i+1]);
res = tmp > res ? tmp : res;
}
return res;
}
int maxDiffSubArrays(vector<int> &nums) {
// write your code here
int res_left_max_right_min = max_diff(nums);
reverse(nums.begin(), nums.end());
int res_left_min_right_max = max_diff(nums);
return res_left_max_right_min > res_left_min_right_max? res_left_max_right_min:res_left_min_right_max;
}
};
繁琐版本:
class Solution {
public:
/**
* @param nums: A list of integers
* @return: An integer indicate the value of maximum difference between two substrings
*/
int max_num(int a, int b, int c){
int first_max = a>b?a:b;
return first_max >c? first_max:c;
}
int min_num(int a, int b, int c){
int first_max = a>b?b:a;
return first_max >c? c:first_max;
}
void get_min_global(int* global, int* local, int size, int* res){
for(int i=1; i<size-1; i++){
res[i] = global[i] < local[i] ? global[i]:local[i];
}
}
void get_max_global(int* global, int* local, int size, int* res){
for(int i=1; i<size-1; i++){
res[i] = global[i] > local[i] ? global[i]:local[i];
}
}
void maxSubArrays(vector<int> &nums,int* max_global){
int size = nums.size();
int* max_local = new int[size+1];
max_global[0] = nums[0];
max_local[0] = -(1<<30);
for(int i=1; i<size; i++){
max_local[i] = max_global[i-1] > max_local[i-1]?max_global[i-1]:max_local[i-1];
max_global[i] = max_global[i-1]+nums[i] > nums[i]?max_global[i-1]+nums[i]:nums[i];
}
get_max_global(max_global, max_local, size, max_global);
}
void minSubArrays(vector<int> &nums, int* max_global){
int size = nums.size();
int* max_local = new int[size+1];
max_global[0] = nums[0];
max_local[0] = (1<<30);
for(int i=1; i<size; i++){
max_local[i] = max_global[i-1] < max_local[i-1]?max_global[i-1]:max_local[i-1];
max_global[i] = max_global[i-1]+nums[i] < nums[i]?max_global[i-1]+nums[i]:nums[i];
}
get_min_global(max_global, max_local, size, max_global);
}
void max_reverseSubArrays(vector<int> &nums, int* max_global){
int size = nums.size();
int* max_local = new int[size+1];
max_global[size-1] = nums[size-1];
max_local[size-1] = -(1<<30);
for(int i=size-2; i>=0; i--){
max_local[i] = max_global[i+1] > max_local[i+1]?max_global[i+1]:max_local[i+1];
max_global[i] = max_global[i+1]+nums[i] > nums[i]?max_global[i+1]+nums[i]:nums[i];
}
get_max_global(max_global, max_local, size, max_global);
}
void min_reverseSubArrays(vector<int> &nums, int* max_global){
int size = nums.size();
//int* max_global = new int[size+1];
int* max_local = new int[size+1];
max_global[size-1] = nums[size-1];
max_local[size-1] = (1<<30);
for(int i=size-2; i>=0; i--){
max_local[i] = max_global[i+1] < max_local[i]?max_global[i+1]:max_local[i];
max_global[i] = max_global[i+1]+nums[i] < nums[i]?max_global[i+1]+nums[i]:nums[i];
}
get_min_global(max_global, max_local, size, max_global);
}
void print(int* arr, int size){
for(int i=0; i<size; i++){
cout << arr[i] << " ";
}
cout << endl;
}
int maxDiffSubArrays(vector<int> &nums) {
// write your code here
int size = nums.size();
if(size == 2){
return abs(nums[0] - nums[1]);
}
int* max_global = new int[size+1];
int* min_global = new int[size+1];
int* max_reverse_global = new int[size+1];
int* min_reverse_global = new int[size+1];
maxSubArrays(nums, max_global);
max_reverseSubArrays(nums, max_reverse_global);
minSubArrays(nums, min_global);
min_reverseSubArrays(nums,min_reverse_global);
// print(max_global,size);
// print(min_global,size);
// print(max_reverse_global,size);
// print(min_reverse_global,size);
int res = -1;
for(int cut_pos = 0; cut_pos < size -1; cut_pos++){
int tmp1 = abs(max_global[cut_pos] - min_reverse_global[cut_pos+1]);
int tmp2 = abs(max_reverse_global[cut_pos+1] - min_global[cut_pos]);
res = max_num(res, tmp1, tmp2);
}
return res;
}
};