[路飞]_leetcode刷题_1647. 字符频次唯一的最小删除次数

264 阅读2分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战

题目

1647. 字符频次唯一的最小删除次数

如果字符串 s 中 不存在 两个不同字符 频次 相同的情况,就称 s 是 优质字符串 。

给你一个字符串 s,返回使 s 成为 优质字符串 需要删除的 最小 字符数。

字符串中字符的 频次 是该字符在字符串中的出现次数。例如,在字符串 "aab" 中,'a' 的频次是 2,而 'b' 的频次是 1 。

示例 1:

输入:s = "aab"
输出:0
解释:s 已经是优质字符串。

示例 2:

输入:s = "aaabbbcc"
输出:2
解释:可以删除两个 'b' , 得到优质字符串 "aaabcc" 。
另一种方式是删除一个 'b' 和一个 'c' ,得到优质字符串 "aaabbc"

示例 3:

输入:s = "ceabaacb"
输出:2
解释:可以删除两个 'c' 得到优质字符串 "eabaab" 。
注意,只需要关注结果字符串中仍然存在的字符。(即,频次为 0 的字符会忽略不计。)

解法一

遍历,去重。

思路

首先我们要知道,如果遇到有两个字符频率一样,那么我将一个频率减1之后,如果还有元素和当前元素,那就还得继续减1,知道没有频率相同为止,也就是说,这个规律,没有什么套路。

例1:

aaabbbcc,我们将a频率减1,那a和c频率都为2,我们还得把a频率再降1才行

例2:

aaaaabbbbbccccdddee,这个我们将频率写出来为,554321,那将a降为4,a又和c冲突了,再降1又和d冲突了,所以我们得一直降,降到a只剩一个,则更其他人不冲突。

那我们的逻辑也很简单。

  1. 先把每个字符的频率计算出来,放在一个数组里。
  2. 用一个set来存字符出现的频率
  3. 遍历所有字符
    • 如果当前字符的频率在set中没有重复的,则将它加入set
    • 如果当前字符的频率在set中有重复的,则将当前字符频率减一,继续判断
  4. 频率每次减一,就把处理次数加1
  5. 最终返回处理次数即可

代码如下

/**
 * @param {string} s
 * @return {number}
 */
var minDeletions = function (s) {
    let arr = s.split('').map((item) => {
        return item.charCodeAt()
    });
    let count = new Array(26).fill(0);
    let result = 0;
    let set = new Set();

    for (let i = 0; i < arr.length; i++) {
        count[arr[i] - 'a'.charCodeAt()]++;
    }

    for (let i = 0; i < 26; i++) {
        let k = count[i];
        while (k > 0) {
            if (set.has(k)) {
                k--;
                result++;
            }
            else {
                set.add(k);
                break;
            }
        }
    }
    return result;
}

复杂度分析

时间复杂度:O(n),第一次处理字符的频率为一个数组为O(n),后面遍历时间复杂度最坏情况为O(n),即每个元素都只有一个,故总共取O(n)。

空间复杂度:O(n),将字符串处理成数组需要O(n)。