子数组的和等于特定值

来源:互联网 发布:三丰三坐标编程视频 编辑:程序博客网 时间:2024/04/30 06:41

这是一道比较经典的数组算法题。很多地方都有解法。当然蛮力肯定是不得分的。

我们来看一个数组A1,A2...An. 如果我们想得到Ai到Aj的和。我们可以求A1..Ai-1的和,然后再求A1到Aj的和。用这两个和相减,得到的就是Ai到Aj的和。因为A1到Aj的和包括A1到Ai-1,Ai到Aj。那么通过一次遍历数组我们就能够得到A1到An中任意数的和。但是我们要找的是子数组之和等于特定值。我们如何利用得到的结果呢?我们定义得到的结果为SUM1,SUM2...SUMn。那么用SUMm- 特定值S。如果能够在SUM数组中找到SUMn等于这个结果,SUMm-S=SUMn于是有SUMm-SUMn=S。根据我们前面的推倒,m到n求和的结果就是S。也就是说m到n就是我们要找的子数组。我们可以用一个二叉树表示SUMm-S的结果,然后每次遍历这个查找二叉树,看有没有找到SUMn期待的SUMm-S。如果没有,我们可以把SUMn-S也放入这个二叉树,继续SUMn+1的查找,知道找到匹配的结果。时间复杂度是nlogn。如果S值相对很小,我们还可以用一个0到S的数组,然后通过将SUMm-S放入数组指定下标。用这个方法,我们可以在O(1)的时间复杂度完成一次查找。所以整体的时间复杂度可以减小到O(n)。但是缺点是空间复杂度的增加。

 

struct Node{Node* left;Node* right;int value;int pos;}bool InsertNode(Node* root, int value, int pos, int& start, int& end){if(NULL == root){return false;}if(root->value = value){start = pos;end = pos;return true;}while(NULL != root){if(root->value == value){if(root->pos < pos){start = root->pos;end = pos;}else{end = root->pos;start = pos;}return true;}else if(root->value < value){if(root->right){root = root->right;}else{Node* newNode = new Node;newNode->pos = pos;newNode->value = value;root->right = newNode;return false;}}else{if(root->left){root = root->left;}else{Node* newNode = new Node;newNode->pos = pos;newNode->value = value;root->left = newNode;return false;}}}return false;}void FindSubArrayEqValue(int* A, int length, int S,int& start, int& end){if(length < 1 || NULL == A){start = -1;end = -1;return;}if(length ==1){start = 0;end = 0;}int* SUM = new int[length];SUM[0] = A[0];for(int i = 1; i < length; ++i){SUM[i] = SUM[i - 1] + A[i];}Node* root = new Node;root->pos = -1;root->value = 0;for(int i = 0; i < length; ++i){if(InsertNode(root,SUM[i] - S, i,start,end)){return ;}}ClearTree(root);delete []SUM;}


下面有一个更为复杂的思考题,如何找到子数组的和最接近特定值?

明天给出答案:)