【LeetCode每日一题合集】2023.9.18-2023.9.24(⭐拓扑排序⭐设计数据结构:LRU缓存实现 LinkedHashMap⭐)

news2024/11/27 17:43:27

文章目录

  • 337. 打家劫舍 III(树形DP)
  • 2560. 打家劫舍 IV(二分查找+动态规划)
  • LCP 06. 拿硬币(简单贪心模拟)
  • 2603. 收集树中金币⭐
    • 思路——拓扑排序删边
  • 2591. 将钱分给最多的儿童(分类讨论)
  • 1993. 树上的操作💩(设计数据结构)
  • 146. LRU 缓存(⭐数据结构:哈希表+双向链表)
    • 解法1——哈希表+双向链表⭐
    • 解法2——Java JDK LinkedHashMap
      • 补充——LinkedHashMap
      • 补充——Java修饰符

337. 打家劫舍 III(树形DP)

https://leetcode.cn/problems/house-robber-iii/description/?envType=daily-question&envId=2023-09-18

在这里插入图片描述
提示:
树的节点数在 [1, 10^4] 范围内
0 <= Node.val <= 10^4

class Solution {
    public int rob(TreeNode root) {
        int[] res = dfs(root);
        return Math.max(res[0], res[1]);
    }

    public int[] dfs(TreeNode root) {
        // 返回值{a,b} a表示没选当前节点的最大值,b表示选了当前节点的最大值
        if (root == null) return new int[]{0, 0};
        int[] l = dfs(root.left), r = dfs(root.right);
        int a = Math.max(l[0], l[1]) + Math.max(r[0], r[1]), b = root.val + l[0] + r[0];
        return new int[]{a, b};
    }
}

2560. 打家劫舍 IV(二分查找+动态规划)

https://leetcode.cn/problems/house-robber-iv/description/?envType=daily-question&envId=2023-09-19

在这里插入图片描述
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
1 <= k <= (nums.length + 1)/2

二分查找答案。 对于每次查找,判断是否可以至少偷k家。

class Solution {
    public int minCapability(int[] nums, int k) {
        if (nums.length == 1) return nums[0];
        int l = Integer.MAX_VALUE, r = Integer.MIN_VALUE;
        for (int x: nums) {
            l = Math.min(l, x);
            r = Math.max(r, x);
        }
        // 二分查找答案
        while (l < r) {
            int mid = l + r >> 1;
            if (op(nums, mid) >= k) r = mid;
            else l = mid + 1;
        }
        return l;
    }

    // 动态规划
    public int op(int[] nums, int k) {
        int n = nums.length;
        int[] dp = new int[n];      // dp[i]表示0~i中最多能偷几个
        dp[0] = nums[0] <= k? 1: 0;
        dp[1] = Math.max(dp[0], nums[1] <= k? 1: 0);
        for (int i = 2; i < n; ++i) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + (nums[i] <= k? 1: 0));
        }
        return dp[n - 1];
    }
}

LCP 06. 拿硬币(简单贪心模拟)

https://leetcode.cn/problems/na-ying-bi/

在这里插入图片描述

class Solution {
    public int minCount(int[] coins) {
        int ans = 0;
        for (int x: coins) ans += (x + 1) / 2;
        return ans;
    }
}

2603. 收集树中金币⭐

https://leetcode.cn/problems/collect-coins-in-a-tree/description/?envType=daily-question&envId=2023-09-21

在这里插入图片描述
提示:
n == coins.length
1 <= n <= 3 * 10^4
0 <= coins[i] <= 1
edges.length == n - 1
edges[i].length == 2
0 <= ai, bi < n
ai != bi
edges 表示一棵合法的树。

难度分 2712 是因为当时美国站点崩了,很多人没看到题。

思路——拓扑排序删边

https://leetcode.cn/problems/collect-coins-in-a-tree/solutions/2191371/tuo-bu-pai-xu-ji-lu-ru-dui-shi-jian-pyth-6uli/?envType=daily-question&envId=2023-09-21

先去掉所有没有金币的叶子节点。
再去掉最外两层的节点。
最后的答案就是剩余的边数 * 2。

