【每日一题Day206】LC1054距离相等的条形码 | 计数+大顶堆 计数+排序

简介: 【每日一题Day206】LC1054距离相等的条形码 | 计数+大顶堆 计数+排序

距离相等的条形码【LC1054】

在一个仓库里,有一排条形码,其中第 i 个条形码为 barcodes[i]

请你重新排列这些条形码,使其中任意两个相邻的条形码不能相等。 你可以返回任何满足该要求的答案,此题保证存在答案。

写出了第一种

想做周赛 但是怕脑子动不起来掉分 所以又没做

计数+贪心+大顶堆
  • 思路【计数+贪心+大顶堆】

     需要保证出现次数最多的条形码优先匹配另一个与自身不同的条形码,否则可能会出现相同条形码相邻的情况

  • 首先记录每个条形码的出现次数
  • 然后将二元组[ 条形码,次数 ]放入大顶堆中,以次数降序排序,保证堆顶元素的出现次数最大
  • 然后将次数第一大和第二大的元素交替放入结果集中,注意:次数第二大的元素存在没有的情况
  • 最后返回结果即可
  • 实现
class Solution {
    public int[] rearrangeBarcodes(int[] barcodes) {
        int n = barcodes.length;
        int[] res = new int[n];       
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o2[1] - o1[1]);
        int mx = 0;
        for (int barcode : barcodes){
            mx = Math.max(mx, barcode);
        }
        int[] count = new int[mx + 1];
        for (int barcode : barcodes){
            count[barcode]++;
        }
        // 次数最大的优先匹配第二大的
        for (int j = 1; j <= mx; j++){
            if (count[j] != 0){
                pq.add(new int[]{j,count[j]});
            }
        }
        int i = 0;
        while (i < n){
            int[] pair1 = pq.poll();
            int[] pair2 = null;
            res[i++] = pair1[0];
            pair1[1]--;                    
            if (!pq.isEmpty()){
                pair2 = pq.poll();
                res[i++] = pair2[0];
                pair2[1]--;
            }
            if (pair1[1] != 0){
                pq.add(pair1);
            }
            if (pair2 != null && pair2[1] != 0){
                pq.add(pair2);
            }
        }
        return res;
    }
}

复杂度

  • 时间复杂度:O(n+nlogn)将二元组插入大顶堆的时间复杂度为O(logn)可能需要添加n次。计数的时间复杂度为O(n)
  • 空间复杂度:O(n)
计数+贪心+排序
  • 思路
    由于题目保证存在答案,那么出现最多的条形码的次数一定小于等于n/2那么将出现次数较多的条形码优先交替放置至结果集中,再将出现次数小的条形码放置至其的相邻位置,这样得到的结果一定符合要求
  • 先进行计数
  • 然后将条形码按照出现次数从大到小排序,出现次数相同时按照值从大到小排序
  • 然后将下标分为奇数组和偶数组两组,将相应的条形码依次放入结果集中
  • 实现
class Solution {
    public int[] rearrangeBarcodes(int[] barcodes) {
        int n = barcodes.length;
        Integer[] t = new Integer[n];
        int mx = 0;
        for (int i = 0; i < n; ++i) {
            t[i] = barcodes[i];
            mx = Math.max(mx, barcodes[i]);
        }
        int[] cnt = new int[mx + 1];
        for (int x : barcodes) {
            ++cnt[x];
        }
        Arrays.sort(t, (a, b) -> cnt[a] == cnt[b] ? a - b : cnt[b] - cnt[a]);
        int[] ans = new int[n];
        for (int k = 0, j = 0; k < 2; ++k) {
            for (int i = k; i < n; i += 2) {
                ans[i] = t[j++];
            }
        }
        return ans;
    }
}
作者:ylb
链接:https://leetcode.cn/problems/distant-barcodes/solutions/2268959/python3javacgotypescript-yi-ti-yi-jie-ji-3or2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(M)M为条形码的最大值
目录
相关文章
|
9月前
【每日一题Day272】LC1499满足不等式的最大值 | 单调队列 大顶堆
【每日一题Day272】LC1499满足不等式的最大值 | 单调队列 大顶堆
37 0
|
9月前
|
算法 测试技术 C++
【线段树】【众数】1157数组中占绝大多数的元素
【线段树】【众数】1157数组中占绝大多数的元素
【线段树】【众数】1157数组中占绝大多数的元素
|
9月前
|
算法 测试技术 C#
【线段树】2276. 统计区间中的整数数目
【线段树】2276. 统计区间中的整数数目
|
9月前
每日一题——寻找旋转排序数组中的最小值(I)
每日一题——寻找旋转排序数组中的最小值(I)
|
9月前
|
Java
每日一题《剑指offer》数组篇之把数组排成最小的数
每日一题《剑指offer》数组篇之把数组排成最小的数
49 0
每日一题《剑指offer》数组篇之把数组排成最小的数
|
9月前
|
存储
【每日一题Day276】LC2208将数组和减半的最少操作次数 | 贪心+大顶堆
【每日一题Day276】LC2208将数组和减半的最少操作次数 | 贪心+大顶堆
58 0
|
9月前
【每日一题Day269】LC1851包含每个查询的最小区间 | 排序+离线查询+小顶堆
【每日一题Day269】LC1851包含每个查询的最小区间 | 排序+离线查询+小顶堆
58 0
|
9月前
【每日一题Day220】LC1439有序矩阵中的第 k 个最小数组和 | 堆
【每日一题Day220】LC1439有序矩阵中的第 k 个最小数组和 | 堆
84 0
|
9月前
|
算法 vr&ar 图形学
☆打卡算法☆LeetCode 154. 寻找旋转排序数组中的最小值 II 算法解析
☆打卡算法☆LeetCode 154. 寻找旋转排序数组中的最小值 II 算法解析
|
9月前
|
算法 vr&ar 图形学
☆打卡算法☆LeetCode 153. 寻找旋转排序数组中的最小值 算法解析
☆打卡算法☆LeetCode 153. 寻找旋转排序数组中的最小值 算法解析