IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 优先队列和双优先队列解题 -> 正文阅读

[Java知识库]优先队列和双优先队列解题

一个优先队列解决

leetcode 358 重新安排字符串相同字符间隔k

    /**
     * leetcode 358
     * 给一个非空字符串和一个整数k,要将这个字符串中的字母进行重新排列,使得重排后的字符串中
     * 相同字母的位置间隔至少为k。
     * 所有输入字符串都由小写字母组成,如果找不到距离至少为k的重排结果,请返回一个空字符串"".
     */
    public String rearrangeString(String s, int k) {
        /**
         * 1.先统计所有字符出现的次数,存入一个HashMap
         * 2.按照重复次数从大到小构建一个大顶堆,把map中的元素装进去
         * 3.创建一个StringBuilder, 创建一个普通队列变量queue同步记录已经加入到stringbuilder中的字符
         * 4.循环遍历大顶堆的字符:
         *                      a.取出一个字符char,把它加入到stringbuilder中
         *                      b.将char的重复次数-1,加入到普通queue中
         *                      c.判断queue中元素是否为k个,如果是,说明stringbuilder中距离上一个字符char已经插入了k个字符
         *                      char字符可以再出现一次,把queue队首元素放入大顶堆
         * 5.大顶堆没有元素时:
         *                  a.stringbuilder的长度和s一样,说明构建完成,返回
         *                  b.stringbuilder的长度和s不一样,说明还有字符在queue中,无法保证k个距离
         */
        if (k <= 1) {
            return s;
        }

        Map<Character, Integer> map = new HashMap<>();

        PriorityQueue<Map.Entry<Character, Integer>> maxHeap =
                new PriorityQueue<>((a, b) -> b.getValue() - a.getValue());
        for (Character c : s.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }
        maxHeap.addAll(map.entrySet());
        StringBuilder sb = new StringBuilder();
        Queue<Map.Entry<Character, Integer>> queue = new LinkedList<>();
        while (!maxHeap.isEmpty()) {
            Map.Entry<Character, Integer> currentEntry = maxHeap.poll();
            sb.append(currentEntry.getKey());
            currentEntry.setValue(currentEntry.getValue() - 1);
            queue.offer(currentEntry);
            if (queue.size() == k) {
                Map.Entry<Character, Integer> entry = queue.poll();
                if (entry.getValue() > 0) {
                    maxHeap.add(entry);
                }
            }
        }
        return sb.length() == s.length() ? sb.toString() : "";
    }

两个优先队列解题

leetcode 1882 使用服务器处理任务

这道题更重要的借鉴意义在于如何从题目中抽象过程:

使用两个优先队列的考虑是要对【servers的权重】和【tasks需要的时间】排序,

busy服务器队列需要对【任务执行的时间】从小到大排序,

idle服务器队列需要对【空闲服务器权重】从小到大排序。

因此使用两个优先队列,且队列中保存的是不同的int[]数组:

busy优先队列中保存的数组【int[]{任务执行时间,机器编号}】;

idle优先队列中保存的数组【int[]{服务器权重,机器编号}】。

如果busy队首服务器的时间<=当前时间戳ts,则代表在当前时间ts时,busy队首服务器已经完成任务,可以出队。

