为了更好的阅读体检,可以查看我的算法学习网站
在线评测链接:P1103
题目内容
塔子哥是一个大学生,他喜欢研究各种关于字符串的问题。有一天,他在研究字符串问题时想到了这个问题。
这道题目给定一个长度为 n n n ( n ≤ 1 0 5 n\le 10^5 n≤105 )的、由数字字符组成的字符串,你可以进行如下操作: 选择一个字符,使得其加 1 1 1 或者减 1 1 1 。
请注意,你无法对’ 0 0 0’进行减 1 1 1 操作,也无法对’ 9 9 9’进行加 1 1 1 操作。
若干次操作后,你需要使得该字符串存在一个长度为 k k k ( 1 ≤ k ≤ n 1\le k\le n 1≤k≤n )的、所有字符都相同的连续子串。请你计算出操作的最小次数。
输入
3 2
1 2 3
输出
1
思路
枚举 + 滑动窗口
很容易想到暴力枚举的方法。先枚举最终这段连续相同的数字是什么,再去枚举每个长度为 k k k的子段。然后再去计算答案。这样复杂度是 O ( 10 n 2 ) O(10n^2) O(10n2)的。
我们发现每个子段的答案可以使用滑动窗口的方法动态维护。即往右移动一格就把出去的值给减去,然后再加上就行。复杂度 O ( 10 n ) O(10n) O(10n)
类似题目推荐
LeetCode
面试题 17.24. 最大子矩阵 - 同样也是暴力的思路
剑指 Offer 48. 最长不含重复字符的子字符串 - 滑动窗口
209. 长度最小的子数组 -滑动窗口
CodeFun2000
P1290 2023.05.11-华为odA卷-第一题-冗余覆盖 -非常推荐,和本题十分十分类似,也是枚举+滑动窗口
P1175 2023.04.08–华为od-第二题-新学校选址 - 暴力枚举
P1088 2023.3.18.10点-美团春招-第二题-k彩色区间 -滑动窗口
P1001 华为od-k优雅阈值 -滑动窗口
P1119 2023.03.26-第三题-数组之和最小值 - 滑动窗口套数论
代码
CPP
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int INT_MAX = 1e9;
int main() {
int n, k;
scanf("%d %d", &n, &k);
int arr[n];
for(int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int res = INT_MAX;
int times[n];
int sum[n + 1];
// 枚举这一段最后变成什么 , [0 , 9]
for(int i = 0; i <= 9; i++) {
// 先求前k个
for(int j = 0; j < n; j++) {
times[j] = abs(arr[j] - i);
}
// 模拟滑动窗口
int curMin = INT_MAX;
for(int m = 1; m <= n; m++) {
sum[m] = sum[m - 1] + times[m - 1];
if(m >= k) curMin = min(curMin, sum[m] - sum[m - k]);
}
// 更新答案
res = min(curMin, res);
}
printf("%d", res);
return 0;
}
python
n , k = list(map(int , input().split()))
a = list(map(int , input().split()))
ans = 10000000000
# 枚举最后变成什么
for d in range (10):
cost = 0
# 先求前k个
for i in range (k):
cost += abs(a[i] - d)
ans = min (ans , cost)
# 滑动窗口
for i in range (k , n):
cost += abs(a[i] - d)
cost -= abs(a[i - k] - d)
ans = min (ans , cost)
print (ans)
Java
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++){
arr[i] = sc.nextInt();
}
int res = Integer.MAX_VALUE;
int[] times = new int[n];
int[] sum = new int[n + 1];
// 枚举这一段最后变成什么 , [0 , 9]
for(int i = 0; i <= 9; i++){
// 先求前k个
for(int j = 0; j < n; j++){
times[j] = Math.abs(arr[j] - i);
}
// 模拟滑动窗口
int curMin = Integer.MAX_VALUE;
for(int m = 1; m <= n; m++){
sum[m] = sum[m - 1] + times[m - 1];
if(m >= k) curMin = Math.min(curMin, sum[m] - sum[m - k]);
}
// 更新答案
res = Math.min(curMin, res);
}
System.out.println(res);
}
}
Go
package main
import(
"fmt"
)
func main(){
var n int
var k int
fmt.Scanln(&n, &k)
arr := make([]int, n)
for i := range arr{
fmt.Scanf("%d", &arr[i])
}
ans := getResult(n , k , arr)
fmt.Println(ans)
}
func getResult(n , k int, arr []int) int {
ans := 1000000000
// 枚举这一段最后变成什么 , [0 , 9]
for num := 0 ; num <= 9 ; num++{
tmp := 0
// 先求前k个
for i := 0 ; i < k ; i++{
tmp += abs((arr[i] - num))
}
ans = min(ans, tmp)
// 模拟滑动窗口
for i := k ; i < n ; i++{
tmp -= abs((arr[i - k] - num))
tmp += abs((arr[i] - num))
// 更新答案
ans = min(ans, tmp)
}
}
return ans
}
func min(a , b int) int{
if a > b {
return b
}
return a
}
func abs(a int) int{
if a < 0{
return -a
}
return a
}
Js
process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
input += data;
return;
});
process.stdin.on('end', () => {
const lines = input.trim().split('\n');
const [n, k] = lines[0].trim().split(' ').map(x => parseInt(x));
const a = lines[1].trim().split(' ').map(x => parseInt(x));
let ans = 10000000000;
// 枚举最后变成什么
for (let d = 0; d <= 9; d++) {
let cost = 0;
// 先求前k个
for (let i = 0; i < k; i++) {
cost += Math.abs(a[i] - d);
}
ans = Math.min(ans, cost);
// 滑动窗口
for (let i = k; i < n; i++) {
cost += Math.abs(a[i] - d);
cost -= Math.abs(a[i - k] - d);
ans = Math.min(ans, cost);
}
}
console.log(ans);
});
题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。