【备战秋招】每日一题:2022.11.14-华为机试-最差产品奖

题目描述

假设塔子哥是一家电子产品公司的CEO,他的公司生产了 NNN 个产品。

由于市场竞争激烈,塔子哥决定评选出最差的产品,并对其进行改进。评选的方式是首先对每个产品进行评分,然后根据评分区间计算相邻几个产品中最差的产品。

评选的标准是依次找到从当前产品开始前 MMM 个产品中最差的产品,请给出最差产品的评分序列。

输入描述

第一行,数字 MMM ,表示评分区间的长度,取值范围是 0<M<100000<M<100000<M<10000

第二行,产品的评分序列,比如[12,3,8,6,5],产品数量N范围是 −10000<N<10000-10000 < N <1000010000<N<10000

输出描述

评分区间内最差产品的评分序列

样例

输入1

3
12,3,8,6,5

输出1

3,3,5

输入2

4
12,1,5,3,8,6,5,9,8,6

输出2

1,1,3,3,5,5,5

题目思路

滑动窗口的基础题,思想就是用单调队列维护一个窗口,每次的答案就是队列的第一个

本题单调队列维护的是一个严格单调递增的队列

原理:试想,窗口为M大小在滑动时,每次的答案就是窗口内的最小值,但如果暴力判断的话时间复杂度将会是O(NM)。仔细思考我们可以用发现其实窗口内有些值是不用保存的,例如窗口大小为3,序列为[3, 4, 1, 2, ....],可以看到一开始的窗口覆盖的是[3, 4, 1],我们发现只要有1在,4是不可能再未来成为最差的那一个,3也是同理,因为有比他更差的,并且下标还是比他靠后的,固我们其实只要保存最小值1便可。再往后想,经过一次滑动后窗口覆盖的是[4, 1, 2],同理4是不用保存的,但2是有必要保存的,因为2虽然比1要大,但其下标却靠后,窗口在滑动时1离开了窗口后,2可能便是窗口的最小值,固对于这种情况,2是需要保存下来的,固此时需要保存[1,2]便可。如此分析可以看出单调队列维护的是一个严格单调递减的队列。

具体单调队列的实现是用双端队列,在队头取出当前窗口的最小值,同时如果说当前队头的最小值已经准备离开窗口则需要弹出队列,在队尾负责维护队列是单调的,即在队尾弹出比当前元素要大的值并且插入队伍

为了方便处理,单调队列存放的元素是下标,而不是值

该思路的时间复杂度为O(N)

C++代码

#include <algorithm>
#include <vector>
#include <deque>
#include <cstring>
#include <cstdio>

using namespace std;

int main() {
    int M, val, N = 0;
    scanf("%d\n", &M);
    vector<int> a, ans;
    deque<int> w;
    while (~scanf("%d,", &val)) {
        a.push_back(val);
        N++;
    }
    for (int i = 0; i < N; i++) {
        while (w.size() > 0 && a[w.back()] > a[i]) w.pop_back();
        w.push_back(i);
        if (i - w[0] == M) w.pop_front();
        if (i >= M - 1) ans.push_back(a[w[0]]);
    }
    int flag = 0;
    for (int x : ans) { // 按题目要求输出
        if (flag == 0) flag = 1;
        else printf(",");
        printf("%d", x);
    }
    return 0;
}

Python代码

from collections import deque
M = int(input())
a = list(map(int, input().split(',')))
w = deque([])
ans = []
for i in range(len(a)):
    while len(w) > 0 and a[w[len(w) - 1]] > a[i]:
        w.pop()
    w.append(i)
    if i - w[0] == M:
        w.popleft()
    if i >= M - 1:
        ans.append(a[w[0]])
# 按题目要求输出
flag = False
for x in ans:
    if flag == False:
        flag = not flag
    else:
        print(',', end = '')
    print(x, end = '')

Java代码

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        String s = scanner.next();
        String[] str = s.split(",");
        int N = str.length;
        int[] a = new int[N];
        Deque<Integer> w = new LinkedList<Integer>();
        List<Integer> ans = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            a[i] = Integer.valueOf(str[i]).intValue();
            while (!w.isEmpty() && a[w.getLast()] > a[i]) {
                w.removeLast();
            }
            w.addLast(i);
            if (i - w.getFirst() == M) w.removeFirst();
            if (i >= M - 1) ans.add(a[w.getFirst()]);
        }
        Boolean flag = false; //按题目要求输出
        for (int x : ans) {
            if (flag == false) flag = true;
            else System.out.print(',');
            System.out.print(x);
        }
    }
}

Js代码

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';

process.stdin.on('data', (data) => {
	input += data;
	return;
});
process.stdin.on('end', () => {
    input = input.split('\n')
    let M = input[0]
    let a = input[1].split(',').map(Number)
    let N = a.length
    let ans = []
    let w = []
    for (let i = 0; i < N; i++) {
        while (w.length > 0 && a[w[w.length - 1]] > a[i]) {
            w.pop()
        }
        w.push(i)
        if (i - w[0] == M) w.shift();
        if (i >= M - 1) ans.push(a[w[0]]);
    }
    console(ans) // 自己解决按题意输出
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

塔子哥学算法

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

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

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

打赏作者

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

抵扣说明:

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

余额充值