【LeetCode-3306】【周赛417第3题】

题目链接

1. 题目要求

  1. 字符串每个元音字母至少出现一次
  2. 恰好包含k个辅音字母

2. 解决方案

  1. 考虑滑动窗口
  2. 窗口内始终保证
    • 每个元音字母至少出现1
    • 辅音字母出现k
  3. 每个字母记录左测离自己最近的辅音字母的索引 ( 不包括当前字母 )
    • 假设为 nearestConsonant[]
  4. 当窗口满足以上条件时, 如何累加ans?
    • 设窗口最左测的字母索引为 left
    • ans += left - nearestConsonant[left]
  5. 考虑窗口的各种情况
    • 窗口刚好满足情况 — 累加ans
    • 缺少元音字母 —
    • 可以减少元音字母 —
    • 辅音字母小于k —
    • 辅音字母大于k —

3. 代码实现

    public static long countOfSubstrings(String word, int k) {

        int N = word.length();

        boolean[] meta = new boolean[32];
        meta['a' - 'a'] = true;
        meta['e' - 'a'] = true;
        meta['i' - 'a'] = true;
        meta['o' - 'a'] = true;
        meta['u' - 'a'] = true;

        int[] nearestConsonant = new int[N];

        int nearest = -1;

        for (int i = 0; i < N; i++) {

            nearestConsonant[i] = nearest;

            if (!meta[word.charAt(i) - 'a'])
                nearest = i;
        }

        int left = 0;

        int right = 0;

        int[] window = new int[32];

        long ans = 0;

        while (right < N) {

            int index = word.charAt(right) - 'a';

            window[index]++;

            int m;

            while (direction(window, meta, k, left, word) < 0) {

                int leftIndex = word.charAt(left) - 'a';

                window[leftIndex]--;

                left++;

            }

            if (direction(window, meta, k, left, word) == 0) {

                ans += left - nearestConsonant[left];

            }

            right++;

        }

        return ans;
    }

    // 左  = -1
    // 右  = 1
    // ok  = 0
    public static int direction(
            int[] window,
            boolean[] meta,
            int k,
            int left,
            String word
    ) {

        int ac = window['a' - 'a'];
        int ec = window['e' - 'a'];
        int ic = window['i' - 'a'];
        int oc = window['o' - 'a'];
        int uc = window['u' - 'a'];

        int sum = 0;

        for (int w : window)
            sum += w;

        if (ac == 0 || ec == 0 || ic == 0 || oc == 0 || uc == 0)
            return 1;

        int consonant = sum - ac - ec - ic - oc - uc;

        if (consonant < k)
            return 1;

        if (consonant > k)
            return -1;

        char leftestChar = word.charAt(left);

        if (leftestChar == 'a' && ac > 1) return -1;

        if (leftestChar == 'e' && ec > 1) return -1;

        if (leftestChar == 'i' && ic > 1) return -1;

        if (leftestChar == 'o' && oc > 1) return -1;

        if (leftestChar == 'u' && uc > 1) return -1;

        return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值