Medium
题目描述
在一个仓库里,有一排条形码,其中第 i 个条形码是 barcodes[i]。
请重新排列这些条形码,使得其中任意两个相邻的条形码不相等。你可以返回任何满足该要求的答案,此题保证存在答案。
示例 1:
输入:barcodes = [1,1,1,2,2,2]
输出:[2,1,2,1,2,1]
示例 2:
输入:barcodes = [1,1,1,1,2,2,3,3]
输出:[1,3,1,3,1,2,1,2]
约束条件:
- 1 <= barcodes.length <= 10000
- 1 <= barcodes[i] <= 10000
提示:
- 我们总是希望选择出现次数最多或第二多的元素来写入下一个位置。什么数据结构可以让我们高效地查询这个信息?
解题思路
这道题的核心思想是贪心算法配合优先队列(最大堆)。
解题思路:
- 频次统计:首先统计每个条形码出现的次数
- 优先队列:使用最大堆存储 (频次, 条形码值) 对,确保频次高的元素优先被选择
- 贪心策略:每次选择频次最高的条形码放入结果,但要确保不与前一个相同
- 轮换机制:为避免相邻重复,我们需要在最高频次和次高频次的元素间轮换
具体算法:
- 如果堆顶元素与上一个选择的元素不同,直接选择堆顶
- 如果相同,则选择频次第二高的元素
- 每次选择后,将该元素频次减1,如果频次仍大于0则重新入堆
- 重复直到所有元素都被安排
这种方法保证了我们总是优先处理频次高的元素,同时避免相邻重复,时间复杂度为O(n log k),其中k是不同条形码的种类数。
还有一种基于计数排序的方法,时间复杂度更优,但实现稍复杂。对于此题规模,优先队列方法已足够高效。
代码实现
class Solution {
public:
vector<int> rearrangeBarcodes(vector<int>& barcodes) {
unordered_map<int, int> count;
for (int code : barcodes) {
count[code]++;
}
priority_queue<pair<int, int>> pq;
for (auto& p : count) {
pq.push({p.second, p.first});
}
vector<int> result;
while (!pq.empty()) {
auto first = pq.top();
pq.pop();
if (result.empty() || result.back() != first.second) {
result.push_back(first.second);
if (first.first > 1) {
pq.push({first.first - 1, first.second});
}
} else {
auto second = pq.top();
pq.pop();
result.push_back(second.second);
if (second.first > 1) {
pq.push({second.first - 1, second.second});
}
pq.push(first);
}
}
return result;
}
};
class Solution:
def rearrangeBarcodes(self, barcodes: List[int]) -> List[int]:
from collections import Counter
import heapq
count = Counter(barcodes)
heap = [(-freq, code) for code, freq in count.items()]
heapq.heapify(heap)
result = []
while heap:
first = heapq.heappop(heap)
if not result or result[-1] != first[1]:
result.append(first[1])
if first[0] < -1:
heapq.heappush(heap, (first[0] + 1, first[1]))
else:
second = heapq.heappop(heap)
result.append(second[1])
if second[0] < -1:
heapq.heappush(heap, (second[0] + 1, second[1]))
heapq.heappush(heap, first)
return result
public class Solution {
public int[] RearrangeBarcodes(int[] barcodes) {
var count = new Dictionary<int, int>();
foreach (int code in barcodes) {
count[code] = count.GetValueOrDefault(code, 0) + 1;
}
var pq = new PriorityQueue<(int freq, int code), int>();
foreach (var kvp in count) {
pq.Enqueue((kvp.Value, kvp.Key), -kvp.Value);
}
var result = new List<int>();
while (pq.Count > 0) {
var first = pq.Dequeue();
if (result.Count == 0 || result[result.Count - 1] != first.code) {
result.Add(first.code);
if (first.freq > 1) {
pq.Enqueue((first.freq - 1, first.code), -(first.freq - 1));
}
} else {
var second = pq.Dequeue();
result.Add(second.code);
if (second.freq > 1) {
pq.Enqueue((second.freq - 1, second.code), -(second.freq - 1));
}
pq.Enqueue(first, -first.freq);
}
}
return result.ToArray();
}
}
var rearrangeBarcodes = function(barcodes) {
const freq = new Map();
for (const code of barcodes) {
freq.set(code, (freq.get(code) || 0) + 1);
}
const sorted = Array.from(freq.entries()).sort((a, b) => b[1] - a[1]);
const result = new Array(barcodes.length);
let index = 0;
for (const [code, count] of sorted) {
for (let i = 0; i < count; i++) {
result[index] = code;
index += 2;
if (index >= barcodes.length) {
index = 1;
}
}
}
return result;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n log k),其中 n 是条形码总数,k 是不同条形码的种类数。需要进行 n 次堆操作,每次操作的时间复杂度为 O(log k) |
| 空间复杂度 | O(k),用于存储哈希表和优先队列,其中 k 是不同条形码的种类数 |