文章目录
- 相关推荐阅读
- 题目描述与示例
- 题目描述
- 输入描述
- 输出描述
- 示例
- 输入
- 输出
- 解题思路
- 滑窗三问
- 滑窗三答
- 代码
- Python
- Java
- C++
- C
- Node JavaScript
- Go
- 时空复杂度
- 华为OD算法/大厂面试高频题算法练习冲刺训练
相关推荐阅读
- 【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
- 【华为OD机考】2025C+2025B+2024E+D卷真题【完全原创题解 | 详细考点分类 | 不断更新题目】
- 【华为OD笔试】双机位A+2025C+2025B+2024E+D卷真题机考套题汇总【真实反馈,不断更新,限时免费】
- 【华为OD笔试】2024E+D卷命题规律解读【分析500+场OD笔试考点总结】
- 【华为OD流程】性格测试选项+注意事项】
题目练习网址:【固定滑窗】双机位A-字符串计数匹配
题目描述与示例
题目描述
给你一个字符串str和整数k,返回满足以下条件的所有子字符串个数:
- 恰好包含
k个字母。 - 数字
0-9各出现至少一次。
输入描述
- 第一行字符串
str (1 ≤ length ≤ 100000),仅包含数字和小写字母 - 第二行为整数
k (0 ≤ k ≤100000 )
输出描述
输出一个整数,表示满足所有条件的子字符串的个数。
示例
输入
a0123456789aa 1输出
2解题思路
由于符合要求的子串必然包含10个数字(0-9恰好各自出现一次)和k个字母,且原字符串s仅包含数字和小写字母(不包含其他特殊字符),因此符合要求的子串的长度必然为k+10。
因此,我们可以构建一个长度为win_len = k+10的窗口,通过固定滑窗过程来解决该问题。
为了判断子串中数字是否都恰好出现一次,我们可以构建一个长度为10的列表cnt_num_win,来储存窗口中出现的数字个数。其中cnt_num_win[i]就表示数字i在窗口中出现的次数。
考虑滑动窗口三问三答
滑窗三问
Q1:对于每一个右指针right所指的元素ch,做什么操作?
Q2:什么时候要令左指针left右移?对于left所指的元素left_ch,要做什么操作?
Q3:什么时候进行ans的更新?如何更新?
滑窗三答
A1:如果ch是数字,则更新cnt_num_win[ch] += 1,表示ch在窗口中出现的次数增加1。
A2:移除窗口的left = right - win_len。如果ch_left是数字,则更新cnt_num_win[ch_left] -= 1,表示ch_left在窗口中出现的次数减少1。
A3:如果cnt_num_win中的所有元素均为1,则说明0-9这10个数字,在窗口中出现的次数恰好均为1,更新答案。
当ch或ch_left为字母时,无需做任何操作。
代码
Python
# 题目:【固定滑窗】双机位A-字符串计数匹配# 分值:100# 作者:闭着眼睛学数理化# 算法:固定滑窗# 代码看不懂的地方,请直接在群上提问# 用于检查长度为10的列表cnt中所有元素是否为1的函数# 如果cnt中所有元素都为1,则返回1,否则返回0defcheck(cnt):returnint(all(num==1fornumincnt))# 输入原字符串s=input()# 输入k值k=int(input())# 固定滑窗的窗口长度为k+10win_len=k+10# 构建长度为10的列表,用来记录窗口中的数字个数# cnt[i]就表示数字i的出现次数cnt=[0]*10# 初始化第一个窗口的情况forchins[:win_len]:# 如果ch是数字ifch.isdigit():# 则令ch在cnt中的计数+1cnt[int(ch)]+=1# 初始化答案变量# 如果第一个窗口中,0-9这些数字出现次数均为1,则初始化ans为1# 否则初始化为0ans=check(cnt)# 固定滑窗过程forright,chinenumerate(s[win_len:],win_len):# A1ifch.isdigit():cnt[int(ch)]+=1# A2left=right-win_len ch_left=s[left]ifch_left.isdigit():cnt[int(ch_left)]-=1# A3ans+=check(cnt)print(ans)Java
importjava.util.*;publicclassMain{// 用于检查长度为10的数组 cnt 中所有元素是否为1的函数// 如果 cnt 中所有元素都为1,则返回1,否则返回0publicstaticintcheck(int[]cnt){for(intnum:cnt){if(num!=1)return0;}return1;}publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);// 输入原字符串Strings=sc.nextLine();// 输入 k 值intk=sc.nextInt();// 固定滑窗的窗口长度为 k+10intwinLen=k+10;// 构建长度为10的数组,用来记录窗口中的数字个数// cnt[i] 就表示数字 i 的出现次数int[]cnt=newint[10];// 初始化第一个窗口的情况for(inti=0;i<Math.min(winLen,s.length());i++){charch=s.charAt(i);// 如果 ch 是数字if(Character.isDigit(ch)){cnt[ch-'0']++;}}// 初始化答案变量// 如果第一个窗口中,0-9这些数字出现次数均为1,则初始化ans为1,否则初始化为0intans=check(cnt);// 固定滑窗过程for(intright=winLen;right<s.length();right++){charch=s.charAt(right);// A1if(Character.isDigit(ch)){cnt[ch-'0']++;}// A2intleft=right-winLen;charchLeft=s.charAt(left);if(Character.isDigit(chLeft)){cnt[chLeft-'0']--;}// A3ans+=check(cnt);}System.out.println(ans);}}C++
#include<iostream>#include<string>#include<vector>usingnamespacestd;// 用于检查长度为10的数组 cnt 中所有元素是否为1的函数// 如果 cnt 中所有元素都为1,则返回1,否则返回0intcheck(constvector<int>&cnt){for(intnum:cnt){if(num!=1)return0;}return1;}intmain(){string s;getline(cin,s);// 输入原字符串intk;cin>>k;// 输入 k 值// 固定滑窗的窗口长度为 k+10intwin_len=k+10;// 构建长度为10的数组,用来记录窗口中的数字个数vector<int>cnt(10,0);// 初始化第一个窗口的情况for(inti=0;i<min(win_len,(int)s.size());i++){charch=s[i];// 如果 ch 是数字if(isdigit(ch)){cnt[ch-'0']++;}}// 初始化答案变量// 如果第一个窗口中,0-9这些数字出现次数均为1,则初始化ans为1,否则初始化为0intans=check(cnt);// 固定滑窗过程for(intright=win_len;right<(int)s.size();right++){charch=s[right];// A1if(isdigit(ch)){cnt[ch-'0']++;}// A2intleft=right-win_len;charch_left=s[left];if(isdigit(ch_left)){cnt[ch_left-'0']--;}// A3ans+=check(cnt);}cout<<ans<<endl;return0;}C
#include<stdio.h>#include<string.h>#include<ctype.h>// 用于检查长度为10的数组 cnt 中所有元素是否为1的函数// 如果 cnt 中所有元素都为1,则返回1,否则返回0intcheck(intcnt[10]){for(inti=0;i<10;i++){if(cnt[i]!=1)return0;}return1;}intmain(){chars[100005];// 输入原字符串fgets(s,sizeof(s),stdin);s[strcspn(s,"\n")]='\0';// 去除换行符intk;// 输入 k 值scanf("%d",&k);// 固定滑窗的窗口长度为 k+10intwin_len=k+10;// 构建长度为10的数组,用来记录窗口中的数字个数intcnt[10]={0};intn=strlen(s);// 初始化第一个窗口的情况for(inti=0;i<win_len&&i<n;i++){charch=s[i];// 如果 ch 是数字if(isdigit(ch)){cnt[ch-'0']++;}}// 初始化答案变量// 如果第一个窗口中,0-9这些数字出现次数均为1,则初始化ans为1,否则初始化为0intans=check(cnt);// 固定滑窗过程for(intright=win_len;right<n;right++){charch=s[right];// A1if(isdigit(ch)){cnt[ch-'0']++;}// A2intleft=right-win_len;charch_left=s[left];if(isdigit(ch_left)){cnt[ch_left-'0']--;}// A3ans+=check(cnt);}printf("%d\n",ans);return0;}Node JavaScript
// Node.js 固定滑窗实现 - 字符串计数匹配constreadline=require("readline");constrl=readline.createInterface({input:process.stdin,output:process.stdout});letinputLines=[];rl.on("line",line=>inputLines.push(line.trim())).on("close",()=>{consts=inputLines[0];// 输入原字符串constk=parseInt(inputLines[1]);// 输入 k 值console.log(solve(s,k));});// 检查长度为10的数组 cnt 中所有元素是否为1的函数functioncheck(cnt){for(letnumofcnt){if(num!==1)return0;}return1;}functionsolve(s,k){// 固定滑窗的窗口长度为 k+10constwinLen=k+10;// 构建长度为10的数组,用来记录窗口中的数字个数constcnt=Array(10).fill(0);// 初始化第一个窗口的情况for(leti=0;i<Math.min(winLen,s.length);i++){constch=s[i];// 如果 ch 是数字if(/\d/.test(ch)){cnt[parseInt(ch)]++;}}// 初始化答案变量// 如果第一个窗口中,0-9这些数字出现次数均为1,则初始化ans为1,否则初始化为0letans=check(cnt);// 固定滑窗过程for(letright=winLen;right<s.length;right++){constch=s[right];// A1if(/\d/.test(ch)){cnt[parseInt(ch)]++;}// A2constleft=right-winLen;constchLeft=s[left];if(/\d/.test(chLeft)){cnt[parseInt(chLeft)]--;}// A3ans+=check(cnt);}returnans;}Go
packagemainimport("bufio""fmt""os""strconv""strings")// 用于检查长度为10的数组 cnt 中所有元素是否为1的函数// 如果 cnt 中所有元素都为1,则返回1,否则返回0funccheck(cnt[10]int)int{for_,num:=rangecnt{ifnum!=1{return0}}return1}funcmain(){in:=bufio.NewScanner(os.Stdin)in.Buffer(make([]byte,0,1024),1<<20)// 放大缓冲,防止长行被截断// 输入原字符串if!in.Scan(){return}s:=strings.TrimSpace(in.Text())// 输入 k 值if!in.Scan(){return}kStr:=strings.TrimSpace(in.Text())k,_:=strconv.Atoi(kStr)// 固定滑窗的窗口长度为 k+10winLen:=k+10// 构建长度为10的数组,用来记录窗口中的数字个数varcnt[10]intn:=len(s)// 初始化第一个窗口的情况limit:=winLeniflimit>n{limit=n}fori:=0;i<limit;i++{ch:=s[i]// 如果 ch 是数字ifch>='0'&&ch<='9'{cnt[ch-'0']++}}// 初始化答案变量// 如果第一个窗口中,0-9这些数字出现次数均为1,则初始化ans为1,否则初始化为0ans:=check(cnt)// 固定滑窗过程forright:=winLen;right<n;right++{// A1ch:=s[right]ifch>='0'&&ch<='9'{cnt[ch-'0']++}// A2left:=right-winLen chLeft:=s[left]ifchLeft>='0'&&chLeft<='9'{cnt[chLeft-'0']--}// A3ans+=check(cnt)}fmt.Println(ans)}时空复杂度
时间复杂度:O(n)。仅需一次遍历原字符串
空间复杂度:O(1)。仅需长度为10的列表cnt来维护固定滑窗过程,可视为常数空间复杂度。
华为OD算法/大厂面试高频题算法练习冲刺训练
华子OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务1000+同学成功上岸!
课程讲师为全网200w+粉丝编程博主@吴师兄学算法以及小红书头部编程博主@闭着眼睛学数理化
90+天陪伴式学习,100+直播课时,300+动画图解视频,500+LeetCode经典题,500+华为OD真题/大厂真题,还有简历修改、模拟面试、陪伴小群、资深HR对接将为你解锁