hiho字符串

描述

如果一个字符串恰好包含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。

思路

本题是一道比较常见的双指针(或滑动窗口)题目
首先值得注意的是题目要求找到S的子串“恰好”包含2个h、1个i和1个o,不是“至少”包含。
本题的思路就是枚举子串的起点位置L=0, 1, 2, … |S|-1, O(|S|); 然后找到一个最短的,也就是右端点R最小的、使得S[L…R]“至少”包含2个h、1个i和1个o。
然后判断S[L…R]是不是“恰好”包含2个h、1个i和1个o;如果是,我们就找到了一个答案,就用R-L+1更新当前最短的答案。
本题可以用双指针(或滑动窗口),奥妙就在于,当我们要枚举下一个起点L时,即令L=i变成L=i+1时,新的R(i+1)一定在R(i)的右边。
这样R不用从L+1开始计算,总的复杂度就是O(|S|)的了。

代码

#include <stdio.h>
#include <string.h>

#define LEN 100010

int main()
{
        char str[LEN];
        int i,j, minl = LEN;

        scanf("%s", str);

        int l = strlen(str);
        int hn = 0, in = 0, on = 0; // hn > 2 in > 1 on > 1
        for( i = 0, j = 0; i < l; i++)
        {
                if( str[i] != 'h' && str[i] != 'i' && str[i] != 'o' )
                {
                        continue;
                }

                while( j < l && ( hn < 2 || in < 1 || on < 1 ))
                {
                        switch(str[j])
                        {
                                case 'h': hn++; break;
                                case 'i': in++; break;
                                case 'o': on++; break;
                        }
                        j++;
                }

                if( hn == 2 && in == 1 && on == 1 )
                {
                        minl = minl > (j - i) ? j - i : minl;
                        // printf("minl = %d, j = %d, i = %d\n", minl, j, i);
                }

                switch(str[i])
                {
                        case 'h': hn--; break;
                        case 'i': in--; break;
                        case 'o': on--; break;
                }
        }
        if( minl == LEN ) minl = -1;

        printf("%d\n", minl);
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值