【固定滑窗】2023A-找出通过车辆最多颜色
【固定滑窗】2023A-找出通过车辆最多颜色
题目描述与示例
本题练习地址:https://www.algomooc.com/problem/P3251
题目
在一个狭小的路口,每秒只能通过一辆车,假如车辆的颜色只有 3
种,找出 N
秒内经过的最多颜色的车辆数量,三种颜色编号为 0, 1, 2
。
输入
第一行输入的是通过的车辆颜色信息。比如[0, 1, 1, 2]
代表 4
秒钟通过的车辆颜色分别是 0, 1, 1, 2
第二行输入的是统计时间窗,整型,单位为秒。
输出
输出指定时间窗内经过的最多颜色的车辆数量
示例一
输入
0 1 2 1
3
输出
2
说明
在[1,2,1]
这个 3
秒时间窗内,1
这个颜色出现 2
次,数量最多
示例二
输入
0 1 2 1
2
输出
1
说明
在 2
秒时间窗内,每个颜色最多出现 1
次
解题思路
本题明确地指出,时间窗口的长度为N
,所以考虑使用固定滑窗来解决问题。
由于在滑窗内需要统计各种颜色车辆的数目,所以我们可以用哈希表来统计元素频率。特别地,由于题目告诉我们车辆颜色有且只有 0, 1, 2
三种,所以我们可以更加简单地用一个列表 windows_colors
来代替哈希表。
对于固定滑窗,我们需要考虑滑窗和答案的初始化。我们需要以第一个窗口,即colors[0:N]
这个窗口的情况来初始化windows_colors = [0, 0, 0]
。然后遍历colors[0:N]
中的颜色,将其统计在windows_colors
中。而答案变量ans的初始化,即为为第一个固定滑窗中的最大值。
然后我们思考滑窗三问三答。
滑窗三问
**Q1:**对于每一个右指针right
所指的元素right_color
,做什么操作?
**Q2:**什么时候要令左指针left
右移?对于left
所指的元素left_color
,要做什么操作?
**Q3:**什么时候进行ans
的更新?如何更新?
滑窗三答
**A1:**将right_color
在windows_colors
中的统计次数+1
**A2:**在固定滑窗中,left
始终为right-N
,同时需要将left_color
在windows_colors
中的统计次数-1
**A3:**做完windows_colors
的更新后,取其中最大值和当前ans
比较并更新。
代码
Python
# 题目:2023A-找出通过车辆最多颜色
# 分值:100
# 作者:闭着眼睛学数理化
# 算法:固定滑窗
# 代码看不懂的地方,请直接在群上提问
colors = list(map(int, input().split()))
N = int(input())
# 初始化统计时间窗口内各种颜色出现的次数的列表
# windows_colors[i]表示颜色为i的车辆的个数
windows_colors = [0, 0, 0]
# 初始化固定滑窗中的颜色数目
for color in colors[:N]:
windows_colors[color] += 1
# 初始化答案变量,为第一个固定滑窗中的最大值
ans = max(windows_colors)
for right, right_color in enumerate(colors[N:], N):
# Q1:对于每一个右指针right所指的元素right_color,做什么操作?
# A1:将right_color在窗口中的统计次数+1
windows_colors[right_color] += 1
# Q2:什么时候要令左指针left右移?
# 对于left所指的元素left_color,要做什么操作?
# A2:在固定滑窗中,left始终为right-N
# 将left_color在窗口中的统计次数-1
left = right - N
left_color = colors[left]
windows_colors[left_color] -= 1
# A3:什么时候进行ans的更新?
# Q3:做完windows_colors的更新后,取其中最大值和当前ans比较并更新
ans = max(ans, max(windows_colors))
print(ans)
Java
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
String[] str = s.nextLine().split(" ");
int n = s.nextInt();
int[] arr = new int[3];
int max = 0;
int cur = 0;
if(n > str.length){
n = str.length;
}
for(int i = 0;i < n;i++){
int num = str[i].charAt(0)-'0';
arr[num]++;
}
cur = Math.max(Math.max(arr[0],arr[1]),arr[2]);
max = Math.max(max,cur);
for(int right = n;right < str.length;right++){
int num = str[right].charAt(0)-'0';
arr[num]++;
int left = str[right-n].charAt(0)-'0';
arr[left]--;
max = Math.max(max,arr[num]);
}
System.out.println(max);
}
}
C++
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
string line;
getline(cin, line);
istringstream iss(line);
vector<int> colors;
int color;
while (iss >> color) {
colors.push_back(color);
}
int n;
cin >> n;
int arr[3] = {0, 0, 0};
int ans = 0;
int cur = 0;
if (n > colors.size()) {
n = colors.size();
}
for (int i = 0; i < n; i++) {
int num = colors[i];
arr[num]++;
}
cur = max(arr[0], max(arr[1], arr[2]));
ans = max(ans, cur);
for (int right = n; right < colors.size(); right++) {
int num = colors[right];
arr[num]++;
int leftNum = colors[right - n];
arr[leftNum]--;
ans = max(ans, arr[num]);
}
cout << ans << endl;
return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
// 返回三个整数中的最大值
int maxOf(int a, int b, int c) {
int maxVal = a;
if (b > maxVal) {
maxVal = b;
}
if (c > maxVal) {
maxVal = c;
}
return maxVal;
}
int main() {
int colors[10000]; // 假设颜色数组不会超过 10000 个元素
int N, length = 0;
// 读取颜色数组,直到遇到换行符
while (scanf("%d", &colors[length]) == 1) {
length++;
if (getchar() == '\n') {
break;
}
}
// 读取窗口长度 N
scanf("%d", &N);
// 如果窗口长度 N 大于数组长度,则调整 N 为数组长度
if (N > length) {
N = length;
}
// 初始化统计时间窗口内各种颜色出现的次数的数组
// windowsColors[i] 表示颜色 i 的车辆数量
int windowsColors[3] = {0, 0, 0};
// 初始化第一个固定滑窗中的颜色数量
for (int i = 0; i < N; i++) {
windowsColors[colors[i]]++;
}
// 初始化答案变量,设为第一个固定滑窗中的最大值
int ans = maxOf(windowsColors[0], windowsColors[1], windowsColors[2]);
// 滑动窗口
for (int right = N; right < length; right++) {
int rightColor = colors[right];
windowsColors[rightColor]++;
// 左边界为 right - N,移除左边界的颜色
int leftColor = colors[right - N];
windowsColors[leftColor]--;
// 更新答案变量,取当前滑窗中的最大颜色数量
int currentMax = maxOf(windowsColors[0], windowsColors[1], windowsColors[2]);
if (currentMax > ans) {
ans = currentMax;
}
}
// 输出最终答案
printf("%d\n", ans);
return 0;
}
Node JavaScript
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let colors = [];
let N = 0;
rl.on('line', (input) => {
if (!colors.length) {
colors = input.split(' ').map(Number);
} else {
N = parseInt(input);
rl.close();
}
});
rl.on('close', () => {
console.log(maxColorsInWindow(colors, N));
});
function maxColorsInWindow(colors, N) {
// 处理特殊情况,当数组长度小于窗口长度时,调整N为数组长度
if (N > colors.length) {
N = colors.length;
}
// 初始化窗口中各种颜色的计数
const windowsColors = [0, 0, 0];
// 初始化固定滑窗中的颜色数量
for (let i = 0; i < N; i++) {
windowsColors[colors[i]] += 1;
}
// 初始答案变量,设为第一个滑窗中的最大值
let ans = Math.max(...windowsColors);
// 固定滑窗的滑动过程
for (let right = N; right < colors.length; right++) {
let rightColor = colors[right];
windowsColors[rightColor] += 1;
let left = right - N;
let leftColor = colors[left];
windowsColors[leftColor] -= 1;
// 更新最大值
ans = Math.max(ans, Math.max(...windowsColors));
}
return ans;
}
Go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
// 返回两个或三个整数的最大值
func maxOf(a, b int, others ...int) int {
maxVal := a
if b > maxVal {
maxVal = b
}
for _, val := range others {
if val > maxVal {
maxVal = val
}
}
return maxVal
}
func main() {
reader := bufio.NewReader(os.Stdin)
// 读取颜色数组
colorsInput, _ := reader.ReadString('\n')
colorsStr := strings.Fields(colorsInput)
var colors []int
for _, val := range colorsStr {
num, _ := strconv.Atoi(val)
colors = append(colors, num)
}
// 读取窗口长度
nInput, _ := reader.ReadString('\n')
N, _ := strconv.Atoi(strings.TrimSpace(nInput))
// 如果窗口长度大于颜色数组的长度,调整窗口大小为数组长度
if N > len(colors) {
N = len(colors)
}
// 初始化统计时间窗口内各种颜色出现的次数的列表
windowsColors := [3]int{}
// 初始化第一个固定滑窗中的颜色数目
for i := 0; i < N; i++ {
windowsColors[colors[i]]++
}
// 初始化答案变量,为第一个固定滑窗中的最大值
ans := maxOf(windowsColors[0], windowsColors[1], windowsColors[2])
// 开始滑动窗口
for right := N; right < len(colors); right++ {
// 将右边界的颜色加入窗口
rightColor := colors[right]
windowsColors[rightColor]++
// 左边界为right - N,将左边界的颜色移出窗口
left := right - N
leftColor := colors[left]
windowsColors[leftColor]--
// 更新答案变量,取窗口内最大值和当前答案的较大值
ans = maxOf(ans, windowsColors[0], windowsColors[1], windowsColors[2])
}
// 输出最终答案
fmt.Println(ans)
}
时空复杂度
时间复杂度:O(M)
。仅需一次遍历数组,M
为数组长度。
空间复杂度:O(1)
。列表的长度为3
,为常数级别空间。