STL: map应用之统计和为0的最长子段

1. 题目描述

给定序列 {a_0, a_1, ... , a_n},输出序列中和为0的子段中,长度的最大值.

例如:{1, -1, 1},则和为0的最长子段长为 2.

2. 思路描述

若某子段的和为0,则 子段前的第一个元素的前缀和 一定等于 子段最后一个元素的前缀和

由图易知:L2 = L1 + L0,又 L0 = 0,则 L2 = L1. 在该情况下,该子段的长度等于两个前缀和相等的元素的下标之差,如 6 - 3 = 3.

这里考虑特殊情况:若 L1 的长度恰为0,即某个和为0的子段无排在其前面的元素,此时整个子段的长度就是子段末尾元素的下标值加1.

至此,问题转化为某个元素:

1. 若元素前缀和为0,则当前子段长为该元素的下标值 + 1.

2. 若元素前缀和不为0,是否存在排在其前面,且前缀和与其相等的元素,若存在,则子段长为两个前缀和相等的元素的下标之差,若不存在,则可以先记录当前元素前缀和及其下标,方便后续比较判断.

3. C++算法实现

遍历前缀和过程的三种情况
① 前缀和为0:整个子段为合法子串,无需将0记录 map
② 前缀和不为0,且从未出现,记录该前缀和下的下标,下标记录要加1
③ 前缀和不为0,且已经出现,则与所记录的下标之差为子段长

void Solution(vector<int>& a){
    int res = 0;                //默认无符合题意的子串
    map<int,int> mp;

    if(a[0] != 0)
        mp[a[0]] = 1;           //②
    else
        res = 1;                //①
    
    for(int i = 1; i < int(a.size()); i++){
        a[i] += a[i-1];
        if(a[i] == 0)           //①
            res = max(res,i + 1);
        else if(mp[a[i]] == 0)  //②
            mp[a[i]] = i;
        else{                   //③
            res = max(res,i - mp[a[i]]);
        }
    }
    cout << res;
}

🚩 第2行:res为最终统计结果,初始状态下默认无和为0的子串.

🚩 第3行:利用STL的map实现前缀和的记录与查询,key 记录前缀和值,value记录下标.

🚩 第5~8行:为了方便前缀和统计,先记录a[0]的值. 若a[0]不为0,则需要记录mp中方便后序判断,否则直接以 0 + 1 作为符合的子段长度.

🚩 第11行:统计前缀和.

🚩 第14行:由于map默认情况下的 value 为0,故一次判断前面是否有相同前缀和的元素出现.

注意:相同前缀和元素下标只需记录第一次即可,因为这样得到的子段才会是最长子段.

4. 算法时间复杂度分析

针对每一个元素,统计前缀和消耗O(1)时间,map查询、插入消耗O(logN)时间,因此总时间复杂度为O(N·logN).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值