leetcode
leetcode 1001 ~ 1050
距离相等的条形码

距离相等的条形码

难度:

标签:

题目描述

代码结果

运行时间: 66 ms, 内存: 17.5 MB


/*
 * 思路:
 * 1. 统计每个条形码的出现频率。
 * 2. 将条形码按照出现频率从高到低排序。
 * 3. 使用流来简化频率统计和排序。
 */
import java.util.*;
import java.util.stream.Collectors;

public class SolutionStream {
    public int[] rearrangeBarcodes(int[] barcodes) {
        Map<Integer, Long> countMap = Arrays.stream(barcodes)
                .boxed()
                .collect(Collectors.groupingBy(e -> e, Collectors.counting()));

        PriorityQueue<Map.Entry<Integer, Long>> maxHeap = new PriorityQueue<>((a, b) -> Long.compare(b.getValue(), a.getValue()));
        maxHeap.addAll(countMap.entrySet());

        int[] result = new int[barcodes.length];
        int index = 0;
        while (!maxHeap.isEmpty()) {
            Map.Entry<Integer, Long> first = maxHeap.poll();
            if (index > 0 && result[index - 1] == first.getKey()) {
                Map.Entry<Integer, Long> second = maxHeap.poll();
                result[index++] = second.getKey();
                if (second.getValue() > 1) {
                    second.setValue(second.getValue() - 1);
                    maxHeap.add(second);
                }
                maxHeap.add(first);
            } else {
                result[index++] = first.getKey();
                if (first.getValue() > 1) {
                    first.setValue(first.getValue() - 1);
                    maxHeap.add(first);
                }
            }
        }

        return result;
    }
}

解释

方法:

这个题解使用了贪心算法和计数方法来重新排列条形码,以确保没有两个相邻的条形码是相同的。首先,使用Counter计算每个条形码出现的次数。然后,通过遍历这个计数字典,将条形码按照出现次数插入到结果列表中的适当位置。代码中使用了两个索引,odd_idx(奇数索引)和eve_idx(偶数索引),来分别填充奇数和偶数位置的条形码。如果某个条形码的计数小于等于n的一半,则优先填充到奇数位置;如果超过n的一半,则填充到偶数位置。这种策略保证了最终结果中任何相邻位置都不会有相同的条形码。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中提到使用贪心算法和计数方法,能否详细解释为什么这种方法适用于此题目?
贪心算法在此题中的应用是为了尽可能地分散高频条形码的位置,以避免相邻。通过计数方法,我们能够明确每个条形码的出现频率,然后通过贪心地选择位置(奇数位或偶数位)来放置这些条形码。对于出现次数最多的条形码,尽量分布在整个数组中,从而使得任何两个相邻的位置尽可能不放置相同的条形码。这种方法直观且有效地解决了问题,确保了算法的高效性和问题的正确解决。
🦆
在处理计数超过n的一半的条形码时,为什么选择将它们填充到偶数位置?
当某个条形码的计数超过n的一半时,将它们优先填充到偶数位置是为了确保这些条形码可以尽可能均匀地分布在整个数组中。考虑到偶数索引(0, 2, 4, ...)在数组中是连续的,而且对于偶数n来说,偶数位置的数量等于奇数位置的数量。如果条形码的数量非常多,放在偶数位可以保证这些位置被填满,余下的可以填入奇数位置,从而避免连续相同条形码的情况。
🦆
如果条形码的总数n是奇数,填充到奇数索引的条形码数量是否会比偶数索引多一个?这会对最终的排列有什么影响?
当n是奇数时,奇数索引(1, 3, 5, ...)的数量确实会比偶数索引(0, 2, 4, ...)多一个。这意味着最后一个条形码将被放置在最后一个奇数索引上。这种情况下,如果最后几个条形码是相同的,它们可能无法完全分散,因为奇数位置多一个。然而,算法通过优先填充偶数位置确保了高频条形码的分散,因此最终的排列仍然能够尽可能避免相邻条形码相同,即使在奇数总数的情况下。
🦆
代码中在填充条形码时,使用了两个while循环,第一个循环条件中包含`cnt <= half_n`,这是基于什么考虑?
在代码中,`cnt <= half_n`的条件是基于将低频条形码优先放置在奇数位置的考虑。这是因为如果一个条形码的数量不超过n的一半,意味着即使完全填满所有奇数位置,也不会导致任何相邻位置出现相同的条形码。这样的策略帮助确保了条形码的均匀分布,尤其是在条形码种类较多的情况下。这也是一种贪心策略,通过优先解决可能性较低的问题(即低频条形码的分布),从而简化了问题的复杂性。

相关问题