【LeetCode每日一题合集】2023.9.25-2023.10.1(⭐LFU缓存Java数据流花期内花的数量)

news2024/9/24 7:21:03

文章目录

460. LFU 缓存⭐(数据结构题)

https://leetcode.cn/problems/lfu-cache/description/?envType=daily-question&envId=2023-09-25

在这里插入图片描述

提示:
1 <= capacity <= 10^4
0 <= key <= 10^5
0 <= value <= 10^9
最多调用 2 * 10^5 次 get 和 put 方法

解法1——平衡树 + 哈希表(TreeSet + HashMap) O ( l o g n ) O(logn) O(logn)

自定义节点维护每个键值对的 time 和 cnt。
用 TreeSet 对节点排序,HashMap 存储 key 和 node 的对应关系。

class LFUCache {
    int capacity, time;
    Map<Integer, Node> keyTable;
    TreeSet<Node> s;

    public LFUCache(int capacity) {
        this.capacity = capacity;
        this.time = 0;
        keyTable = new  HashMap<>();
        s = new TreeSet<Node>();
    }
    
    public int get(int key) {
        if (!keyTable.containsKey(key)) return -1;
        // 取出旧的
        Node cache = keyTable.get(key);
        s.remove(cache);
        // 修改旧的 并重新放入
        cache.cnt++;
        cache.time = time++;
        s.add(cache);
        keyTable.put(key, cache);
        return cache.value;
    }
    
    public void put(int key, int value) {
        if (!keyTable.containsKey(key)) {
            if (keyTable.size() == capacity) {
                // 删除最近最少使用的
                keyTable.remove(s.first().key);
                s.remove(s.first());
            }
            // 创建新的缓存
            Node cache = new Node(1, time++, key, value);
            keyTable.put(key, cache);
            s.add(cache);
        } else {
            Node cache = keyTable.get(key);
            s.remove(cache);
            cache.cnt++;
            cache.time = time++;
            cache.value = value;
            s.add(cache);
            keyTable.put(key, cache);
        }
    }
}

class Node implements Comparable<Node> {
    int cnt, time, key, value;

    Node(int cnt, int time, int key, int value) {
        this.cnt = cnt;
        this.time = time;
        this.key = key;
        this.value = value;
    }

    public boolean equals(Object anObject) {
        if (this == anObject) return true;
        if (anObject instanceof Node) {
            Node rhs = (Node) anObject;
            return this.cnt == rhs.cnt && this.time == this.time;
        }
        return false;
    }

    public int compareTo(Node rhs) {
        return cnt == rhs.cnt? time - rhs.time: cnt - rhs.cnt;
    }

    public int hashCode() {
        return cnt * 1000000007 + time;
    }
}

