
题目描述
给你一个非空的字符串 s 和一个整数 k ,你要将这个字符串 s 中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离 至少 为 k 。如果无法做到,请返回一个空字符串 ""。
 
示例 1:
输入: s = "aabbcc", k = 3
输出: "abcabc" 
解释: 相同的字母在新的字符串中间隔至少 3 个单位距离。
示例 2:
输入: s = "aaabc", k = 3
输出: "" 
解释: 没有办法找到可能的重排结果。
示例 3:
输入: s = "aaadbbcc", k = 2
输出: "abacabcd"
解释: 相同的字母在新的字符串中间隔至少 2 个单位距离。
 
提示:
    1 <= s.length <= 3 * 105 
    s 仅由小写英文字母组成 
    0 <= k <= s.length 
解法
方法一:贪心 + 哈希表 + 优先队列(大根堆)
我们用一个哈希表或数组 \(\textit{cnt}\) 来统计字符串中每个字母出现的次数,然后用一个大根堆 \(\textit{pq}\) 来存储每个字母及其出现次数。堆中的每个元素是一个二元组 \((v, c)\),其中 \(v\) 和 \(c\) 分别表示字母出现的次数和字母本身。
在重排字符串时,我们每次从堆顶弹出一个元素 \((v, c)\),将字母 \(c\) 添加到结果字符串中,并将 \((v-1, c)\) 放入一个队列 \(\textit{q}\) 中。当队列 \(\textit{q}\) 的长度达到 \(k\) 及以上时,弹出队首元素,若此时 \(v\) 大于 \(0\),则将队首元素重新放入堆中。重复该过程,直到堆为空。
最后,我们判断结果字符串的长度是否与原字符串相等,若相等则返回结果字符串,否则返回空串。
时间复杂度为 \(O(n \log n)\),其中 \(n\) 是字符串的长度。空间复杂度 \(O(|\Sigma|)\),其中 \(|\Sigma|\) 是字符集的大小,本题中 \(|\Sigma| = 26\)。
相似题目:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16  | class Solution:
    def rearrangeString(self, s: str, k: int) -> str:
        cnt = Counter(s)
        pq = [(-v, c) for c, v in cnt.items()]
        heapify(pq)
        q = deque()
        ans = []
        while pq:
            v, c = heappop(pq)
            ans.append(c)
            q.append((v + 1, c))
            if len(q) >= k:
                e = q.popleft()
                if e[0]:
                    heappush(pq, e)
        return "" if len(ans) < len(s) else "".join(ans)
  | 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29  | class Solution {
    public String rearrangeString(String s, int k) {
        int[] cnt = new int[26];
        for (char c : s.toCharArray()) {
            ++cnt[c - 'a'];
        }
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[0] - a[0]);
        for (int i = 0; i < cnt.length; ++i) {
            if (cnt[i] > 0) {
                pq.offer(new int[] {cnt[i], i});
            }
        }
        Deque<int[]> q = new ArrayDeque<>();
        StringBuilder ans = new StringBuilder();
        while (!pq.isEmpty()) {
            var p = pq.poll();
            p[0] -= 1;
            ans.append((char) ('a' + p[1]));
            q.offerLast(p);
            if (q.size() >= k) {
                p = q.pollFirst();
                if (p[0] > 0) {
                    pq.offer(p);
                }
            }
        }
        return ans.length() < s.length() ? "" : ans.toString();
    }
}
  | 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35  | class Solution {
public:
    string rearrangeString(string s, int k) {
        vector<int> cnt(26, 0);
        for (char c : s) {
            ++cnt[c - 'a'];
        }
        priority_queue<pair<int, int>> pq;
        for (int i = 0; i < 26; ++i) {
            if (cnt[i] > 0) {
                pq.emplace(cnt[i], i);
            }
        }
        queue<pair<int, int>> q;
        string ans;
        while (!pq.empty()) {
            auto p = pq.top();
            pq.pop();
            p.first -= 1;
            ans.push_back('a' + p.second);
            q.push(p);
            if (q.size() >= k) {
                p = q.front();
                q.pop();
                if (p.first > 0) {
                    pq.push(p);
                }
            }
        }
        return ans.size() < s.size() ? "" : ans;
    }
};
  | 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41  | func rearrangeString(s string, k int) string {
    cnt := [26]int{}
    for _, c := range s {
        cnt[c-'a']++
    }
    pq := priorityqueue.NewWith(func(a, b any) int {
        x := a.([2]int)
        y := b.([2]int)
        return y[0] - x[0]
    })
    for i := 0; i < 26; i++ {
        if cnt[i] > 0 {
            pq.Enqueue([2]int{cnt[i], i})
        }
    }
    var q [][2]int
    var ans strings.Builder
    for pq.Size() > 0 {
        p, _ := pq.Dequeue()
        pair := p.([2]int)
        pair[0]--
        ans.WriteByte(byte('a' + pair[1]))
        q = append(q, pair)
        if len(q) >= k {
            front := q[0]
            q = q[1:]
            if front[0] > 0 {
                pq.Enqueue(front)
            }
        }
    }
    if ans.Len() < len(s) {
        return ""
    }
    return ans.String()
}
  | 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29  | export function rearrangeString(s: string, k: number): string {
    const cnt: number[] = Array(26).fill(0);
    for (const c of s) {
        cnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
    }
    const pq = new PriorityQueue<[number, number]>((a, b) => b[0] - a[0]);
    for (let i = 0; i < 26; i++) {
        if (cnt[i] > 0) {
            pq.enqueue([cnt[i], i]);
        }
    }
    const q: [number, number][] = [];
    const ans: string[] = [];
    while (!pq.isEmpty()) {
        const [count, idx] = pq.dequeue()!;
        const newCount = count - 1;
        ans.push(String.fromCharCode('a'.charCodeAt(0) + idx));
        q.push([newCount, idx]);
        if (q.length >= k) {
            const [frontCount, frontIdx] = q.shift()!;
            if (frontCount > 0) {
                pq.enqueue([frontCount, frontIdx]);
            }
        }
    }
    return ans.length < s.length ? '' : ans.join('');
}
  |