贪心与优先队列相结合:如何高效求解最大子序列分数

贪心与优先队列相结合:如何高效求解最大子序列分数

在这篇文章中,我们将详细讲解如何从两个长度相同的数组 nums1nums2 中选择 k 个元素的子序列,从而找到最大子序列分数。这道题目要求我们从 nums1nums2 中分别选择相同索引的 k 个元素,然后计算 nums1 中选定元素的和,并乘以它们在 nums2 中的最小值。最后返回所有可能子序列组合中的最大分数。

题目链接:LeetCode 2542 - 最大子序列的分数


问题分析

1. 题目理解与示例

给定两个相同长度的数组 nums1nums2,目标是选择 k 个元素的子序列,计算这些元素在 nums1 中的和,并乘以它们在 nums2 中的最小值,最后找到所有可能组合中分数的最大值。

举例说明:

  • 示例 1:

    输入: nums1 = [1,3,3,2], nums2 = [2,1,3,4], k = 3
    输出: 24
    解释: 选择子序列为 [3,3,2],对应 nums2 的最小值为 2,则分数为 (3+3+2)*2 = 24。
    
  • 示例 2:

    输入: nums1 = [4,2,3,1,1], nums2 = [7,5,10,9,6], k = 1
    输出: 30
    解释: 选择 nums1 中的任意一个元素,乘以其对应 nums2 中的值即可得到最大分数。
    
2. 思路分析

为了更好地理解问题,我们需要考虑几个方面:

  1. 如何选择子序列?

    • nums1 中选择 k 个元素,并对应在 nums2 中选择同样索引的元素。
  2. 如何最大化分数?

    • 分数计算为 nums1 选择 元素的和 sum 乘以 nums2 中选定元素的 最小值 min(nums2_selected)
    • 因此,我们希望尽量选择 nums1 中较大的 k 个数,同时选择 nums2 中最小值较大的组合。
  3. 复杂度与优化方向

    • 由于组合数量巨大,使用暴力枚举的方式会超时。我们需要一种高效的策略来筛选组合,从而减少计算量。
3. 常见错误与优化方向

如果使用暴力枚举所有可能的子序列组合,那么复杂度为 O ( ( n k ) ) = n ! k ! ( n − k ) ! O(\binom{n}{k}) = \frac{n!}{k!(n-k)!} O((kn))=k!(nk)!n!,这是指数级别的复杂度,显然不适用于较大的 nk

因此,我们需要考虑使用贪心算法和优先队列(堆)来优化解决方案。


优化解法:贪心 + 优先队列

1. 思路阐述

通过观察题目,我们可以发现以下贪心策略:

  • 我们希望 nums2 中的最小值尽可能大,因为它作为分数计算的乘数,影响最大。
  • 因此,我们可以优先选择 nums2 中较大的元素进行组合,然后在这些组合中选择 nums1 中较大的元素。

为了实现这一策略:

  1. 排序与配对:

    • 首先,我们将 nums1nums2 配对,形成 (nums2[i], nums1[i]) 的对组,然后按照 nums2 的值从大到小进行排序。
    • 这样一来,我们在遍历时,可以保证每次遍历到的 nums2 的值是当前所有未遍历元素中的最大值,从而尽可能增加分数中的乘数值。
  2. 优先队列维护最大 knums1

    • 使用一个优先队列(最小堆)来维护当前 nums1 中的前 k 大元素的和。
    • 当堆中元素数量超过 k 个时,移除堆顶元素(最小值),保证堆中始终包含 k 个最大的 nums1 元素。
  3. 计算分数与更新结果:

    • 每次遍历到 k 个元素时,计算当前组合的分数,即 sum(nums1_selected) * min(nums2_selected)
    • 更新当前的最大分数。
2. 代码实现
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>using namespace std;class Solution {
public:long long maxScore(vector<int>& nums1, vector<int>& nums2, int k) {int n = nums1.size();// 1. 创建配对数组,并按 nums2 从大到小排序vector<pair<int, int>> pairs(n);for (int i = 0; i < n; ++i) {pairs[i] = {nums2[i], nums1[i]};}sort(pairs.rbegin(), pairs.rend()); // 按照 nums2 降序排列// 2. 使用最小堆来维护 nums1 中最大的 k 个数priority_queue<int, vector<int>, greater<int>> minHeap;long long sum = 0, result = 0;// 3. 遍历排序后的数组for (int i = 0; i < n; ++i) {int num1 = pairs[i].second;int num2 = pairs[i].first;// 将当前 num1 加入堆中minHeap.push(num1);sum += num1;// 如果堆中元素超过了 k 个,移除最小的那个if (minHeap.size() > k) {sum -= minHeap.top();minHeap.pop();}// 如果堆中的元素正好是 k 个,计算当前的分数if (minHeap.size() == k) {result = max(result, sum * num2); // 当前 sum * nums2 中的最小值}}return result;}
};
3. 代码详解
  1. 排序操作:

    • nums1nums2 的元素进行配对,生成 (nums2[i], nums1[i]) 的形式,并按照 nums2 的值从大到小进行排序。
    • 排序的时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)
  2. 优先队列维护前 k 大元素:

    • 使用最小堆(优先队列)来维护当前选定的 knums1 元素的和。
    • 每次加入一个新的元素时,如果堆中元素超过 k,则移除堆顶最小元素,以保证堆中是当前最大的 k 个元素。
  3. 分数计算与结果更新:

    • 当堆中元素达到 k 个时,计算当前组合的分数。
    • 分数等于堆中 nums1 元素的和 sum,乘以当前 nums2 中的最小值(因为是按降序排列,所以 nums2 中的最小值就是当前遍历的元素)。
