题目描述: 有一套系统需要升级,为了减小系统升级期间的影响,需根据系统过去几周内的平均每小时的访问数据,来预测最佳升级时间窗,时间窗的选择规则如下:
1、升级时间窗内累计用户访问量必须小于等于给定的容忍值
2、升级时间窗必须是连续的X个小时,越大越好,最大的X即为最佳升级时间窗,且不超过7*24
3、升级时间窗允许跨周期
现给定升级影响的容忍值,和一个周期(7*24)的每小时用户访问量的历史数据(整数数组),请计算最佳升级时间窗,并返回其开始时间和结束时间的下标,如果存在多个最佳升级时间窗时,返回开始时间下标最小的一个
输入:
第一行为整数n,表示给定的升级影响的容忍值,取值范围:[0,2^31)
第二行为724个整数,表示一个周期(724)的每个小时用户访问量,每个值的取值范围:[0,2^31)
输出:
两个整数,分别表示所计算出的最佳升级时间窗的开始时间下标(包含)和结束时间下标(包含),不存在时返回-1,-1
样例1:
6
1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 11 12 12 11 10 9 8 7 6 5 4 3 2 1
输出:
22 25
最佳升级窗口为:2 1 1 2
样例2:
167
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 167 1
输出:
167 165
样例3:
200
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
输出:
0 167
题解:
① C++滑动窗口:
思路:
1、sum记录窗口内数据的和,当sum小于等于n时,窗口右边界向右移动;
2、当sum大于n时,窗口左边界向左移动,且sum 需要减去左边界的值。
3、满足要求的窗口被记录在ans数组中,且后面只记录笔前面出现窗口周期长的记录。
4、当 sum小于n值,且 r - l 大于等于整个周期长度时,说明整个周期都满足升级要求。
5、r取余是因为可以跨周期,如样例2.
#include <iostream>
#include <vector>
using namespace std;
const int ARR_LEN (7*24);
class Solution {
public:
vector<int> getBestTime(int n, vector<int> arr) {
int l = 0;
int r = 0;
int sum = arr[l];
int maxLen = -1;
vector<int> ans{-1,-1};
int size = arr.size();
for(; l < size; l++) {
while(sum <= n) {
if(r - l > maxLen) {
maxLen = r - l;
ans.push_back(l);
ans.push_back(r % size);
}
r++;
sum += arr[r % size];
if(r - l >= 168) {
sum -= arr[l];
break;
}
}
sum -= arr[l];
}
return ans;
}
};
int main()
{
int count;
cin >> count;
vector<int> arr(ARR_LEN);
for(int i = 0; i < ARR_LEN; i++) {
cin >> arr[i];
}
Solution solu;
vector<int> result = solu.getBestTime(count, arr);
cout << result[result.size() - 2] << " " << result[result.size() - 1] << endl;
}
② python 前缀和
1、将数组复制一份至两倍长度
2、求出新的数组的前缀和放到presum中
3、presum[j] - presum[i] 则表示数组下标[i, j -1]窗口的和。如果和满足要求,则记录当前窗口下标,同时记录当前窗口长度
4、对所有满足要求的窗口,以窗口长度为第一优先级,左下标为第二优先级排序。
5、第一个数据则是最佳数据。
#!/usr/bin/env python
# coding=utf-8
class Solution :
def get_best_time(self, n, arr):
new_arr = arr * 2;
windows = [];
ans = []
presum = [_ for _ in range(len(new_arr) + 1)]
presum[0] = 0
for i in range(1, len(new_arr) + 1):
presum[i] = presum[i -1] + new_arr[ i - 1 ]
for i in range(len(new_arr)):
for j in range(i+1, len(new_arr) + 1):
if presum[j] - presum[i] <= n:
windows.append([j-i, i, j -1])
if j - i >= 168:
return [i,j-1]
if not windows:
return [-1,-1]
windows.sort(key = lambda x: (x[0], -x[1]), reverse = True);
ans = [windows[0][1] % 168, windows[0][2] % 168]
return ans
if __name__ == "__main__":
n = int(input().strip())
arr = list(map(int, input().strip().split()))
function = Solution()
result = function.get_best_time(n, arr);
print(str.join(' ', map(str, result)))