class Solution {
    public int collectTheCoins(int[] coins, int[][] edges) {
        int n = coins.length;
        List<Integer>[] g = new ArrayList[n];
        Arrays.setAll(g, e -> new ArrayList<>());
        int[] deg = new int[n];     // 记录每个节点的入度
        for (int[] e: edges) {
            int x = e[0], y = e[1];
            g[x].add(y);
            g[y].add(x);
            deg[x]++;
            deg[y]++;
        }

        int leftEdges = n - 1;      // 记录剩余的边数
        // 拓扑排序,去掉所有没有金币的子树
        Queue<Integer> q = new LinkedList<>();
        for (int i = 0; i < n; ++i) {
            if (deg[i] == 1 && coins[i] == 0) q.offer(i);
        }
        while (!q.isEmpty()) {
            leftEdges--;            // 删除当前节点和其父节点之间的边
            for (int y: g[q.poll()]) {
                if (--deg[y] == 1 && coins[y] == 0) {
                    q.offer(y);
                }
            }
        }

        // 再次拓扑排序,删除最外两层的节点
        for (int i = 0; i < n; ++i) {
            if (deg[i] == 1 && coins[i] == 1) q.offer(i);
        }
        leftEdges -= q.size();
        for (int x: q) {
            for (int y: g[x]) {
                if (--deg[y] == 1) leftEdges--;
            }
        }
        return Math.max(leftEdges * 2, 0);
    }
}

2591. 将钱分给最多的儿童(分类讨论)

https://leetcode.cn/problems/distribute-money-to-maximum-children/description/?envType=daily-question&envId=2023-09-22
在这里插入图片描述

class Solution {
    public int distMoney(int money, int children) {
        if (money < children) return -1;
        money -= children;
        int x = Math.min(money / 7, children);      // 计算最多多少个儿童分到8美元
        int y = money - x * 7;                      // 计算剩余的美元
        if ((x == children - 1 && y == 3 ) || (x == children  && y > 0)) return x - 1;
        return x;
    }
}

1993. 树上的操作💩(设计数据结构)

https://leetcode.cn/problems/operations-on-tree/description/?envType=daily-question&envId=2023-09-23
在这里插入图片描述
提示:
n == parent.length
2 <= n <= 2000
对于 i != 0 ,满足 0 <= parent[i] <= n - 1
parent[0] == -1
0 <= num <= n - 1
1 <= user <= 10^4
parent 表示一棵合法的树。
lock ,unlock 和 upgrade 的调用 总共 不超过 2000 次。

class LockingTree {
    int[] parent;
    int[] lockNodeUser;
    List<Integer>[] g;      // 存储所有儿子

    public LockingTree(int[] parent) {
        int n = parent.length;
        this.parent = parent;
        lockNodeUser = new int[n];
        Arrays.fill(lockNodeUser, -1);
        g = new List[n];
        Arrays.setAll(g, e -> new ArrayList<>());
        for (int i = 0; i < n; ++i) {
            if (parent[i] != -1) g[parent[i]].add(i);
        }
    }
    
    public boolean lock(int num, int user) {
        if (lockNodeUser[num] == -1) {
            lockNodeUser[num] = user;
            return true;
        }
        return false;
    }
    
    public boolean unlock(int num, int user) {
        if (lockNodeUser[num] == user) {
            lockNodeUser[num] = -1;
            return true;
        }
        return false;
    }
    
    public boolean upgrade(int num, int user) {
        // 自己没被上锁,没有祖宗上锁,有子孙节点上锁了
        boolean res = lockNodeUser[num] == -1 && !hasLockedAncestor(num) && checkAndUnlockDescendant(num);
        if (res) lockNodeUser[num] = user;
        return res;
    }

    // 是否有祖宗节点被上锁
    public boolean hasLockedAncestor(int num) {
        num = parent[num];
        while (num != -1) {
            if (lockNodeUser[num] != -1) return true;
            num = parent[num];
        }
        return false;
    }

    // 是否有子孙节点被上锁,并解锁
    public boolean checkAndUnlockDescendant(int num) {
        boolean res = lockNodeUser[num] != -1;
        lockNodeUser[num] = -1;         
        for (int y: g[num]) {
            res |= checkAndUnlockDescendant(y);
        }
        return res;
    }
}

/**
 * Your LockingTree object will be instantiated and called as such:
 * LockingTree obj = new LockingTree(parent);
 * boolean param_1 = obj.lock(num,user);
 * boolean param_2 = obj.unlock(num,user);
 * boolean param_3 = obj.upgrade(num,user);
 */

这题的重点在于操作三的实现。

146. LRU 缓存(⭐数据结构:哈希表+双向链表)

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

在这里插入图片描述
提示:

1 <= capacity <= 3000
0 <= key <= 10000
0 <= value <= 10^5
最多调用 2 * 10^5 次 get 和 put

解法1——哈希表+双向链表⭐

双向链表维护各个节点被使用的情况,头节点是最近被使用的,尾节点是最久未被使用的。
哈希表维护key和节点之间的映射,帮助快速找到指定key的节点。

