Java算法语法学习 美丽子集的数目 - 力扣 Map接口
文章目录
- 题目
- 解题思路
- 题解
- 统计数组中每个数字按模k分组的出现次数,并保持数值有序
- 作用
- **`merge(x, 1, Integer::sum)`**
- 解释
- **检查键是否存在**:
- **合并现有值**:
- 示例
- 在代码中的应用
- **计算余数**:
- **存储余数及其出现次数**:
- `merge` 的常见用法
- 统计频率
- 合并字符串
- 合并集合
- 合并自定义对象
- 合并列表
题目
2597. 美丽子集的数目 - 力扣(LeetCode)
给你一个由正整数组成的数组 nums 和一个 正 整数 k 。
如果 nums 的子集中,任意两个整数的绝对差均不等于 k ,则认为该子数组是一个 美丽 子集。
返回数组 nums 中 非空 且 美丽 的子集数目。
nums 的子集定义为:可以经由 nums 删除某些元素(也可能不删除)得到的一个数组。只有在删除元素时选择的索引不同的情况下,两个子集才会被视作是不同的子集。示例 1:输入:nums = [2,4,6], k = 2
输出:4
解释:数组 nums 中的美丽子集有:[2], [4], [6], [2, 6] 。
可以证明数组 [2,4,6] 中只存在 4 个美丽子集。
示例 2:输入:nums = [1], k = 1
输出:1
解释:数组 nums 中的美丽数组有:[1] 。
可以证明数组 [1] 中只存在 1 个美丽子集。 提示:1 <= nums.length <= 18
1 <= nums[i], k <= 1000
解题思路
动态规划
- 把数组按照模 k 的结果,分成k组
- 从第一组选一些数,从第二组选一些数。第一组中的数字 x 和第二组中的数字 y,
二者相差一定不等于 k(不同余)
。 - 只需考虑每组内选数字的方案数,根据乘法原理把各个组的方案数相乘,即为答案
- 动态规划
设 a 的长度为 m。考虑最大的数 a[m−1] 选或不选:
- 选
a[m−1]
及子问题 设 c 为 a[m−1] 的出现次数,由于大小为 c 的集合有 2 c − 1 2^c-1 2c−1 个非空子集,所以选至少一个 a[m−1] 的方案数为 2 c − 1 2^c-1 2c−1。- 如果
a[m−1] − a[m−2] = k
不选, 则变成a[m - 2]
的子问题
题解
灵神代码
来源:力扣(LeetCode)
class Solution {public int beautifulSubsets(int[] nums, int k) {// 使用HashMap存储每个余数对应的TreeMap,TreeMap按键排序Map<Integer, TreeMap<Integer, Integer>> cnts = new HashMap<>();// 统计每个数字模k的结果,并记录其出现次数for (int x : nums) {cnts.computeIfAbsent(x % k, i -> new TreeMap<>()).merge(x, 1, Integer::sum);}// 初始化答案为1,表示空集int ans = 1;// 遍历每个余数对应的TreeMapfor (TreeMap<Integer, Integer> cnt : cnts.values()) {int m = cnt.size(); // 当前TreeMap中元素的数量int[] f = new int[m + 1]; // 动态规划数组,f[i]表示前i个元素的美丽子集数量f[0] = 1; // 空集是一个美丽子集int i = 1; // 当前处理的索引int pre = 0; // 上一个处理的键值// 遍历当前TreeMap中的每个键值对for (Map.Entry<Integer, Integer> e : cnt.entrySet()) {int x = e.getKey(); // 当前键值int c = e.getValue(); // 当前键值的出现次数// 如果当前键值与上一个键值相差k,则需要考虑不能同时选择的情况if (i > 1 && x - pre == k) {f[i] = f[i - 1] + f[i - 2] * ((1 << c) - 1);} else {f[i] = f[i - 1] << c;}pre = x; // 更新上一个键值i++; // 更新当前索引}// 将当前TreeMap的结果乘到总答案中ans *= f[m];}// 减去1是因为初始时将空集也算进去了return ans - 1;}
}
统计数组中每个数字按模k分组的出现次数,并保持数值有序
// 使用HashMap存储每个余数对应的TreeMap,TreeMap按键排序
Map<Integer, TreeMap<Integer, Integer>> cnts = new HashMap<>();// 统计每个数字模k的结果,并记录其出现次数for (int x : nums) {cnts.computeIfAbsent(x % k, i -> new TreeMap<>()).merge(x, 1, Integer::sum);}
外层HashMap:键是数字对k取模的余数,用于快速定位余数对应的分组
内层TreeMap:值是有序映射,维护该余数下所有原始数字及其出现次数,按键(数字大小)自动排序
computeIfAbsent(x%k, ...)
:余数分组不存在时创建新TreeMap,保证分组结构merge(x, 1, Integer::sum)
:合并相同数字的计数,存在则累加,不存在则初始化为1
作用
快速访问:通过余数直接定位到对应的数字集合
有序存储:TreeMap保持数字自然顺序,便于后续有序遍历或范围查询
高效计数:merge操作简化了频次统计逻辑,避免显式判断键是否存在
适用场景:需要同时按余数分组、维护数值顺序,并统计数值出现次数的算法问题(如某些数对匹配、余数互补检查等问题)
merge(x, 1, Integer::sum)
Java 中 Map
接口提供的一个方法,用于合并指定键的值。
merge
方法的签名如下:
default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
key
: 要合并的键。
value
: 如果键不存在时要插入的值。
remappingFunction
: 一个函数,用于合并现有的值和新值。
解释
在代码中,merge(x, 1, Integer::sum)
的作用是:
检查键是否存在:
如果键 x
不存在于 TreeMap
中,则将其插入,并将值设置为 1
。
合并现有值:
如果键 x
已经存在于 TreeMap
中,则使用 Integer::sum
函数将现有值与 1
相加。
示例
设有一个 TreeMap<Integer, Integer>
,初始为空。执行以下操作:
TreeMap<Integer, Integer> map = new TreeMap<>();
map.merge(1, 1, Integer::sum); // map 现在是 {1=1}
map.merge(1, 1, Integer::sum); // map 现在是 {1=2}
map.merge(2, 1, Integer::sum); // map 现在是 {1=2, 2=1}
map.merge(2, 1, Integer::sum); // map 现在是 {1=2, 2=2}
在代码中的应用
在代码中,merge(x, 1, Integer::sum)
用于统计每个数字模 k
后的结果及其出现次数。
步骤如下:
计算余数:
对于每个数字 x
,计算其模 k
的结果 x % k
。
存储余数及其出现次数:
使用 computeIfAbsent
方法确保 HashMap
中存在键 x % k
对应的 TreeMap
。
使用 merge(x, 1, Integer::sum)
将键 x
在 TreeMap
中的值增加 1
。如果 x
不存在于 TreeMap
中,则将其初始化为 1
。
merge
的常见用法
default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
merge
方法在 Java 中非常灵活,可以用于各种场景。
统计频率
用于统计某个键出现的次数。
import java.util.HashMap;
import java.util.Map;public class FrequencyCounter {public static void main(String[] args) {String[] words = {"apple", "banana", "apple", "orange", "banana", "apple"};Map<String, Integer> frequencyMap = new HashMap<>();for (String word : words) {frequencyMap.merge(word, 1, Integer::sum);}System.out.println(frequencyMap); // 输出: {banana=2, orange=1, apple=3}}
}
合并字符串
import java.util.HashMap;
import java.util.Map;public class StringMerger {public static void main(String[] args) {Map<String, StringBuilder> map = new HashMap<>();String[] words = {"hello", "world", "hello"};for (String word : words) {map.merge(word, new StringBuilder(word), (existing, replacement) -> existing.append(", ").append(replacement));}for (Map.Entry<String, StringBuilder> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue().toString());}// 输出:// hello: hello, hello// world: world}
}
合并集合
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;public class SetMerger {public static void main(String[] args) {Map<String, Set<Integer>> map = new HashMap<>();String[] keys = {"a", "b", "a", "c", "b"};int[] values = {1, 2, 3, 4, 5};for (int i = 0; i < keys.length; i++) {map.merge(keys[i], new HashSet<>(Set.of(values[i])), (existing, replacement) -> {existing.addAll(replacement);return existing;});}for (Map.Entry<String, Set<Integer>> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());}// 输出:// a: [1, 3]// b: [2, 5]// c: [4]}
}
合并自定义对象
import java.util.HashMap;
import java.util.Map;class Account {private String name;private double balance;public Account(String name, double balance) {this.name = name;this.balance = balance;}public void deposit(double amount) {this.balance += amount;}@Overridepublic String toString() {return "Account{name='" + name + "', balance=" + balance + "}";}
}public class CustomObjectMerger {public static void main(String[] args) {Map<String, Account> accountMap = new HashMap<>();String[] names = {"Alice", "Bob", "Alice"};double[] amounts = {100.0, 200.0, 50.0};for (int i = 0; i < names.length; i++) {accountMap.merge(names[i], new Account(names[i], amounts[i]), (existing, replacement) -> {existing.deposit(replacement.balance);return existing;});}for (Map.Entry<String, Account> entry : accountMap.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());}// 输出:// Alice: Account{name='Alice', balance=150.0}// Bob: Account{name='Bob', balance=200.0}}
}
合并列表
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ListMerger {public static void main(String[] args) {Map<String, List<Integer>> map = new HashMap<>();String[] keys = {"a", "b", "a", "c", "b"};int[] values = {1, 2, 3, 4, 5};for (int i = 0; i < keys.length; i++) {map.merge(keys[i], new ArrayList<>(List.of(values[i])), (existing, replacement) -> {existing.addAll(replacement);return existing;});}for (Map.Entry<String, List<Integer>> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());}// 输出:// a: [1, 3]// b: [2, 5]// c: [4]}
}
merge
方法是一个非常强大的工具,可以用于多种类型的合并操作。通过提供一个键、一个默认值和一个合并函数,可以灵活地处理不同的数据结构和逻辑。
键不存在时: 插入默认值。
键存在时: 使用提供的合并函数将现有值与新值合并。
相关文章:
Java算法语法学习 美丽子集的数目 - 力扣 Map接口
文章目录 题目解题思路题解统计数组中每个数字按模k分组的出现次数,并保持数值有序作用 **merge(x, 1, Integer::sum)**解释**检查键是否存在**:**合并现有值**: 示例在代码中的应用**计算余数**:**存储余数及其出现次数**: merge 的常见用法统计频率合并字符串合并…...

Vue项目通过内嵌iframe访问另一个vue页面,获取token适配后端鉴权(以内嵌若依项目举例)
1. 改造子Vue项目进行适配(ruoyi举例) (1) 在路由文件添加需要被外链的vue页面配置 // 若依项目的话是 router/index.js文件 {path: /contrast,component: () > import(/views/contrast/index),hidden: true },(2) 开放白名单 // 若依项目的话是 permission.js 文件 cons…...
梯度本质论:从黎曼流形到神经网络的拓扑寻优
一、微分几何框架下的梯度再诠释 在标准数学分析中,梯度被定义为标量场 f : R n → R f:\mathbb{R}^n→\mathbb{R} f:Rn→R的导数张量 ∇ f ( ∂ f ∂ x 1 , . . . , ∂ f ∂ x n ) \nabla f(\frac{\partial f}{\partial x_1},...,\frac{\partial f}{\partial x_n…...

计算机毕业设计SpringBoot+Vue.js网络海鲜市场系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

一文对比RAGFLOW和Open WebUI【使用场景参考】
一、RAGFLOW与Open WebUI RAGFLOW是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不…...

2025年03月07日Github流行趋势
项目名称:ai-hedge-fund 项目地址url:https://github.com/virattt/ai-hedge-fund项目语言:Python历史star数:12788今日star数:975项目维护者:virattt, seungwonme, KittatamSaisaard, andorsk, arsaboo项目…...

实训任务2.2 使用Wireshark捕获数据包并分析
目录 【实训目标】 【实训环境】 【实训内容】 【实训步骤】 1.启动WireShark 2. 使用Wireshark捕获数据包 (1)选择网络接口 (2)捕获数据包 (1)设置Wireshark过滤器并捕获数据包 (2&…...
C# Lambda 表达式 详解
总目录 前言 在C#编程中,Lambda表达式是一种简洁而强大的语法特性,它提供了一种更加灵活和直观的方式来编写匿名函数。无论是在LINQ查询、事件处理还是异步编程中,Lambda表达式都扮演着重要角色。本文将详细介绍Lambda,帮助您更好…...
wordpress自定the_category的输出结构
通过WordPress的过滤器the_category来自定义输出内容。方法很简单,但是很实用。以下是一个示例代码: function custom_the_category($thelist, $separator , $parents ) {// 获取当前文章的所有分类$categories get_the_category();if (empty($categ…...

HTML前端手册
HTML前端手册 记录前端框架在使用过程中遇到的各种问题和解决方案,供后续快速进行手册翻阅使用 文章目录 HTML前端手册1-前端框架1-TypeScript框架2-CSS框架 2-前端Demo1-Html常用代码 2-知云接力3-Live2D平面动画 3-前端运维1-NPM版本管理 1-前端框架 1-TypeScrip…...

vscode mac版本 配置git
首先使用 type -a git查看git的安装目录 然后在vscode中找到settings配置文件,修改git.path...

爬虫Incapsula reese84加密案例:Etihad航空
声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、找出需要加密的参数 1.js运行 atob(‘aHR0cHM6Ly93d3cuZXRpaGFkLmNvbS96aC1jbi8=’) 拿到网址,F12打开调试工具,随便搜索航班,切换到network搜索一个时间点可以找…...

【C#】async与await介绍
1. 实例1 1.1 代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ConsoleApp1 {class Program{static void Main(string[] args){Method1();Method2();Console.ReadKey();}public static…...

【银河麒麟高级服务器操作系统实例】虚拟机桥接网络问题分析及处理
更多银河麒麟操作系统产品及技术讨论,欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer…...

Vue3路由组件和一般组件 切换路由时组件挂载和卸载 路由的工作模式
路由组件和一般组件 路由组件 一般放到pages或view目录 一般组件 一般放到component目录 切换路由 切换路由时,组件和执行挂载和卸载 路由的工作模式 Hash模式 缺点 1.不美观,路径带#号 优点 1.兼容性好 一般适用于管理系统 History模式 缺点…...

Spring Boot集成Minio笔记
一、首先配置MinIO 1、MinIO新建Bucket,访问控制台如图 创建访问密钥(就是账号和密码) 二、集成mino添加Minio客户端依赖 1.maven构建方式在pom.xml引入jar <dependency><groupId>io.minio</groupId><artifactId>minio</artifactI…...
linux c++11 gcc4 环境编译安装googletest/gtest v1.10
c11对应googletest/gtest 经过测试,c11对应版本是googletest v1.10.x 编译安装 编译环境 sudo apt-get update sudo apt-get install -y build-essential cmake下载或git clone代码 git clone https://github.com/google/googletest.git cd googletest git che…...

20250306-笔记-精读class CVRPEnv:step(self, selected)
文章目录 前言一、时间步小于 41.1 控制时间步的递增1.2 判断是否在配送中心1.3 特定时间步的操作1.4更新1.4.1 更新当前节点和已选择节点列表1.4.2 更新需求和负载1.4.3 更新访问标记1.4.4 更新负无穷掩码1.4.5 更新步骤状态,将更新后的状态同步到 self.step_state…...
文档进行embedding,Faiss向量检索
这里采用Langchain的HuggingFaceEmbeddings 参照博主,改了一些东西,因为Langchain0.3在0.2的基础上进行了一定的修改 from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings …...

一周学会Flask3 Python Web开发-在模板中渲染WTForms表单视图函数里获取表单数据
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 为了能够在模板中渲染表单,我们需要把表单类实例传入模板。首先在视图函数里实例化表单类LoginForm,然…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...