1. 问题描述:
如果一个字符串恰好包含2个'h'、1个'i'和1个'o',我们就称这个字符串是hiho字符串。
例如"oihateher"、"hugeinputhugeoutput"都是hiho字符串。
现在给定一个只包含小写字母的字符串S,小Hi想知道S的所有子串中,最短的hiho字符串是哪个。
输入
字符串S
对于80%的数据,S的长度不超过1000
对于100%的数据,S的长度不超过100000
输出
找到S的所有子串中,最短的hiho字符串是哪个,输出该子串的长度。如果S的子串中没有hiho字符串,输出-1。
样例输入
happyhahaiohell
样例输出
5
2. 与最短摘要不同的是,hiho规定了hiho字符串的规则,但是思路与最短摘要的思路相同,都可以使用尺取法来解决
只不过这次的扫描的是字符串,最短摘要扫描的是单词,但是本质上是一样的
这里需要注意题目有一个坑就是恰好为2个h,1个i和1和o
代码如下:
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int res = solve(s);
System.out.println(res);
}
private static int solve(String s) {
char a[] = s.toCharArray();
int j = 0;
int len = Integer.MAX_VALUE;
int begin = 0;
int end = -1;
for(int i = 0;i<s.length();i++){
char c = a[i];
if(!check(c))continue;
if(j==0)j=i+1;
//判断还有更短的hiho字符串吗,但是后来想想假如更新len之后那么表示i到j就是hiho字符串不可能包括多于的字符
if(j-i+1>=4&&j<a.length&&containAll(a,i,j)){
if(check(a,i,j)&&j-i+1<len){
len = j - i + 1;
begin = i;
end = j;
}
}
while(j<a.length){
c = a[j];
if(!check(c)){
j++;
continue;
}
if(containAll(a,i,j)){
if(check(a,i,j)&&j-i+1<len){
len = j - i + 1;
begin = i;
end = j;
}
break;
}
//不满足也要继续扫描
j++;
}
}
//print(a,begin,end);
return len==Integer.MAX_VALUE?-1:len;
}
private static void print(char[] a, int begin, int end) {
System.out.print(begin+" "+end);
for(int i = begin;i<=end;i++){
System.out.print(a[i]);
}
}
private static boolean check(char[] a, int i, int j) {
//题目规定是恰好2个h 1个i 1个o
int c1 = 0,c2 = 0,c3 = 0;
for(int k = i;k<=j;k++){
if(a[k]=='h')c1++;
if(a[k]=='i')c2++;
if(a[k]=='o')c3++;
}
return c1==2&&c2==1&&c3==1;
}
private static boolean containAll(char[] a, int i, int j) {
int c1 = 0,c2 = 0,c3 = 0;
for(int k = i;k<=j;k++){
if(a[k]=='h')c1++;
if(a[k]=='i')c2++;
if(a[k]=='o')c3++;
}
return c1>=2&&c2>=1&&c3>=1;
}
private static boolean check(char c) {
return c=='h'||c=='i'||c=='o';
}
}