4. 时间复杂度分析
  • 排序: O ( n log ⁡ n ) O(n \log n) O(nlogn)
  • 堆操作: 遍历每个元素并对堆进行插入或删除操作,每次操作的时间复杂度为 O ( log ⁡ k ) O(\log k) O(logk),因此总的时间复杂度为 O ( n log ⁡ k ) O(n \log k) O(nlogk)

总时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn),相对于暴力枚举的指数级复杂度,这种方式显著提升了算法的效率。


示例讲解

示例 1:

输入:nums1 = [1,3,3,2], nums2 = [2,1,3,4], k = 3

  1. 首先,我们对 nums2 从大到小进行排序:

    • 排序后的配对数组为 [(4, 2), (3, 3), (2, 1), (1, 3)]
  2. 使用最小堆维护 k = 3 个最大的 nums1 元素:

    • 第一个配对 (4, 2):加入堆,当前堆为 [2],和为 2,当前最小 nums24,暂时不计算。
    • 第二个配对 (3, 3):加入堆,当前堆为 [2, 3],和为 5,当前最小 nums23,暂时不计算。
    • 第三个配对 (3, 3):加入堆,当前堆为 [2, 3, 3],和为 8,此时堆中有 3 个元素,可以计算分数为 8 * 3 = 24
    • 第四个配对 (2, 1):堆已满,且此时堆顶最小元素为 2,替换后和不变,最终分数为 24

输出:24

示例 2:

输入:nums1 = [4,2,3,1,1], nums2 = [7,5,10,9,6], k = 1

  1. nums2 从大到小排序:

    • 排序后的配对数组为 [(10, 3), (9, 1), (7, 4), (6, 1), (5, 2)]
  2. 使用最小堆维护 k = 1 个最大的 nums1 元素:

    • 第一个配对 (10, 3):堆中元素为 [3],分数为 3 * 10 = 30
    • 后续配对都不比此分数大,最终结果为 30

输出:30

总结

通过贪心策略和优先队列的结合,我们能够高效解决“最大子序列的分数”这一问题。核心思路在于排序 nums2 来优先选择最大乘数,然后通过维护 nums1 中最大和的 k 个数来最大化分数。希望这篇文章能够帮助你深入理解该题目的优化方法和代码实现。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++面试速通宝典——7

150. 数据库连接池的作用 数据库连接池的作用包括以下几个方面&#xff1a; 资源重用&#xff1a;连接池允许多个客户端共享有限的数据库连接&#xff0c;减少频繁创建和销毁连接的开销&#xff0c;从而提高资源的利用率。 统一的连接管理&#xff1a;连接池集中管理数据库连…

python交互式命令时如何清除

在交互模式中使用Python&#xff0c;如果要清屏&#xff0c;可以import os&#xff0c;通过os.system()来调用系统命令clear或者cls来实现清屏。 [python] view plain copy print? >>> import os >>> os.system(clear) 但是此时shell中的状态是&#xff1a;…

Java 面向对象设计一口气讲完![]~( ̄▽ ̄)~*(上)

目录 Java 类实例 Java面向对象设计 - Java类实例 null引用类型 访问类的字段的点表示法 字段的默认初始化 Java 访问级别 Java面向对象设计 - Java访问级别 Java 导入 Java面向对象设计 - Java导入 单类型导入声明 按需导入声明 静态导入声明 例子 Java 方法 J…

msvcp140.dll丢失的解决方法,详细解读6种解决方法

在使用电脑时&#xff0c;我们可能会遇到提示缺少msvcp140.dll的错误信息。这个提示意味着我们的电脑中缺少MSVCP140.dll这个文件&#xff0c;它是某些程序运行所必需的。如果我们遇到这个问题&#xff0c;应该如何解决呢&#xff1f;本文将详细解析如何解决msvcp140.dll丢失的…

Study-Oracle-10-ORALCE19C-RAC集群搭建

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 ORACLE --RAC 搭建理念:准备工作要仔细,每个参数及配置都到仔细核对。环境准备完成后,剩下的就是图像化操作,没啥难度,所以图形化操作偷懒不续写了。 一、硬件信息及配套软件 1、硬件设置 RAC…

springboot系列--web相关知识探索二

一、映射 指的是与请求处理方法关联的URL路径&#xff0c;通过在Spring MVC的控制器类&#xff08;使用RestController注解修饰的类&#xff09;上使用注解&#xff08;如 RequestMapping、GetMapping&#xff09;来指定请求映射路径&#xff0c;可以将不同的HTTP请求映射到相应…

