[Leetcode] 358. Rearrange String k Distance Apart 解题报告

这篇博客介绍了LeetCode 358题的解题思路,采用贪心策略和优先队列实现。通过统计字符出现次数,确保至少k距离间隔。当无法满足间隔条件时,返回空串。代码实现中,时间复杂度为O(n),空间复杂度为O(m),n为字符串长度,m为不同字符数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Given a non-empty string s and an integer k, rearrange the string such that the same characters are at least distance k from each other.

All input strings are given in lowercase letters. If it is not possible to rearrange the string, return an empty string "".

Example 1:

s = "aabbcc", k = 3

Result: "abcabc"

The same letters are at least distance 3 from each other.

Example 2:

s = "aaabc", k = 3 

Answer: ""

It is not possible to rearrange the string.

Example 3:

s = "aaadbbcc", k = 2

Answer: "abacabcd"

Another possible answer is: "abcabcda"

The same letters are at least distance 2 from each other.

思路

一道比较变态的难题。其基本思想是贪心策略,我们首先统计每个字符出现的个数,然后用一个优先队列来组织它们,以便于出现个数多的字符优先被排列。具体做法如下:

1)如果剩余字符的数量大于等于k,那么我们优先排列这k个不同的字符。如果在排列的过程中发现并没有k个不同的字符了,那么说明后面无论如何排列,都会有字符间隔小于k,所以可以直接返回空串。

2)如果剩余的字符数量小于k个呢?可以采用和1)一样的方法排列剩余的不同字符。

我们采用优先队列进行排列,可以保证让数量大的字符最优先得到排列,并且使其间隔的距离最小,这样可以最大限度地保证后面的字符有足够大的自由排列空间。

如果写出来了下面的代码片段,那么还有一个考点就是如何计算该算法的时间复杂度?虽然在while循环里面还有一个for循环,但是仔细分析我们就可以发现,所有循环的执行次数加起来刚好是字符串s的长度,因为每执行一次循环result的长度就增加1。所以算法的时间复杂度是O(n),空间复杂度是O(m),m是s中不同字符的个数。

代码

class Solution {
public:
    string rearrangeString(string s, int k) {
        if (k == 0) {
            return s;
        }
        int len = s.size();  
        string result;
        map<char, int> hash;                                // map from char to its appearance time
        for(auto ch: s) {
            ++hash[ch];
        }
        priority_queue<pair<int, char>> que;                // using priority queue to pack the most char first
        for(auto val: hash) {
            que.push(make_pair(val.second, val.first));
        }
        while(!que.empty()) {  
            vector<pair<int, int>> vec; 
            int cnt = min(k, len); 
            for(int i = 0; i < cnt; ++i, --len) {           // try to pack the min(k, len) characters sequentially 
                if(que.empty()) {                           // not enough distinct charachters, so return false
                    return "";  
                }
                auto val = que.top();  
                que.pop();  
                result += val.second;  
                if(--val.first > 0) {                       // collect the remaining characters
                    vec.push_back(val);
                }
            }  
            for(auto val: vec) {
                que.push(val);
            }
        }  
        return result;  
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值