【座右铭】1. 想要成为行家,就必须尝试解决大量的问题;
2. 解决大量问题并不代表能解决所有问题,而是表示解决下一个问题的几率变大了
1. 现有一个数组,里面包含了正数和负数,取其中若干个连续的数,要求这些数的和的绝对值最小【问题来源于论坛】
第一部分:思路
1. 对数组A[1...N],做和运算S[1...N],其中S[1] = A[1]; S[2] = A[1]+A[2];...;S[N]=A[1]+A[2]+A[3]+...+A[N]
2. 对S[1...N]从小到大排序
3. 连续子段绝对值最小:Min{ |S[i]|,S[i+1]-S[i]} 1<=i<=N
第二部分:Java代码,不考虑异常情况
//待修正,在获取连续子段在原数组中的开始索引和结束索引有bug。
//代码中存在错误的判断条件:S[i+1]对应的索引大于S[i]对应的索引
//问题提出日期:4.18
/**
* 现有一个数组,里面包含了正数和负数,取其中若干个连续的数,要求这些数的和的绝对值最小
* @param source
* 数组
* @param len
* 数组长度
* @return
* 一个三元组,分别是最小值,连续子段在原数组中的开始索引,结束索引
*/
public static int[] minAbs(int[] source, int len)
{
//保存最小值,连续子段在原数组中的开始索引,结束索引
int[] result = new int[3];
//和数组
int[] sum = new int[len];
sum[0] = source[0];
for(int i=1;i<len;i++)
{
source[i] += source[i-1];
sum[i] = source[i];
}
//排序
quicksort(sum, 0, len-1);
boolean isFromZero = false;
result[0] = sum[0]>0?sum[0]:-1*sum[0];
isFromZero = true;
result[1] = 0;
result[2] = sum[0];
for(int j=1;j<len;j++)
{
int cur = sum[j]>0?sum[j]:-1*sum[j];
if(cur<result[0])
{
result[0] = cur;
isFromZero = true;
result[1] = 0;
result[2] = sum[j];
}
cur = sum[j] - sum[j-1];
if(cur<result[0])
{
result[0] = cur;
isFromZero = false;
result[1] = sum[j-1];
result[2] = sum[j];
}
}
//还原数组
int k = len - 1;
for(;k>=0;k--)
{
if(source[k]==result[2])
{
result[2] = k;
break;
}
}
if(!isFromZero)
{
for(k=0;k<result[2];k++)
{
if(source[k]==result[1])
{
result[1] = k+1;
break;
}
}
}
for(k=len-1;k>0;k--)
{
source[k] -= source[k-1];
}
return result;
}
/**
* 快速排序
*/
static void quicksort(int[] source, int left, int right)
{
if(left<right)
{
int mid = partition(source, left, right);
quicksort(source, left, mid-1);
quicksort(source, mid+1, right);
}
}
static int partition(int[] source, int left, int right)
{
int start = left, end = right;
int tmp = 0;
left++;
while(left<=right)
{
while(left<=end&&source[left]<=source[start])
{
left++;
}
while(source[right]>source[start])
{
right--;
}
if(left<right)
{
tmp = source[left];
source[left] = source[right];
source[right] = tmp;
}
}
tmp = source[start];
source[start] = source[right];
source[right] = tmp;
return right;
}
第三部分:测试用例
数组{2,2,2,2}:返回{2,0,0}
数组{2,-2,1,3,4,-4}:返回{0,0,1}
数组{-2,1,2,-1,4}:返回{0,0,3}
数组{-2,3,1,-3,4,6,-7,2,8}:返回{0,3,6}
数组{-2,-6,-7,-3}:返回{2,0,0}