连续子数组最大和-最大乘积-乘积为正数的最大子数组长度

dp6 连续子数组最大和

dp6

注意此题子数组长度最小为1.因此负数的情况也需要考虑。

由于此题我已做过多遍,不再赘述。

#include <bits/stdc++.h>
using namespace std;
int main () {
    int n;
    scanf("%d", &n);
    int tmp = 0, sum = -101, c;
    for(int i = 0; i < n; ++i) {
        scanf("%d", &c);
        tmp += c;
        if(sum < tmp) {
            sum = tmp;
        }        
        if(tmp < 0) {
            tmp = 0;
        }
    }
    printf("%d", sum);
    return 0;
}

dp7 连续子数组的最大乘积

dp7

此题基本是套着最大和的模板 关键点在于什么情况下该重置tmp

#include <bits/stdc++.h>
using namespace std;
int main () {
    int n;
    scanf("%d", &n);
    vector<int> dp(n);
    int tmp = 1, sum = -101, l = -1, r = n, c = 0;//统计最左边的负数下标 最右边负数下标 总负数个数
    for(int i = 0; i < n; ++i) {
        scanf("%d", &dp[i]);
        if(dp[i] < 0) {
            c++;
            if(l == -1) {
                l = i;
            }
            r = i;
        }
    }
    //从头到尾
    for(int i = 0; i < n; ++i) {
        tmp *= dp[i];
        if(sum < tmp) {//小于就更新
            sum = tmp;
        }
        if(dp[i] == 0) {//乘0会导致后续都是0 所以需要重置tmp
            tmp = 1;
        }
        if(i == r && (c & 1)) {//如果到了最右边 说明再也不会出现负数 同时负数个数又是奇数个数 说明当前tmp只能为负数了 这种情况下 就需要重置tmp
            tmp = 1;
        }
    }
    tmp = 1;//从尾到头
    //比如 2 -2 -5 -4 3 这种情况 最优的其实是从右向左得到的-5 -4 3
    for(int i = n - 1; i >= 0; --i) {
        tmp *= dp[i];
        if(sum < tmp) {
            sum = tmp;
        }
        if(dp[i] == 0) {
            tmp = 1;
        }
        if(i == l && (c & 1)) {
            tmp = 1;
        }
    }
    printf("%d", sum);
    return 0;
}

dp8 乘积为正数的最大子数组长度

dp8

/*
0 负数个数为奇数
	记录从负数起点到当前点前一个的长度
  否则
  	记录tmp中的长度
  重置ne, tmp, positive
正数 长度tmp增加
	负数个数为奇数
		记录从负数起点到当前点前一个的长度
	否则
		正数长度记录positive增加
		记录tmp的长度
负数 当前负数个数为偶数 tmp长度增加, positive更新为tmp 记录
	当前负数个数为奇数 
		如果后续无负数 记录长度 重置ne, tmp, positive
		否则 长度增加
		
写到头晕
稍微总结一下
需要去记录一下最右边负数的下标 用于去判断当前乘法序列的长度是否还能增加
需要ne 用于判断当前序列的负数个数是奇数还是偶数
positive 记录当前序列乘积为正数序列的长度 
tmp 记录当前序列的长度

对于
1 2 -3 4 序列
ne = 1
positive = 2
tmp = 4
如果之后遇到0了
那么应该让 tmp - positive - 1 (即[4])去更新最后的结果 (因为[1 2]在正数那里已经算过了)
然后重置各个元素
如果碰到了正数 tmp增加 记录tmp - positive - 1
如果碰到了负数
	那么整个序列乘积为正 tmp++, positive = tmp 长度增加 正数序列长度置为 序列长度
*/
#include <bits/stdc++.h>
using namespace std;
int main () {
    int n;
    scanf("%d", &n);
    vector<int> dp(n);
    int tmp = 0, r = n, count = 0, ne = 0, positive = 0;//统计最左边的负数下标 最右边负数下标 总负数个数
    for(int i = 0; i < n; ++i) {
        scanf("%d", &dp[i]);
        if(dp[i] < 0) {
            r = i;
        }
    }
    for(int i = 0; i < n; ++i) {
        if(dp[i] == 0) {
            if(ne & 1) {
                count = max(count, tmp-1-positive);
            } else {
                count = max(count, tmp);
            }
            tmp = 0;//重置
            ne = 0;
            positive = 0;
        } else if (dp[i] < 0) {
            ++ne;
            if(ne & 1) { //当前负数个数为奇数
                if(i < r) {//后续还有负数
                    ++tmp;//增加长度
                } else {//后续没有负数
                    //cout << count << ' ' << tmp << endl;
                    count = max(count, tmp);//记录长度
                    ne = 0;//重置
                    tmp = 0;
                    positive = 0;
                }
            } else {//偶数个数
                ++tmp;
                positive = tmp;
                count = max(count, tmp);//记录长度
            }
        } else {
            ++tmp;
            if(ne & 1) {
                count = max(count, tmp-1-positive);
            } else {
                ++positive;
                count = max(count, tmp);
            }
        }
    }
    printf("%d", count);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值