【每日一题】LeetCode 2516.每种字符至少取k个(哈希表、字符串、滑动窗口)

【每日一题】LeetCode 2516.每种字符至少取k个(哈希表、字符串、滑动窗口)

题目描述

给定一个由字符 ‘a’、‘b’、‘c’ 组成的字符串 s 和一个非负整数 k。每分钟,你可以选择取走 s 最左侧或最右侧的那个字符。

你必须取走每种字符至少 k 个,返回需要的最少分钟数;如果无法取到,则返回 -1

输入示例

示例 1

  • 输入:s = "aabaaaacaabc", k = 2
  • 输出:8
  • 解释:从 s 的左侧取三个字符,现在共取到两个字符 ‘a’ 、一个字符 ‘b’ 。从 s 的右侧取五个字符,现在共取到四个字符 ‘a’ 、两个字符 ‘b’ 和两个字符 ‘c’ 。共需要 3 + 5 = 8 分钟。

示例 2

  • 输入:s = "a", k = 1
  • 输出:-1
  • 解释:无法取到一个字符 ‘b’ 或者 ‘c’,所以返回 -1

提示

  • 1 <= s.length <= 10^5
  • s 仅由字母 ‘a’、‘b’、‘c’ 组成
  • 0 <= k <= s.length

思路分析

  1. 首先检查字符串长度是否小于 k * 3,如果是,则无法满足条件,直接返回 -1
  2. 使用哈希表 map 记录每个字符出现的次数。
  3. 遍历字符串,更新 map 中每个字符的计数。
  4. 检查 map 中的每个字符是否满足至少出现 k 次的条件,如果不满足,则返回 -1
  5. 使用双指针 leftright 分别从字符串的两端开始遍历。
  6. 在每一步中,从右侧取一个字符,并更新 map
  7. 如果当前 map 中的字符计数不满足条件,则从左侧取一个字符,直到满足条件。
  8. 更新 max 变量,记录当前找到的最长连续满足条件的子串长度。
  9. 循环结束后,如果 max 仍然是 -1,则说明无法满足条件,返回 -1;否则,返回总长度减去 max 的值,即为所需的最少分钟数。

代码实现

class Solution {
    public int takeCharacters(String s, int k) {
        int n = s.length();
        int max = -1;
        if (n < k * 3) return max; // 如果字符串长度小于k*3,则无法满足条件

        HashMap<Character, Integer> map = new HashMap<>();
        char[] chars = s.toCharArray();
        // 遍历字符串,统计每个字符出现的次数
        for (int right = 0; right < n; right++) {
            map.put(chars[right], map.getOrDefault(chars[right], 0) + 1);
        }
        // 检查是否每个字符都至少出现k次
        if (map.getOrDefault('a', 0) < k || map.getOrDefault('b', 0) < k || map.getOrDefault('c', 0) < k)
            return max;

        int left = 0;
        int right = 0;
        while (right < n) {
            map.put(chars[right], map.getOrDefault(chars[right], 0) - 1); // 从右侧取一个字符
            while (map.getOrDefault('a', 0) < k || map.getOrDefault('b', 0) < k || map.getOrDefault('c', 0) < k) {
                map.put(chars[left], map.getOrDefault(chars[left], 0) + 1); // 从左侧取一个字符,直到满足条件
                left++;
            }
            max = Math.max(max, right - left + 1); // 更新最长连续满足条件的子串长度
            right++;
        }
        return max == -1 ? -1 : n - max; // 返回所需的最少分钟数
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值