• [getLongestLength] 加和为0的最长子串长度


    点击这里查看原文

    假设一个数组仅仅由1和-1组成,求该数组的和为0的最长子串的长度。
    例如:
    {1,-1,1,-1,1,1,1} 输出:4.
    昨天机试的时候做到这道题,不会做,今天思考一下。

    普通的解法

    枚举所有的子串,然后得到和为0的最长的长度,复杂度是O(n*n),这个应该会超时,昨天只能保存,不能运行,我猜这样应该不行,需要下面方法。其实看到这题,我想到的是最长回文子串这道题,仔细想想,还是挺像的,该搞一个传送门的。

    正确的解法

    解法:动态规划,dp0[i]表示以i结尾的加和为0 得到最长子串长度,dp1[i] 表示以i结尾的加和为1的最长子串长度,dp2[i]表示以i结尾的加和为-1 的最长子串长度。于是可以得到下面的递推关系:

    上面这段话摘自那个博客,n的平方复杂度不行,那大概就是nlogn或者n,需要考虑dp,然后分析,数组只有1或者-1,然后需要获得结果为0的长度,所以碰到1,我们希望能知道前面和为-1的最长,遇到-1,我们需要知道和为1的最长,所以我们就需要维护到当前位置,以当前位置结尾的和为0,1,-1的最长长度,然后思考怎么递推。显然,1 + 0 = 1, 1 + (-1) = 0,转移到1和0,很容易,转移到-1,怎么处理,什么结果加上1能得到结果是-1,当然是-2,但是我没维护和为2的,这就需要巧妙的思想。

    利用当前段的结果为0,加上这段之前的结果为-1,这样就能导出当前段为-1的,这样的思想很巧妙,仔细想想怎么回事,是不是有点kmp,马拉车算法之类的思想。

    好了,贴一下那位大神的代码:

    #include<iostream>
    #include<vector>
    using namespace std;
    int getLongestLength(int array[],int size){
        if(size<=1) return 0;
        vector<int>dp0(size);
        vector<int>dp1(size);
        vector<int>dp2(size);
        dp0[0]=0;
        if(array[0]==1){
            dp1[0]=1;
            dp2[0]=0;
        }else{
            dp1[0]=0;
            dp2[0]=1;
        }
        int result =0;
        for(int i =1;i<size;i++){
            if(array[i]==1){
                dp0[i]=dp2[i-1]==0?0:dp2[i-1]+1;
                dp1[i]=dp0[i-1]==0?1:dp0[i-1]+1;
                dp2[i]=dp0[i]==0?0:dp2[i-dp0[i]]+dp0[i];
            }else{
                dp0[i]=dp1[i-1]==0?0:dp1[i-1]+ 1;
                dp1[i]=dp0[i]==0?0:dp1[i-dp0[i]]+dp0[0];
                dp2[i]=dp0[i-1]==0?0:dp0[i-1]+1;
            }
            if(result<dp0[i]) result  =dp0[i];
        }
    
        return result;
    }
    int main(){
        int nums[]={-1,1,-1,1};
        cout<<getLongestLength(nums,4);
    }
    

    我认为也需要判断一下dp2[i-dp0[i]]的结果不为0,才行。没有画图,不知道解释清楚没有。

    还可以这样做,维护前缀和s,i<j, s(j) = s(i)的时候,可以知道i + 1 到j和为0,即可满足要求。这个好像容易理解一些。

    百度搜索1,-1,最长字串 可以找到解法。延伸到数组里面只有0和1,比如只有a和b,求最长子串a和b的个数相等之类的。还有什么变形,想出来再记下来吧。

    int getLongestString(vector<int> & v) {
        int n = v.size();
        if(n < 2) return 0;
        map<int, int> m;
        int s = 0;
        int res = 0;
        for(int i = 0; i < n; i++) {
            s += v[i];
            if(s == 0) {
                res = max(res, i + 1); continue;
            }
            if(!m.count(s)) {
                m[s] = i;
            } else {
                int len = i - m[s];
                res = max(res, len);
            }
        }
        return res;
    }
    
  • 相关阅读:
    python基础_类的继承
    python基础_命名规范
    jmeter分布式压测(linux)
    Jmeter压测报错java.net.BindException: Address already in use: connect
    分布式压测平台之Ngrinder(安装篇)
    关于TeamCenter流程开发Handler问题
    C语言中的指向运算符:->
    Eclipse Action与Command的区别
    Eclipse开发RCP项目的plugin.xml详解
    Swing中通过按钮对表格JTable选中行对象进行上移和下移的操作
  • 原文地址:https://www.cnblogs.com/y119777/p/5851025.html
Copyright © 2020-2023  润新知