贪心算法,递归——最小删除次数

题目描述

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

难度中等53收藏分享切换为英文接收动态反馈

如果字符串 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 <= s.length <= 105

  • s 仅含小写英文字母

思路:

1,确定字符串中的字母种类及一个字母出现的次数

2,对出现的次数进行排序(这里采用降序),根据题目要求 最小删除数就是不能有相同出现的频次 也就是说 对相同的频次减一 看有没有与减一之后再次相同的 如果有继续上述过程 如果无停止记录减一的次数 对每一个相同频次采用类似的处理方法

3,因为要求最小删除数 及最优解 那么可以用贪心算法

开辟一个数组 将其初始化为0 用频次作为下标 将该项赋值为1 如果频次相等 对其减一 有多少个相同频次进行多少次上述操作

直到减到频次为1 那么剩下的频次加上减一的次数即最小删除次数 ```

代码块

#define LETTER_NUM 26
#define MAX_LENGTH 100001

// 降序 比较函数
int cmp_down(const void *a, const void *b)
{
    return (*(int *)b - *(int *)a);
}

int minDeletions(char *s)
{
    int i;
    int hash[LETTER_NUM] = {0}; // 统计字母出现个数
    int flag[MAX_LENGTH] = {0}; // 标记是否已经出现过,出现flag = 1
    int str_len = strlen(s);
    int min_delete = 0;

    for (i = 0; i < str_len; i++) {
        hash[s[i] - 'a']++;
    }
    qsort(hash, LETTER_NUM, sizeof(int), cmp_down);

    for (i = 0; i < LETTER_NUM; i++) {
        // 如果出现次数为0,停止循环
        if (hash[i] == 0) {
            break;
        }

        // 如果没有出现过,标记为1
        if (flag[hash[i]] == 0) {
            flag[hash[i]] = 1;
        } else {
            while (1) {
                min_delete++;
                hash[i]--;//相当于下标
                // 如果减小到数字0,跳出本次循环
                if (hash[i] == 0) {
                    break;
                }
                // 如果减小到没有出现,标记为1,跳出本次循环
                if (flag[hash[i]] == 0) {
                    flag[hash[i]] = 1;
                    break;
                }
            }
        }
    }

    return min_delete;
}

递归思路


// 删除频次相同的最大次数字符中的1个即可,递归,计算depth

int cmp(const int *a, const int *b)
{
    return *a - *b;
}

void dfs(int *dict, int dictSize, int *depth)
{
    qsort(dict, dictSize, sizeof(int), cmp);
    for (int i = 1; i < dictSize; i++) {
        if (dict[i] == dict[i - 1] && dict[i] != 0) {
            dict[i]--;
            *depth += 1;
            dfs(dict, dictSize, depth);
            return;
        }
    }

    return;
}

int minDeletions(char * s){
    if (strlen(s) == 1) {
        return 0;
    }
    int dict[26] = { 0 };
    for (char *tmp = s; *tmp != '\0'; tmp++) {
        dict[*tmp - 'a']++;
    }
    int depth = 0;
    dfs(dict, sizeof(dict) / sizeof(int), &depth);

    return depth;
}

如有其他解法相互分享

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸡爱玩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值