一道猿题库笔试题解答: 只包含1和-1的数组,如: [1, -1, 1, 1, 1, -1] 求其中和为0的最长连续子数组

来源:互联网 发布:美乎机油广州门市部 编辑:程序博客网 时间:2024/06/05 03:07

中午吃饭时一位同学说了一道猿题库的一道题,觉得很有意思。分享一下解决思路和代码。


思路

最开始想了分治法和动态规划,都觉得不适用,规律性不明显。

后来觉得必须将这些值(1和-1)转换成一种直接可判断是否和为0的表达方式。由此想到了一个基本原理,如果该数组(名字为arry)中,sum(arry[m], ... ,arry[n])为0,那么必然有sum(arry[0], ..., arry[m-1]) == sum(arry[0], ..., arry[n])。


实例

下面是个简单的例子,方框中是各个元素,假设最左侧元素下标为0。如果我们定义s[i] = sum(arry[0], ...,arry[i]),那么s[i]的值如数组下面的所示(一共15个元素):




根据这个原理,我们已经把何为0的子串的特征值,变为S[i]相等这一条件。比如,s[1] =s[3]=s[5]=s[7]=s[9]=s[13]=1(标记为红色),那么arry[2], arry[3]的和为0,arry[2],...,arry[5]的和为0,arry[2],...,arry[13]也为0。

同样,考虑标记蓝色的部分,arry[1], arry[2]的和为0, arry[1],..., arry[14]的和也为0。


与问题的对应

    我们只需要找出S[i]的各种值的出现位置,然后求得位置的差的最大值即可。比如,上面例子中:

     1) s[1] =s[13]=2;

     2) s[0]=s[14]=1;

     3) s[8]=s[10] = 3;

     4) s[9]=s[10] = 4;

    我们得到相应你给的最大子串长度分别为 13-1 = 12;  14-0=14; 10-8=2; 10-9=1。因此,最大的和为0子串长度为14。


以下是志坚点击打开链接同学贡献的代码

<span style="font-size:18px;">/* * test.cpp * *  Created on: 2016年9月7日 *      Author: zh-jian */#include <vector>#include <map>#include <iostream>using namespace std;/* * 描述: * arr 为只包含1 和 -1的数组,如: * [1 -1 1 1 1 -1] * 求其中和为0的最长连续子数组 * */int maxLen(vector<int> &arr){int mmax = 0,sum = 0;map<int,int> m;//m[s] = i; 表示i是,字段[1:k]和为s的最小的km[0] = 0;//边界for(int i = 0;i<arr.size();i++)if(m.find(sum+=arr[i])==m.end())//没出现过summ[sum] = i+1;else if(i+1-m[sum]>mmax)//出现过,更新长度mmax = i+1-m[sum];return mmax;}//测试程序//输入格式://3//1 -1 1int main(){int n;cin >>n;vector<int> arr(n);for(int i = 0;i<n;i++)cin >> arr[i];printf("max len:%d\n",maxLen(arr));return 0;}</span>










2 0