求子数组和最接近0

题目:给定一个子数组,求子数组和最接近0

分析:

方法1:

这个问题和求子数组最大值优点相似,但解法不同,如果按照求子数组最大值的方法来求解,我们可以求出以j为截止的最大值和最小值,如果最大值和最小值都>0,那么最小值即为所求,如果都<0,那么最大值就为所求,如果有一个值为0,那么为0的就为所求,但问题是如果最大值>0而最小值<0的情况,需要向前回溯才能解决。因此复杂度还是N^2。

方法2:

我们先计算所有sum[0-j] 0<= j <n,然后对sum[0-j]的数组进行排序,那么对于任何i,j段的和等于:

sum[i-j]= sum[0-j] - sum[0-i];

因为已经对sum[0-j]进行了排序,所以只要找相邻的比较就可以了,找出绝对值最接近0的sum[0-j]和sum[0-i],那么i+1 到j 即是所求。

需要特别注意的一点是,sum的最前面要增加一个初值sum[-1-0] = 0,否则,如果开始的位置从0开始时,就会出现错误,编写程序时,开始就犯了这个错误。

具体程序如下:

#include <stdio.h>
template<typename T>
void Swap(T& a, T& b) {
  T tmp = a;
  a = b;
  b = tmp;
}
template<typename T>
int Partition(T array[], int start, int end) {
  int j = start - 1;
  T last = array[end];
  for (int i = start; i < end; ++i) {
    if (array[i] < last) {
      Swap(array[i], array[j+1]);
      j++;
    }
  }
  Swap(array[end], array[j+1]);
  return j+1;
}
template<typename T>
void QuickSort(T array[], int start, int end) {
  if (start < end) {
    int pivot = Partition(array, start, end);
    QuickSort(array, start, pivot - 1);
    QuickSort(array, pivot + 1, end);
  }
}
int Abs(int a) {
  return a < 0 ? -1 * a : a;
}
class SumFromStart {
 public:
  SumFromStart() : end_(0), sum_(0) {}
  int end_;
  int sum_;
  bool operator<(const SumFromStart& right) {
    return sum_ < right.sum_;
  }
};
bool SubArraySumNearZero(int array[], int length, int* start, int* end) {
  if (length < 1) {
    return false;
  }
  if (length == 1) {
    *start = 0;
    *end = 0;
    return true;
  }
  SumFromStart sum_from_start[length + 1];
  sum_from_start[0].sum_ = 0;
  sum_from_start[0].end_ = -1;
  for (int i = 1; i <= length; ++i) {
    sum_from_start[i].sum_ = sum_from_start[i-1].sum_ + array[i-1];
    sum_from_start[i].end_ = i - 1;
  }
  QuickSort(sum_from_start, 0, length + 1);
  for (int i = 0; i <= length; ++i) {
    printf("%d ", sum_from_start[i].sum_);
  }
  printf("\n");
  int min = sum_from_start[1].sum_ - sum_from_start[0].sum_;
  for (int i = 2; i < length; ++i) {
    if (Abs(sum_from_start[i].sum_ - sum_from_start[i-1].sum_) < min) {
      if (sum_from_start[i].end_ < sum_from_start[i-1].end_) {
        *start = sum_from_start[i].end_ + 1;
        *end = sum_from_start[i-1].end_;
      } else {
        *start = sum_from_start[i-1].end_ + 1;
        *end = sum_from_start[i].end_;
      }
    }
  }
  return true;
}
int main(int argc, char** argv) {
  int array[] = {-2, 3, 4, -5, 8, 2, -2};
  int start = -1;
  int end = -1;
  SubArraySumNearZero(array, sizeof(array) / sizeof(int), &start, &end);
  printf("%d  %d\n", start, end);
}
  

参考文献:

http://blog.csdn.net/bertzhang/article/details/7242497

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值