从busy队中出来的服务器要重新组数组,行式为?int[]{服务器权重,机器编号},并加入到idle服务器中,具体什么时候用要看服务器的权限什么时候排到。

    /**
     * leetcode 1882 使用服务器处理任务
     *
     * 两个整数数组:servers[n] & tasks[m]
     * servers[i]是第i台服务器的权重
     * tasks[j]是第j个任务所需要的时间
     *
     * 你正在运行一个仿真系统,在处理完所有任务后,该系统将会关闭。
     * 每台服务器只能同时处理一项任务。第 0 项任务在第 0 秒可以开始处理,相应地,第 j 项任务在第 j秒可以开始处理。
     * 处理第 j 项任务时,你需要为它分配一台 权重最小 的空闲服务器。
     * 如果存在多台相同权重的空闲服务器,请选择 下标最小 的服务器。
     * 如果一台空闲服务器在第 t 秒分配到第 j 项任务,那么在 t + tasks[j] 时它将恢复空闲状态。
     *
     * 如果没有空闲服务器,则必须等待,直到出现一台空闲服务器,并 尽可能早地处理剩余任务。
     * 如果有多项任务等待分配,则按照 下标递增 的顺序完成分配。
     *
     * 如果同一时刻存在多台空闲服务器,可以同时将多项任务分别分配给它们。
     *
     * 构建长度为m 的答案数组 ans ,其中 ans[j] 是第 j 项任务分配的服务器的下标。
     *
     * 返回答案数组 ans 。
     */
    public int[] assignTasks(int[] servers, int[] tasks) {
        /**
         * 优先队列busy 存储工作中的服务器(t - 该服务器结束工作的时间, idx - 该服务器的编号)
         *      要满足队首t最小,t相等时则idx最小
         * 优先队列idle 存储空闲的服务器(w - 该服务器的权重, idx - 该服务器的编号)
         *      要满足队首w最小,w相等时则idx最小
         *
         * 算法流程:
         *        1.初始将所有服务器servers放入idle中,并用一个时间戳ts记录当前时间,初始化0
         *        2.遍历每个任务task:
         *                         a.因为第i个任务必须在时间i时开始,因此需要将ts置为ts与i的较大值
         *                         b.需要将优先队列busy中满足t <= ts的服务器依次取出并放入优先队列idle
         *                         c.如果此时idle中无服务器,说明需要等待一台服务器完成任务,因此可以将ts
         *                             置为busy中队首服务器完成任务的时间t,并再执行b步
         *                         d.此时可以给第i个任务安排服务器,即为idle的队首服务器,将其取出并放入busy
         */
        PriorityQueue<int[]> busy = new PriorityQueue<>((a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]);
        PriorityQueue<int[]> idle = new PriorityQueue<>((a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]);

        for (int i = 0; i < servers.length; i++) {
            idle.add(new int[]{servers[i], i});
        }

        int ts = 0;
        int[] ans = new int[tasks.length];
        for (int i = 0; i < tasks.length; i++) {
            ts = Math.max(ts, i);
            while ((!busy.isEmpty() && busy.peek()[0] <= ts) || idle.isEmpty()) {
                int[] busyServer = busy.poll();
                idle.add(new int[]{servers[busyServer[1]], busyServer[1]});
                ts = busyServer[0];
            }
            int[] server = idle.poll();
            ans[i] = server[1];
            int end = tasks[i] + ts;
            busy.add(new int[]{end, server[1]});
        }
        return ans;
    }

leetcode 计算流的中位数

    /**
     * 计算得到一个流的中位数
     * 奇数个值:所有数值排序后位于中间的数值
     * 偶数个值:所有数值排序后中间两个数的平均值
     */

    /**
     * 大顶堆小顶堆排序算法
     */
    /**
     * 大顶堆保留较小的一半,一堆保留一半,
     * 且n为偶数的时候,长度为 n / 2, 为奇数的时候,长度为 (n - 1) / 2
     */
    PriorityQueue<Integer> smaller;
    /**
     * 小顶堆保留较大的一半
     * 且n为偶数的时候,长度为 n / 2, 为奇数的时候,长度为 (n + 1) / 2,也就是说小顶堆个数要大于大顶堆
     */
    PriorityQueue<Integer> larger;
    public MedianFinder() {
        smaller = new PriorityQueue<>(Comparator.reverseOrder());
        larger = new PriorityQueue<>();
    }

    public void addNum(int num) {
        // 保持两端的平衡
        if (smaller.size() != larger.size()) {
            larger.add(num);
            smaller.add(larger.poll());
        } else {
            // 当两个堆个数相同时,先添加到大顶堆,再从大顶堆出队添加到小顶堆
            // 是为了保证小顶堆个数大于大顶堆
            smaller.add(num);
            larger.add(smaller.poll());
        }
    }

    public double findMedian() {
        return smaller.size() != larger.size() ? larger.peek() : (larger.peek() + smaller.peek()) / 2.0;
    }

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:18:55  更:2022-03-15 22:22:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:58:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码