一道很简单的题

一道很简单的题

​ 今天我刷leetcode时遇到了一道很简单的题

给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。

示例:
输入:[1,12,-5,-6,50,3], k = 4
输出:12.75
解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75

乍一看这道题非常简单,只追求做出来的话刚学一天的学生都能做出来。直接穷举法然后找到最大的平均值,谁都会做好吧,只要用循环把求和写出来再冒泡排序的方法就能做出来。于是我信心满满地提交了如下代码:

class Solution {
public:
    double findMaxAverage(vector<int>& nums, int k) {
int n=nums.size();
double max=0;
for(int i=0;i<k;i++)
{
    max+=nums[i];
}
for(int i=1;i<n-k+1;i++)
{
double m=0;
for(int j=i;j<i+k;j++)
m+=nums[j];
if(m>max)
max=m;
}
return max/k;
    }
};

然后系统提示我超出时间范围了…系统给出的的数组非常吓人

-4227,-8599,-3198,7597,-2658,-6857,-8758,6478,2440,-3582,-1029,7197,6468,-4310,2881,6658,1407,-9934,507,-1628,-7524,-8949,530,8119,-476,-8123,-9095,-3908,8790,-5499,8855,-1625,4037,-4865,-7427,4154,-9334,8772,8952,-3362,1823,-8352,-610,2058,-420,9105,8292,9004,435,3903,8366,-4147876,1491,-7267,1190,-5021,-5353,-9550,6838,-9760,-4345,-3497,-2521,-4559,-8471,-3502,-8654,5716,5771,6419,-6373,-7560,4663,9765,6292,-2268,-8600,7953,-3666,551,5781,7008,-8648,3258,-4408,-6924,-3145,-8352,-5276,-4481,-9793,4964,-3969,5940,9637,-865,6288,8577,4331,9200,-4975,2905,-7405,-7178,-4163,9617,9903,1651,4884,-6594,-8033,9499,-9711,2668,7750,-3994,-4061,2102,5733,-6894,-699,2455,9762,1089,5718,-7485,8815,-4047,-9329,9389,-9389,4942,-7042,-2067,-9932,-9876,-7667,-2799,7978,7436,-8128,1244,-1402,5129,3449,-5385,8556,2832,-743,3107,-3973,554,-2537,-8293,9757,5582,-4101,9420,-6800,134,9993,3923,-9222,3970,3919,3692,9441,-8844,-6153,-5545,8739,-5244,8144,3321,1262,-9097,7801,7442,-4004,-711,-3093,-2728,-4451,9154,-6010,-3486,-8091,8731,9121,8152,2773,355,-4100,267,-9803,170,-8046,4269,3371,-3418,1491,-301,6510,2260,-7395,428,4561,3315,-6521,1541,4165,-808,-7155,-141,-1984,-2288,9133,3333,6629,-9721,1817,-7219,1159,-4293,5819,-1757,9675,-3579,2499,9842,-5255,491,-6327,8866,4836,-3607,-9316,-7395,9204,4833,6538,-7180,-618,-5955,8786,-93,-8664,-6830,-1810,9300,1189,6421,2088,-4653,151,-5899,6742,6420,-5308,-5835,-9268,6772,-407,-5601,-6032,5234,-8406,-4792,-2619,2313,-2970,2960,8656,7527,6372,-1861,-6402,9328,9234,5582,-94,2026,-9236,-1241,2344,7911,-6344,2551,-3536,4211,8680,9145,7852,-7857,-1861,3387,-97,8487,-5101,476,3089,3444,961,2719,-2635,-190,-5266,9660,-7207,3229,6177,8701,2559,-3596,9321,-2402,-8665,2162,-9254,8654,5491,-1604,-8970,1983,913,-593,-2726,-3213,1126,3966,-66,2726,-7,7557,5626,7886,1606,-8905,7208,-2600,-6287,-6037,1997,-1179,-3701,6432,4890,8961,1155,-5021,-4996,9122,-1582,-5252,-3563,4257,8,-8736,-4384,5716,-7627,-5385,-7370,8262,3540,3441,-2236,1866,-9564,2115,1843,-9660,-6254,5213,2685,-4394,5709,3635,-5150,-4680,-3771,8713,4076,8258,-9294,-2044,-2453,6388,4861,-8676,-6840,4154,4359,-9706,5137,9509,1860,5127,8812,-231,19,-9217,-112,5815,-927,-552,6123,-9723,-4767,-5350,4567,-4155,4407,3147,981,-1676,7023,3543,3753,-5539,2608,2250,4120,-649,-5306,4762,-2214,4020,-5052,6988,-4810,-4598,2742,148,-7569,8666,1892,1196,7211,2071,6512,9724,-1884,5153,-7849,4222,324,-8532,4172,4665,863,5689,6348,-1017,1162,7846,-6877,-2011,5211,-4699,-3238,6689,-2521,-520,-6141,9771,3747,6527,8322,5746,-6410,-6194,-5731,-5666,2869,-7375,-828,-9140,-5758,-958,-4214,-3468,-4949,9768,-4232,6856,4645,-1325,-7042,7291,-3871,-6924,-5004,962,9984,1845,-9636,4740,8227,-1467,8660,6916,-8972,-9137,-6474,54,-1321,-325,-4567,-2814,-455,2120,-2086,-2823,-2384,-5208,-3252,1045,3424,-2939,526,-5…more chars…

这里截取的不到给的数组的二十分之一

我仔细一想,确实时时间复杂度太高了,竟达到了O((n-k)*k),然后我就想如何优化代码。

在穷举之中,每次移动求和开头时,中间部分的数字是保持不变的,只有开头和结尾处会后移一个单位。而如果我再重新求和的话必然利用不上重合的部分,相当于做了许多无用功。因此我可以直接让原来的和减去原开头加上新结尾,这样操作就简单多了。改写后代码如下:

class Solution {
public:
    double findMaxAverage(vector<int>& nums, int k) {
int n=nums.size();
double max=0;
for(int i=0;i<k;i++)
{
    max+=nums[i];
}
double t=max;
for(int i=1;i<n-k+1;i++)
{
double m=t-nums[i-1]+nums[i-1+k];
t=m;
if(m>max)
max=m;
}
return max/k;
    }
};

这次运行就快多了,执行时间击败了百分之八十多的用户(虽然我觉得还是有点慢)。

说实话,这道题虽然简单,即使优化算法我也一下子就想出来了,但它给了我一个启示。写程序不要仅限于正确就行,还要更快地正确。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值