刷题的日常-所有子字符串美丽值之和

97 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

刷题的日常-2022年12月12号

一天一题,保持脑子清爽

所有子字符串美丽值之和

来自leetcode的 1781 题,题意如下:

一个字符串的 美丽值 定义为:出现频率最高字符与出现频率最低字符的出现次数之差。

比方说,"abaacc" 的美丽值为 3 - 1 = 2 。 给你一个字符串 s ,请你返回它所有子字符串美丽值 之和。

示例1:

输入:s = "aabcb"
输出:5
解释:美丽值不为零的字符串包括 ["aab","aabc","aabcb","abcb","bcb"] ,每一个字符串的美丽值都为 1

理解题意

通过题意,我们可以将信息整理如下:

  • 题目给出一个字符串,要求我们返回字符串的 子串 的美丽值之和
  • 美丽值是指字符串中字符出现的最大 最小数量之差

做题思路

题目要求我们返回的是 子字符串 的美丽值的和,所以我们需要枚举所有的子字符串,统计每个子串的美丽值,然后返回统计值。
需要枚举所有的子串,这步省略不了,所以时间复杂度至少为O(n ^ 2),所以就只能通过其它方式进行加速。我们可以用map的方式保存出现的字符,然后在扫描的过程中进行更新,更新完成之后就可以统计最大最小值,加到结果当中。步骤如下:

  • 开辟一个数组用于保存字符数量
  • 统计字符出现的数量
  • 遍历字符串
    • 将出现的字符数组进行拷贝
    • 索引从后往前扫描,出去的字符需要减一
    • 统计最大最小值加到结果当中
    • 最后返回结果
  • 当前出现的字符减一
  • 返回最终结果

代码实现

代码实现如下:

public class Solution {
    int[] map = new int[26];
    public int beautySum(String s) {
        int res = 0;
        for (int i = 0; i < s.length(); i++) {
            map[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < s.length(); i++) {
            res += cnt(i, s);
            map[s.charAt(i) - 'a']--;
        }
        return res;
    }
    public int cnt(int idx, String s) {
        int res = 0, tmp, c;
        int min, max;
        int[] minMap = Arrays.copyOf(map, map.length);
        tmp = s.length() - 1;
        while (tmp > idx) {
            c = s.charAt(tmp--) - 'a';
            min = max = minMap[c];
            for (int num : minMap) {
                if (num != 0) {
                    min = Math.min(min, num);
                    max = Math.max(max, num);
                }
            }
            minMap[c]--;
            res += max - min;
        }
        return res;
    }
}

image.png