【错题集-编程题】比那名居的桃子(滑动窗口 / 前缀和)

本文讨论了解决Nowcoder题目中涉及的滑动窗口和前缀和方法,两种策略在计算快乐值和羞耻度总和时的应用,以及如何根据数据规模选择合适的数据类型以优化代码效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

牛客对应题目链接:比那名居的桃子 (nowcoder.com)


一、分析题目

1、滑动窗口

由题意得,我们是要枚举所有大小为 k 的子数组,并且求出这段⼦数组中快乐值和羞耻度之和。因此,可以利用滑动窗口的思想,用两个变量维护大小为 k 的窗口的总和,并且不断更新即可。

2、前缀和

这个就比较简单了,先预处理出来快乐值和羞耻度的前缀和数组,然后枚举的过程中直接求出⼀段区间的和即可(sum[i+k-1] - sum[i-1])。但是相比较于滑动窗口的思想,会有空间消耗。

二、代码

1、看题解之前AC的代码

//滑动窗口
#include <iostream>
using namespace std;

typedef long long LL;
const int N=1e5+10, INF=1e9+7;
int happy[N], shame[N];

int main()
{
    LL n, k;
    cin >> n >> k;
    for(int i=0; i<n; i++) cin >> happy[i];
    for(int i=0; i<n; i++) cin >> shame[i];
    int left=0, right=0;
    LL sum_happy=0, sum_shame=0;
    LL max_happy=0, min_shame=INF;
    LL st=0;
    while(right<n)
    {
        sum_happy+=happy[right];
        sum_shame+=shame[right];
        while(right-left+1>k)
        {
            sum_happy-=happy[left];
            sum_shame-=shame[left];
            left++;
        }
        if(right-left+1==k)
        {
            if(sum_happy>=max_happy)
            {
                if(sum_happy==max_happy && sum_shame<min_shame)
                {
                    st=left;
                    max_happy=sum_happy;
                    min_shame=sum_shame;
                }
                else if(sum_happy>max_happy)
                {
                    st=left;
                    max_happy=sum_happy;
                    min_shame=sum_shame;
                }
            }
        }
        right++;
    }
    cout << st+1 << endl; 
    return 0;
}

2、看了题解之后AC的代码 

//前缀和
#include <iostream>
using namespace std;

typedef long long LL;
const int N=1e5+10, INF=1e9+7;
int happy[N], shame[N];
LL preHappy[N], preShame[N]; 

int main()
{
    LL n, k;
    cin >> n >> k;
    for(int i=1; i<=n; i++) cin >> happy[i];
    for(int i=1; i<=n; i++) cin >> shame[i];
    for(int i=1; i<=n; i++)
    {
        preHappy[i]=preHappy[i-1]+happy[i];
        preShame[i]=preShame[i-1]+shame[i];
    }
    LL max_happy=0, min_shame=INF;
    int st=0;
    for(int i=1; i<=n-k+1; i++)
    {
        LL sum_happy=preHappy[i+k-1]-preHappy[i-1];
        LL sum_shame=preShame[i+k-1]-preShame[i-1];
        if(sum_happy==max_happy && sum_shame<min_shame)
        {
            st=i;
            max_happy=sum_happy;
            min_shame=sum_shame;
        }
        else if(sum_happy>max_happy)
        {
            st=i;
            max_happy=sum_happy;
            min_shame=sum_shame;
        }
    }
    cout << st << endl;
    return 0;
}

3、值得学习的代码 

// 滑动窗⼝
#include <iostream>

using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

LL n, k;
LL h[N], s[N];

int main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> h[i];
    for(int i = 1; i <= n; i++) cin >> s[i];
 
    LL left = 0, right = 0;
    LL hSum = 0, sSum = 0, hMax = 0, sMin = 0, begin = 0;
 
    while(right <= n)
    {
        hSum += h[right];
        sSum += s[right];
        while(right - left + 1 > k)
        {
            hSum -= h[left];
            sSum -= s[left];
            left++;
        }
        if(right - left + 1 == k)
        {
            if(hSum > hMax)
            {
                begin = left;
                hMax = hSum;
                sMin = sSum;
            }
            else if(hSum == hMax && sSum < sMin)
            {
                begin = left;
                hMax = hSum;
                sMin = sSum;
            }
        }
        right++;
    }
 
    cout << begin << endl;
 
    return 0;
}

三、反思与改进

像这种设计题目背景的,一定要结合用例将题意弄清楚,否则思路很有可能是错的。虽然没有想到前缀和的方法,但想到了滑动窗口。因为数据量的原因,这里得用 long long 来存变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炫酷的伊莉娜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值