/**
 * Your LFUCache object will be instantiated and called as such:
 * LFUCache obj = new LFUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

解法2——双哈希表 + 双向链表 O ( 1 ) O(1) O(1) (LRU缓存的升级版)

一个哈希表存储 key 和 Node 之间的关系。另一个哈希表存储 freq 和 DoublyLinkedList 的对应关系。
每个使用频率对应一个双向链表,双向链表维护了该频次所有节点的先后顺序,头节点是最近被使用的,尾节点是最不常被使用的。(类似LRU缓存那道题)。

同时维护一个变量 minFreq,方便快速确定最低使用的频率。

class LFUCache {
    int minFreq, capacity;
    Map<Integer, Node> keyTable;
    Map<Integer, DoublyLinkedList> freqTable;

    public LFUCache(int capacity) {
        this.minFreq = 0;
        this.capacity = capacity;
        keyTable = new HashMap<Integer, Node>();
        freqTable = new HashMap<Integer, DoublyLinkedList>();
    }
    
    public int get(int key) {
        if (capacity == 0) {
            return -1;
        }
        if (!keyTable.containsKey(key)) {
            return -1;
        }
        Node node = keyTable.get(key);
        int val = node.val, freq = node.freq;
        freqTable.get(freq).remove(node);
        // 如果当前链表为空,我们需要在哈希表中删除,且更新minFreq
        if (freqTable.get(freq).size == 0) {
            freqTable.remove(freq);
            if (minFreq == freq) {
                minFreq += 1;
            }
        }
        // 插入到 freq + 1 中
        DoublyLinkedList list = freqTable.getOrDefault(freq + 1, new DoublyLinkedList());
        list.addFirst(new Node(key, val, freq + 1));
        freqTable.put(freq + 1, list);
        keyTable.put(key, freqTable.get(freq + 1).getHead());
        return val;
    }
    
    public void put(int key, int value) {
        if (!keyTable.containsKey(key)) {
            // 缓存已满,需要删除
            if (keyTable.size() == capacity) {
                Node node = freqTable.get(minFreq).getTail();
                keyTable.remove(node.key);
                freqTable.get(minFreq).remove(node);
                if (freqTable.get(minFreq).size == 0) {
                    freqTable.remove(minFreq);
                }
            }
            // 创建新节点
            DoublyLinkedList list = freqTable.getOrDefault(1, new DoublyLinkedList());
            list.addFirst(new Node(key, value, 1));
            freqTable.put(1, list);
            keyTable.put(key, freqTable.get(1).getHead());
            minFreq = 1;
        } else {
            // 与 get 操作基本一致,除了需要更新缓存的值
            Node node = keyTable.get(key);
            int freq = node.freq;
            freqTable.get(freq).remove(node);
            if (freqTable.get(freq).size == 0) {
                freqTable.remove(freq);
                if (minFreq == freq) {
                    minFreq += 1;
                }
            }
            DoublyLinkedList list = freqTable.getOrDefault(freq + 1, new DoublyLinkedList());
            list.addFirst(new Node(key, value, freq + 1));
            freqTable.put(freq + 1, list);
            keyTable.put(key, freqTable.get(freq + 1).getHead());
        }
    }
}

class Node {
    int key, val, freq;
    Node prev, next;

    Node() {
        this(-1, -1, 0);
    }

    Node(int key, int val, int freq) {
        this.key = key;
        this.val = val;
        this.freq = freq;
    }
}

class DoublyLinkedList {
    Node dummyHead, dummyTail;
    int size;

    DoublyLinkedList() {
        dummyHead = new Node();
        dummyTail = new Node();
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
        size = 0;
    }

    public void addFirst(Node node) {
        Node prevHead = dummyHead.next;
        node.prev = dummyHead;
        dummyHead.next = node;
        node.next = prevHead;
        prevHead.prev = node;
        size++;
    }

    public void remove(Node node) {
        Node prev = node.prev, next = node.next;
        prev.next = next;
        next.prev = prev;
        size--;
    }

    public Node getHead() {
        return dummyHead.next;
    }

    public Node getTail() {
        return dummyTail.prev;
    }
}


/**
 * Your LFUCache object will be instantiated and called as such:
 * LFUCache obj = new LFUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

2582. 递枕头

https://leetcode.cn/problems/pass-the-pillow/?envType=daily-question&envId=2023-09-26
在这里插入图片描述

解法——找数学规律

队列长度是 n,每次循环传递 n - 1 次。
计算传递几次循环,以及最后一次循环完成了几次传递。

class Solution {
    public int passThePillow(int n, int time) {
        int x = time / (n - 1), y = time % (n - 1);
        if (x % 2 == 0) return y + 1;
        return n - y;
    }
}

1333. 餐厅过滤器(简单模拟)

https://leetcode.cn/problems/filter-restaurants-by-vegan-friendly-price-and-distance/description/?envType=daily-question&envId=2023-09-27

在这里插入图片描述
提示:
1 <= restaurants.length <= 10^4
restaurants[i].length == 5
1 <= idi, ratingi, pricei, distancei <= 10^5
1 <= maxPrice, maxDistance <= 10^5
veganFriendlyi 和 veganFriendly 的值为 0 或 1 。
所有 idi 各不相同。

写法1——手动模拟

class Solution {
    public List<Integer> filterRestaurants(int[][] restaurants, int veganFriendly, int maxPrice, int maxDistance) {
        List<int[]> ans = new ArrayList<>();
        for (int[] r: restaurants) {
            if (veganFriendly == 1 && r[2] == 0) continue;
            if (r[3] <= maxPrice && r[4] <= maxDistance) {
                ans.add(r);
            }
        }
        Collections.sort(ans, (x, y) -> {
            if (x[1] != y[1]) return y[1] - x[1];
            return y[0] - x[0];
        });
        List<Integer> res = new ArrayList<>();
        for (int[] x: ans) res.add(x[0]);
        return res;
    }
}

写法2——Java数组流处理⭐

class Solution {
    public List<Integer> filterRestaurants(int[][] restaurants, int veganFriendly, int maxPrice, int maxDistance) {
        Stream<int[]> stream = Arrays.stream(restaurants);
        if (veganFriendly == 1) stream = stream.filter(x -> x[2] == 1);
        return stream.filter(x -> x[3] <= maxPrice)
                .filter(x -> x[4] <= maxDistance)
                .sorted((x, y) -> x[1] != y[1]? y[1] - x[1]: y[0] - x[0])
                .map(x -> x[0])
                .collect(Collectors.toList());
    }
}

2251. 花期内花的数目⭐

https://leetcode.cn/problems/number-of-flowers-in-full-bloom/description/?envType=daily-question&envId=2023-09-28

在这里插入图片描述

提示:
1 <= flowers.length <= 5 * 10^4
flowers[i].length == 2
1 <= starti <= endi <= 10^9
1 <= people.length <= 5 * 10^4
1 <= people[i] <= 10^9

解法1——差分数组

由于花期的数据范围很大,所以使用哈希表来代替数组存储差分结果。

代码的重点是差分数组的还原过程。

class Solution {
    public int[] fullBloomFlowers(int[][] flowers, int[] people) {
        Map<Integer, Integer> m = new HashMap<>();  // diff数组
        for (int[] f: flowers) {
            int start = f[0], end = f[1];
            m.merge(start, 1, Integer::sum);
            m.merge(end + 1, -1, Integer::sum);
        }
        // 取出所有的key,从小到大排序
        int[] times = m.keySet().stream().mapToInt(Integer::intValue).sorted().toArray();
        int n = people.length, s = 0;
        int[] ans = new int[n];
        Integer[] idx = IntStream.range(0, n).boxed().toArray(Integer[]::new);
        Arrays.sort(idx, (a, b) -> people[a] - people[b]);
        // 差分数组的还原过程
        for (int i = 0, j = 0; i < n; ++i) {
            while (j < times.length && times[j] <= people[idx[i]]) {
                s += m.get(times[j++]);
            }
            ans[idx[i]] = s;
        }
        return ans;
    }
}

解法2——二分查找

计算出某个人到达之前开花的数量 x 和 花谢的数量 y,那么他对应的答案就是 x - y。这个过程可以用二分查找来做。

class Solution {
    public int[] fullBloomFlowers(int[][] flowers, int[] people) {
        int n = people.length, m = flowers.length;
        int[] ans = new int[n];
        int[] start = new int[m], end = new int[m];
        for (int i = 0; i < m; ++i) {
            start[i] = flowers[i][0];
            end[i] = flowers[i][1];
        }
        Arrays.sort(start);
        Arrays.sort(end);
        for (int i = 0; i < n; ++i) ans[i] = op(start, end, people[i]);
        return ans;
    }

    public int op(int[] start, int[] end, int time) {
        int n = start.length;
        if (start[0] > time || end[n - 1] < time) return 0;
        return bs(start, time) - bs(end, time - 1);
    }

    public int bs(int[] a, int k) {
        int l = -1, r = a.length - 1;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (a[mid] <= k) l = mid;
            else r = mid - 1;
        }
        return l;
    }
}

605. 种花问题(贪心)

https://leetcode.cn/problems/can-place-flowers/description/?envType=daily-question&envId=2023-09-29

在这里插入图片描述
能种就种,比较数量。

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int k = 0, m = flowerbed.length;
        for (int i = 0; i < m; ++i) {
            if (flowerbed[i] == 0) {
                if (i - 1 >= 0 && flowerbed[i - 1] == 1) continue;
                if (i + 1 < m && flowerbed[i + 1] == 1) continue;;
                k++;
                flowerbed[i] = 1;
            }
        }
        return k >= n;
    }
}

2136. 全部开花的最早一天(贪心)

https://leetcode.cn/problems/earliest-possible-day-of-full-bloom/description/?envType=daily-question&envId=2023-09-30

在这里插入图片描述

先种长的慢的。

提示:
n == plantTime.length == growTime.length
1 <= n <= 10^5
1 <= plantTime[i], growTime[i] <= 10^4

class Solution {
    public int earliestFullBloom(int[] plantTime, int[] growTime) {
        Integer[] id = IntStream.range(0, plantTime.length).boxed().toArray(Integer[]::new);
        Arrays.sort(id, (i, j) -> growTime[j] - growTime[i]);
        int ans = 0, day = 0;
        for (int i: id) {
            day += plantTime[i];
            ans = Math.max(ans, day + growTime[i]);
        }
        return ans;
    }
}

这里学习到 IntStream 流创建数组的使用方法——Integer[] id = IntStream.range(0, plantTime.length).boxed().toArray(Integer[]::new);

121. 买卖股票的最佳时机(贪心 | DP)

在这里插入图片描述
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/?envType=daily-question&envId=2023-10-01

解法1——DP

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[] sell = new int[n], buy = new int[n];
        buy[0] = -prices[0];
        for (int i = 1; i < n; ++i) {
            buy[i] = Math.max(buy[i - 1], -prices[i]);
            sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
        }
        return sell[n - 1];
    }
}

解法2——贪心

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length, ans = 0, mn = Integer.MAX_VALUE;
        for (int price: prices) {
            mn = Math.min(mn, price);
            ans = Math.max(ans, price - mn);
        }
        return ans;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1228302.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【WSL/WSL2-Ubuntu】突破界限:不使用服务器在一台Windows搭建Nginx+FastDFS

打造超级开发环境&#xff1a;Nginx和FastDFS在WSL中的完美结合 前言 随着软件开发领域的快速发展&#xff0c;跨平台的开发环境变得日益重要。Windows Subsystem for Linux&#xff08;WSL&#xff09;和WSL 2为开发者提供了在Windows操作系统上体验Linux环境的便捷途径。本…

代码随想录算法训练营第二十八天| 78 子集 90 子集|| 93 复原IP地址

78 子集 由题意可知数组中的元素互不相同&#xff0c;所以在dfs中我们可以将当前的path直接加入到res中。 class Solution {List<List<Integer>>res new ArrayList<>();List<Integer>path new LinkedList<>();public List<List<Integer…

全新酷盒9.0源码:多功能工具箱软件的最新iapp解决方案

全能工具箱软件酷盒&#xff1a;源码提供iapp解决方案&#xff0c;自定义打造个性化体验 酷盒是一款功能丰富的工具箱软件&#xff0c;内置众多实用功能&#xff0c;并实时更新热门功能。该软件还拥有丰富的资源库&#xff0c;用户可以在线畅玩游戏、免费下载音乐等。 我们提…

装饰模式 rust和java的实现

装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。 装饰器模式通过将对象包装在装饰器类中&#xff0c;以便动态地修改其行为。 这种模式创建了一个装饰类&#xff0c;用来包装原有的类&am…

【Flink】系统架构

DataStream API 将你的应用构建为一个 job graph&#xff0c;并附加到 StreamExecutionEnvironment 。当调用 env.execute() 时此 graph 就被打包并发送到 JobManager 上&#xff0c;后者对作业并行处理并将其子任务分发给 Task Manager 来执行。每个作业的并行子任务将在 task…

6 Redis的慢查询配置原理

1、redis的命令执行流程 redis的慢查询只针对步骤3 默认情况下&#xff0c;慢查询的阈值是10ms

[python]python筛选excel表格信息并保存到另一个excel

目录 关键词平台说明背景所需库1.安装相关库2.代码实现sourcetarget1 关键词 python、excel、DBC、openpyxl 平台说明 项目Valuepython版本3.6 背景 从一个excel表中遍历删选信息并保存到另一个excel表 所需库 1.openpyxl &#xff1a;是一个用于读写 Excel 文件的 Pyt…

Flutter 中数据存储的四种方式

在 Flutter 中&#xff0c;存储是指用于本地和远程存储和管理数据的机制。以下是 Flutter 中不同存储选项的概述和示例。 Shared Preferences&#xff08;本地键值存储&#xff09; Shared Preferences 是一种在本地存储少量数据&#xff08;例如用户首选项或设置&#xff09…

【面试经典150 | 算术平方根】

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;数学表达式方法二&#xff1a;二分法 其他语言python3 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并…

测试Bard和ChatGPT关于双休的法规和推理

Bard是试验品&#xff0c;chatgpt是3.5版的。 首先带着问题&#xff0c;借助网络搜索&#xff0c;从政府官方网站等权威网站进行确认&#xff0c;已知正确答案的情况下&#xff0c;再来印证两个大语言模型的优劣。 想要了解的问题是&#xff0c;在中国&#xff0c;跟法定工作…

全新云开发工具箱:融合多项功能的微信小程序源码解决方案

全新云开发工具箱&#xff1a;融合多项功能的微信小程序源码解决方案 这款微信小程序源码提供了超过40个功能&#xff0c;集合了各种实用工具&#xff0c;成为一款全能工具箱。这些功能包括证件照制作、垃圾分类查询、个性签名制作、二维码生成、文字九宫格、手持弹幕、照片压…

初识Java 18-1 泛型

目录 简单泛型 元组库 通过泛型实现栈类 泛型接口 泛型方法 可变参数和泛型方法 通用Supplier 简化元组的使用 使用Set创建实用工具 本笔记参考自&#xff1a; 《On Java 中文版》 继承的层次结构有时会带来过多的限制&#xff0c;例如&#xff1a;编写的方法或类往往…

记一次服务器配置文件获取OSS

一、漏洞原因 由于网站登录口未做双因子校验,导致可以通过暴力破解获取管理员账号,成功进入系统;未对上传的格式和内容进行校验,可以任意文件上传获取服务器权限;由于服务器上配置信息,可以进一步获取数据库权限和OSS管理权限。二、漏洞成果 弱口令获取网站的管理员权限通…

基于Vue+SpringBoot的城市桥梁道路管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询城市桥梁4.2 新增城市桥梁4.3 编辑城市桥梁4.4 删除城市桥梁4.5 查询单个城市桥梁 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的城市桥梁道路管理系统&#xff0c;支持…

系列四、强引用、软引用、弱引用、虚引用分别是什么?

一、整体架构 二、强引用&#xff08;默认支持模式&#xff09; 2.1、概述 当内存不足时&#xff0c;JVM开始垃圾回收&#xff0c;对于强引用的对象&#xff0c;就算是出现了OOM也不会对该对象进行回收&#xff0c;死都不收。 强引用是我们最常见的普通对象引用&#xff0c;只…

腾讯云轻量数据库1核1G评测和租用价格表

腾讯云轻量数据库测评&#xff0c;轻量数据库100%兼容MySQL 5.7和8.0&#xff0c;腾讯云提供1C1G20GB、1C1G40GB、1C2G80GB、2C4G120GB、2C8G240GB五种规格轻量数据库&#xff0c;阿腾云atengyun.com分享腾讯云轻量数据库测评、轻量数据库详细介绍、特性、配置价格和常见问题解…

校园服装定制服务预约小程序的效果如何

对校园服装定制商家而言&#xff0c;如今线下流量稀缺&#xff0c;同行多且竞争激烈&#xff0c;同时这一行面对的消费者非大众&#xff0c;因此各品牌间都在通过各种方式进行同城或多地的客户拓展&#xff0c;但线下方式无疑是比较低效的。线上是一个不错的选择&#xff0c;不…

javaspringbootmysql学生社团管理系统26281-计算机毕业设计项目选题推荐(附源码)

目录 摘要 Abstract 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 学生社团管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析…

TensorRT量化实战课YOLOv7量化:YOLOv7-QAT量化

目录 前言1. YOLOv7-QAT流程2. QAT训练流程 前言 手写 AI 推出的全新 TensorRT 模型量化实战课程&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考。 该实战课程主要基于手写 AI 的 Latte 老师所出的 TensorRT下的模型量化&#xff0c;在其课程的基础上&#xff…

【好用的个人工具】搭建一款实用的个人IT工具箱——it-tools

【好用的个人工具】搭建一款实用的个人IT工具箱——it-tools 一、it-tools介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载it-tools镜像五、部署it-tools工具箱5.1 创建…