【React】事件机制

事件机制 react 基于浏览器的事件机制自身实现了一套事件机制&#xff0c;称为合成事件。比如&#xff1a;onclick -> onClick 获取原生事件&#xff1a;e.nativeEvent onClick 并不会将事件代理函数绑定到真实的 DOM节点上&#xff0c;而是将所有的事件绑定到结构的最外层…

Mysql数据库约束

前言 数据库是用户数据的最后一道保护屏障&#xff0c;所以数据库存在大量的约束&#xff0c;保证数据库中数据的完整性和可预期性。数据库中&#xff0c;数据类型本身就是一种约束&#xff0c;除此在外还有&#xff1a; null/not null&#xff0c;default&#xff0c; comment…

【大模型 AI 学习】大模型 AI 部署硬件配置方案(本地硬件配置 | 在线GPU)

最近想部署一个开源深度学习项目&#xff0c;但是小编的笔记本电脑是8G的集成显存&#xff0c;且没有GPU&#xff0c;性能肯定是不够的。于是小编在小po站上粗浅了解了一下当前: 1. 大模型 AI本地硬件配置和 2. 云上申请GPU算力的两种方式。简单记录一下&#xff1a; 参考视频…

openEuler 24.03 (LTS) 部署 K8s(v1.31.1) 高可用集群(Kubespray Ansible 方式)

写在前面 实验需要一个 CNI 为 flannel 的 K8s 集群之前有一个 calico 的版本有些旧了,所以国庆部署了一个v1.31.1 版本 3 * master 5 * work时间关系直接用的工具 kubespray博文内容为部署过程以及一些躺坑分享需要科学上网理解不足小伙伴帮忙指正 &#x1f603;,生活加油 99…

Android2024.2.1升级错误

提示 Gradle 版本不兼容&#xff0c;升级后就报错了 。 1.gradle安装包镜像 distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists //distributionUrlhttps\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrlhttps://mirrors.cloud.tencen…

一个月学会Java 第2天 认识类与对象

Day2 认识类与对象 第一章 初识类 经过一个程序的编写&#xff0c;应该对程序的结构有点好奇了吧&#xff0c;如果你有基础&#xff0c;接下来的肯定非常的易懂&#xff0c;如果你没有基础也没有关系&#xff0c;反复琢磨一下也就懂了&#x1f606; 我们来重复一下第一个程序 …

Pikachu-unsafe upfileupload-getimagesize

什么是getimagesize()&#xff1f; getimagesize()是PHP中用于获取图像的大小和格式的函数。它可以返回一个包含图像的宽度、高度、类型和MIME类型的数组。 由于返回的这个类型可以被伪造&#xff0c;如果用这个函数来获取图片类型&#xff0c;从而判断是否时图片的话&#xff…

4.资源《Arduino UNO R3 proteus 电机PID参数整定工程文件(含驱动代码)》说明。

资源链接&#xff1a; Arduino UNO R3 proteus 电机PID参数整定工程文件&#xff08;含驱动代码&#xff09; 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;proteus工程&#xff0c;内含设计图和工程代码。 3.内容展示 4.简述 工程功能可以看这个视频 PID仿真调…

Graphiti:如何让构建知识图谱变得更快、更具动态性?

扩展大语言模型数据提取&#xff1a;挑战、设计决策与解决方案 Graphiti 是一个用于构建和查询动态、时间感知的知识图谱的 Python 库。它可以用于建模复杂、不断演变的数据集&#xff0c;并确保 AI 智能体能够访问它们完成非平凡任务所需的数据。它是一个强大的工具&#xff…

java将word转pdf

总结 建议使用aspose-words转pdf,poi的容易出问题还丑… poi的(多行的下边框就不对了) aspose-words的(基本和word一样) poi工具转换 <!-- 处理PDF --><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres…

【WebGis开发 - Cesium】三维可视化项目教程---视点管理

目录 引言一、基础功能探索1. 镜头视角获取2. 镜头视角移动 二、进一步封装代码1. 封装hooks函数2. 看下效果3. 如何使用该hooks函数 三、总结 引言 本教程主要是围绕Cesium这一开源三维框架开展的可视化项目教程。总结一下相关从业经验&#xff0c;如果有什么疑问或更好的见解…

BM1 反转链表

要求 代码 /*** struct ListNode {* int val;* struct ListNode *next;* };*/ /*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可*** param head ListNode类* return ListNode类*/ struct ListNode* ReverseList(struct …

学习资料库系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;观看记录管理&#xff0c;基础数据管理&#xff0c;论坛信息管理&#xff0c;公告信息管理&#xff0c;轮播图信息 微信端账号功能包括&#xff1a;系统首页&#xff0c;阅读资…

HTB:Ignition[WriteUP]

目录 连接至HTB服务器并启动靶机 1.Which service version is found to be running on port 80? 2.What is the 3-digit HTTP status code returned when you visit http://{machine IP}/? 3.What is the virtual host name the webpage expects to be accessed by? 4.…