class LRUCache {
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode() {};
        public DLinkedNode(int _key, int _value) {
            this.key = _key;
            this.value = _value;
        }
    }

    Map<Integer, DLinkedNode> cache = new HashMap<>();  // key和节点的映射
    int size = 0;       // 大小
    int capacity;       // 容量
    // 虚拟头尾节点
    DLinkedNode head = new DLinkedNode(), tail = new DLinkedNode();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) return -1;
        moveToHead(node);
        return node.value;
    }
    
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            DLinkedNode newNode = new DLinkedNode(key, value);
            cache.put(key, newNode);
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                DLinkedNode last = removeTail();    
                cache.remove(last.key);
                --size;
            } 
        } else {
            node.value = value;
            moveToHead(node);
        }
    }

    // 将节点添加到头部
    public void addToHead(DLinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    // 删除节点
    public void removeNode(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    // 将节点移动到头部
    public void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

    // 删除最后一个节点
    public DLinkedNode removeTail() {
        DLinkedNode node = tail.prev;
        removeNode(node);
        return node;
    }
}

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

解法2——Java JDK LinkedHashMap

class LRUCache extends LinkedHashMap<Integer, Integer>{
    private int capacity;

    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }
    
    public int get(int key) {
        return super.getOrDefault(key, -1);
    }
    
    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity;
    } 
}

补充——LinkedHashMap

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashMap.html

构造器:
在这里插入图片描述

在这里插入图片描述


protected boolean removeEldestEntry​(Map.Entry<K,​V> eldest)
如果此映射应该删除其最年长的条目,则返回true。在向映射中插入新条目后,put和putAll调用该方法。它为实现者提供了每次添加新条目时删除最老条目的机会。如果映射表示缓存,这很有用:它允许映射通过删除过时的条目来减少内存消耗。
在这里插入图片描述

补充——Java修饰符

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

MATLAB_5MW风电永磁直驱发电机-1200V直流并网MATLAB仿真模型

仿真软件&#xff1a;matlab2016b 风机传动模块、PMSG模块、蓄电池模块、超级电容模块、无穷大电源、蓄电池控制、风机控制、逆变器控制等模块。 逆变器输出电压&#xff1a; 混合储能系统SOC&#xff1a; 威♥关注“电击小子程高兴的MATLAB小屋”获取更多精彩资料&#xff0…

String的几个常见面试题及其解析

String s3 new String("a") new String("b")会不会在常量池中创建对象&#xff1f; 答案&#xff1a;不会&#xff0c;首先需要解释“”字符串拼接的理解。 采用 运算符拼接字符串时&#xff1a; 如果拼接的都是字符串直接量&#xff0c;则在编译时编…

基于信号功率谱特征和GRNN广义回归神经网络的信号调制类型识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ................................................................ %调制识别 len1 func_f…

【代码】【5 二叉树】d3

关键字&#xff1a; 非叶子结点数、k层叶子结点数、层次遍历、找双亲结点、找度为1、叶子结点数

MySQL EXPLAIN查看执行计划

MySQL 执⾏计划是 MySQL 查询优化器分析 SQL 查询时⽣成的⼀份详细计划&#xff0c;包括表如何连 接、是否⾛索引、表扫描⾏数等。通过这份执⾏计划&#xff0c;我们可以分析这条 SQL 查询中存在的 问题&#xff08;如是否出现全表扫描&#xff09;&#xff0c;从⽽进⾏针对优化…

好用的MybatisX插件~

MybatisX插件&#xff1a; MyBatis-Plus为我们提供了强大的mapper和service模板&#xff0c;能够大大的提高开发效率。但是在真正开发过程中&#xff0c;MyBatis-Plus并不能为我们解决所有问题&#xff0c;例如一些复杂的SQL&#xff0c;多表联查&#xff0c;我们就需要自己去…

Web前端—网页制作(以“学成在线”为例)

版本说明 当前版本号[20231105]。 版本修改说明20231105初版 目录 文章目录 版本说明目录day07-学成在线01-项目目录02-版心居中03-布局思路04-header区域-整体布局HTML结构CSS样式 05-header区域-logo06-header区域-导航HTML结构CSS样式 07-header区域-搜索布局HTML结构CSS…

Gin学习笔记

Gin学习笔记 Gin文档&#xff1a;https://pkg.go.dev/github.com/gin-gonic/gin 1、快速入门 1.1、安装Gin go get -u github.com/gin-gonic/gin1.2、main.go package mainimport ("github.com/gin-gonic/gin""net/http" )func main() {// 创建路由引…

