[LeetCode] 最大子序列问题总结

152. 乘积最大子序列

乘积最大子序列

题目描述

给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

思路

不用dp数组,维护一个到当前位置i的最大值mmax和最小值mmin
这里mmaxmmin都是到当前i为止,区间[k,i]的最大值和最小值,k是不确定的,但i是一定的,也就是一定会由nums[i]作用。这样保证了子序列的连续性
然后对于每一次迭代,更新res。就得到了到所有位置为止的最大值。

代码

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n=nums.size();
        if(n==0)    return nums[0];
        int mmax,mmin,res;
        mmax=mmin=res=nums[0];
        for(int i=1;i<n;i++)
        {
            if(nums[i]>=0)
            {
                mmax=max(mmax*nums[i],nums[i]); // 若当前mmax<=0,则mmax=nums[i],否则,为mmax( + ) * nums[i] ( + )
                mmin=min(mmin*nums[i],nums[i]);
            }
            else
            {
                int t=mmin;
                mmin=min(mmax*nums[i],nums[i]); // 若当前mmax<=0,则mmin=nums[i],否则,为mmax( + ) * nums[i] ( - )
                mmax=max(t*nums[i],nums[i]);
            }
            res=max(res,mmax);
        }
        return res;
    }
};

395. 至少有K个重复字符的最长子字符串

至少有K个重复字符的最长子字符串

题目描述

找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。

输入:
s = “aaabb”, k = 3
输出:
3
最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。

输入:
s = “ababbc”, k = 2
输出:
5
最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。

思路

满足条件的最长子串DP思路可以总结一下,即两遍遍历,第一遍 i : 0 − > n i:0->n i:0>n,第二遍 j : i − > n j:i->n j:i>n j : i − > 0 j:i->0 j:i>0
第二遍遍历时,用到dp数组, d p [ i ] [ j ] dp[i][j] dp[i][j]的子问题条件是否成立,若成立,则在这个基础上更新答案 m a x ( r e s , d p [ i ] [ j ] + . . . ) max(res,dp[i][j]+...) max(res,dp[i][j]+...),同时每步要视题目更新 [ i , j ] [i,j] [i,j]区间的条件状态。
这道题的难点是怎么给一个子串计数,看它每个字符出现的次数。
解法是使用mask,用位运算更新。每一位代表这个字符对应的状态,1是不够k次,0是够k次。若mask是0,表示所有位都是0,即目前为止出现的所有字符都满足条件。

代码

class Solution {
public:
    int longestSubstring(string s, int k) {
        int i=0;
        int max_idx=0;
        int n=s.length();
        int res=0;
        while(i+k<=n)
        {
        	// 每一位计数,记录够/不够状态,避免每次都遍历m
            int mask=0;
            // 节约计算,到这一位都够,不用再遍历了
            max_idx=i;
            // 每一次循环计数,每个字符出现次数
            vector<int> m(26,0);
            for(int j=i;j<n;j++)
            {
                char t=s[j]-'a';
                m[t]++;
                if(m[t]<k)
                	// 1<
                    mask|=(1<<t);
                else
                	// 取反再取与,赋值0
                    mask&=(~(1<<t));
                // 出现的字符都够
                if(mask==0)
                {
                    res=max(res,j-i+1);
                    max_idx=j;
                }
            }
            i=max_idx+1;
        }
        return res;
    }
};

你可能感兴趣的:(LeetCode,算法)