打通你学习C语言的任督二脉-函数栈帧的创建和销毁(上)

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏:C语言学习&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 待解决疑惑: 局部变量是怎么创建的? 为什么局部变量的值是随机值? 函数是怎么传参的?传参的顺序是怎样的? 形参和实参是什么关系? 函数调…

3.25每日一题(知线性常系数方程的特解求线性方程)

思路&#xff1a;通过特解可以知道特征根&#xff0c;通过特征根可以求出特征方程&#xff0c;通过特征方程可以求出线性方程

C语言strcat函数再学习

之前学习了strcat函数&#xff1b;下面继续学习此函数&#xff1b; 它的功能描述是&#xff0c; 功能 把src所指向的字符串&#xff08;包括“\0”&#xff09;复制到dest所指向的字符串后面&#xff08;删除*dest原来末尾的“\0”&#xff09;。要保证*dest足够长&#xff0…

【数智化人物展】觉非科技CEO李东旻:数据闭环,智能驾驶数智时代发展的新引擎...

李东旻 本文由觉非科技CEO李东旻投递并参与《2023中国企业数智化转型升级先锋人物》榜单/奖项评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 数智化的主要作用是帮助决策。它的核心是大数据&#xff0c;以大数据为基础&#xff0c;匹配合适的AI技术&#xff0c;促使数…

Framebuffer 介绍和应用编程

前言&#xff1a; 使用的开发板为韦东山老师的 IMX6ULL 目录 Framebuffer介绍 LCD 操作原理 涉及的 API 函数 1.open 函数 2.ioctl 函数 3.mmap 函数 Framebuffer 程序分析 1.打开设备 2.获取 LCD 参数 3.映射 Framebuffer 4.描点函数 5.随便画几个点 6.上机实验…

一个高性能类型安全的.NET枚举实用开源库

从零构建.Net前后端分离项目 枚举应该是我们编程中&#xff0c;必不可少的了&#xff0c;今天推荐一个.NET枚举实用开源库&#xff0c;它提供许多方便的扩展方法&#xff0c;方便开发者使用开发。 01 项目简介 Enums.NET是一个.NET枚举实用程序库&#xff0c;专注于为枚举提…

【技术干货】开源库 Com.Gitusme.Net.Extensiones.Core 的使用

目录 1、项目介绍 2、为项目添加依赖 3、代码中导入命名空间 4、代码中使用 示例 1&#xff1a;string转换 示例 2&#xff1a;object转换 1、项目介绍 Com.Gitusme.Net.Extensiones.Core是一个.Net扩展库。当前最新版本1.0.4&#xff0c;提供了常见类型转换&#xff0c…

坐公交:内外向乘客依序选座(python字典、字符串、元组)

n排宽度不一的座位&#xff0c;每排2座&#xff0c;2n名内外向乘客依序上车按各自喜好选座。 (笔记模板由python脚本于2023年11月05日 21:49:31创建&#xff0c;本篇笔记适合熟悉python列表list、字符串str、元组tuple的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&…

从公共业务提取来看架构演进——帐号权限篇

1. 引言 在产品业务多元化的过程中&#xff0c;往往会遇到一些与业务发展不匹配的架构问题&#xff0c;这些问题可能会在业务迭代中以性能差、重复开发等形式表现出来&#xff0c;进而给系统的扩展和维护带来一些挑战。 本文准备以一个帐号权限的业务为例&#xff0c;来讨论下…

SQL FULL OUTER JOIN 关键字(完整外部连接)||SQL自连接 Self JOIN

SQL FULL OUTER JOIN 关键字 当左&#xff08;表1&#xff09;或右&#xff08;表2&#xff09;表记录匹配时&#xff0c;FULL OUTER JOIN关键字将返回所有记录。 注意&#xff1a; FULL OUTER JOIN可能会返回非常大的结果集&#xff01; SQL FULL OUTER JOIN 语法 SELECT …

[100天算法】-搜索旋转排序数组(day 60)

题目描述 升序排列的整数数组 nums 在预先未知的某个点上进行了旋转&#xff08;例如&#xff0c; [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] &#xff09;。请你在数组中搜索 target &#xff0c;如果数组中存在这个目标值&#xff0c;则返回它的索引&#xff0c;否…

计算机毕设 基于大数据的服务器数据分析与可视化系统 -python 可视化 大数据

文章目录 0 前言1 课题背景2 实现效果3 数据收集分析过程**总体框架图****kafka 创建日志主题****flume 收集日志写到 kafka****python 读取 kafka 实时处理****数据分析可视化** 4 Flask框架5 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&a…