Leetcode 第 110 场双周赛 Problem D 2809. 使数组和小于等于 x 的最少时间(DP+贪心+正难则反)

  • Leetcode 第 110 场双周赛 Problem D 2809. 使数组和小于等于 x 的最少时间(DP 好题)
  • 题目
    • 给你两个长度相等下标从 0 开始的整数数组 nums1 和 nums2 。每一秒,对于所有下标 0 <= i < nums1.length ,nums1[i] 的值都增加 nums2[i] 。操作 完成后 ,你可以进行如下操作:
      • 选择任一满足 0 <= i < nums1.length 的下标 i ,并使 nums1[i] = 0 。
    • 同时给你一个整数 x 。
    • 请你返回使 nums1 中所有元素之和 小于等于 x 所需要的 最少 时间,如果无法实现,那么返回 -1 。
    • 1 <= nums1.length <= 10 ^ 3
    • 1 <= nums1[i] <= 10 ^ 3
    • 0 <= nums2[i] <= 10 ^ 3
    • nums1.length == nums2.length
    • 0 <= x <= 10 ^ 6
  • 解法
    • DP+贪心+正难则反:
    • 第 1 步:
    • 每个 nums1[i] 置为 0,超过一次不如仅最后一次置为 0,
    • 可知对于 nums1[i] 一样大,且不会影响其他 nums1,
    • 因此时间最多就是 nums1.len、超过则无意义,
    • 第 2 步:
    • 问题转化为经过最少 s 秒且 s <= nums1.len,使得 nums3 = nums2[x]*(s-1) + nums2[y]*(s-2) + … + nums2[z]*0 + nums1[a] + …,nums3.len = nums1.len
    • nums3 总和 sum(nums3) 小于等于 x 时,最小的 s 就是答案,否则答案就是 -1,
    • 同时不可能推出 s 单调性,因此无法二分答案,
    • 第 3 步:
    • 正面直接求最小值无法想到什么贪心策略,如果使用 DP 则第 j+1 秒会影响前 j 秒的数据,因为每秒每个元素会加上 nums2,不满足无后效性
    • 正难则反:
      • 求经过 s 秒最多可以减少多少
      • 总数 sum(nums1) + s*sum(nums2) 减去即可
    • 第 4 步:
    • 动规状态:dp[i][j] 为前 i 个数经过 j 秒最多可以减少多少,注意 i>=j,
    • 初始化 dp[i][0]=0,即前 i 个数不经过任何时间则无法减少
    • 第 5 步
    • 转移方程:dp[i][j]=max(dp[i-1][j], dp[i-1][j-1] + nums1[i-1]+j*nums2[i-1]),
      • 即第 i 个数经过 j 秒是否删除的最大值,取决于是否需要再第 j 秒清理掉第 i 个元素
      • 此时 DP 无后效性,因为第 i+1 个数不会影响前 i 个数的更新,
      • 同时需要满足减少 j 个元素的最大值、等于减少前(i-1 个元素中选 j-1 个元素)的最大值加第 i 个元素,
      • 可以观察减少的是 nums1[i-1]+j*nums2[i-1],由于前 j 秒等价于选 j 个元素,此时 nums1 顺序无所谓,j 固定升序、保证 j*nums2[i-1] 最大需要使 nums2 升序(nums1 跟随排序)
    • 第 6 步:
    • 最后结果就是枚举秒数 j=[0,nums1.len],sum(nums1) + j * sum(nums2) - dp[nums1.len][j] <= x,找到最小的 j,没有则返回 -1
    • 空间压缩:由于 dp[i][j] 仅与 dp[i-1][j]、dp[i-1][j-1] 有关,因此可以使用一维 dp[j] 倒序处理
    • 时间复杂度:O(n ^ 2),空间复杂度:O(n)
  • 代码
/*** DP+贪心+正难则反:** 第 1 步:* 每个 nums1[i] 置为 0,超过一次不如仅最后一次置为 0,* 可知对于 nums1[i] 一样大,且不会影响其他 nums1,* 因此时间最多就是 nums1.len、超过则无意义,** 第 2 步:* 问题转化为经过最少 s 秒且 s <= nums1.len,使得 nums3 = nums2[x]*(s-1) + nums2[y]*(s-2) + ... + nums2[z]*0 + nums1[a] + ...,nums3.len = nums1.len* nums3 总和 sum(nums3) 小于等于 x 时,最小的 s 就是答案,否则答案就是 -1,* 同时不可能推出 s 单调性,因此无法二分答案,** 第 3 步:* 正面直接求最小值无法想到什么贪心策略,如果使用 DP 则第 j+1 秒会影响前 j 秒的数据,因为每秒每个元素会加上 nums2,**不满足无后效性**,* 正难则反:*     * 求经过 s 秒最多可以减少多少*     * 总数 sum(nums1) + s*sum(nums2) 减去即可** 第 4 步:* 动规状态:dp[i][j] 为前 i 个数经过 j 秒最多可以减少多少,注意 i>=j,* 初始化 dp[i][0]=0,即前 i 个数不经过任何时间则无法减少** **第 5 步**:* 转移方程:dp[i][j]=max(dp[i-1][j], dp[i-1][j-1] + nums1[i-1]+j*nums2[i-1]),*     * 即第 i 个数经过 j 秒是否删除的最大值,取决于是否需要再第 j 秒清理掉第 i 个元素*     * **此时 DP 无后效性**,因为第 i+1 个数不会影响前 i 个数的更新,*     * 同时需要满足减少 j 个元素的最大值、等于减少前(i-1 个元素中选 j-1 个元素)的最大值加第 i 个元素,*     * 可以观察减少的是 nums1[i-1]+j*nums2[i-1],由于前 j 秒等价于选 j 个元素,此时 nums1 顺序无所谓,**j 固定升序、保证 j*nums2[i-1] 最大需要使 nums2 升序(nums1 跟随排序)**** 第 6 步:* 最后结果就是枚举秒数 j=[0,nums1.len],sum(nums1) + j * sum(nums2) - dp[nums1.len][j] <= x,找到最小的 j,没有则返回 -1* 空间压缩:由于 dp[i][j] 仅与 dp[i-1][j]、dp[i-1][j-1] 有关,因此可以使用一维 dp[j] 倒序处理* 时间复杂度:O(n ^ 2),空间复杂度:O(n)*/public int minimumTime(List<Integer> nums1, List<Integer> nums2, int x) {// 判空与异常if (nums1 == null || nums2 == null || nums1.size() != nums2.size() || nums1.size() <= 0) {return -1;}int n = nums1.size();// 求总和int sumNums1 = nums1.stream().mapToInt(Integer::intValue).sum();int sumNums2 = nums2.stream().mapToInt(Integer::intValue).sum();
//        System.out.println(sumNums1);
//        System.out.println(sumNums2);// j 固定升序、保证 j*nums2[i-1] 最大需要使 nums2 升序(nums1 跟随排序)List<Pair<Integer, Integer>> numsPair = new ArrayList<>(n);for (int i = 0; i < n; i++) {numsPair.add(new Pair<>(nums2.get(i), nums1.get(i)));}Collections.sort(numsPair, (o1, o2) -> o1.getKey() - o2.getKey());
//        System.out.println(numsPair);// 动规状态:dp[i][j] 为前 i 个数经过 j 秒最多可以减少多少,注意 i>=j,初始化 dp[i][0]=0,即前 i 个数不经过任何时间则无法减少,空间压缩掉 iint[] dp = new int[n + 1];// 转移方程:dp[i][j]=max(dp[i-1][j], dp[i-1][j-1] + nums1[i-1]+j*nums2[i-1]),for (int i = 1; i < n + 1; i++) {// 空间压缩,一维 dp[j] 倒序处理for (int j = i; j >=1; j--) {dp[j] = Math.max(dp[j], dp[j-1] + numsPair.get(i-1).getValue() + j * numsPair.get(i-1).getKey());}}
//        AlgorithmUtils.systemOutArray(dp);int res = -1;// 枚举秒数 j=[0,nums1.len],sum(nums1) + j * sum(nums2) - dp[nums1.len][j] <= x,找到最小的 j,没有则返回 -1for (int j = 0; j <= n; j++) {if (sumNums1 + j * sumNums2 - dp[j] <= x) {res = j;break;}}return res;}

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

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

相关文章

supervisor管理python进程

前言 平时开发调试中使用conda环境&#xff0c;项目比较多环境多&#xff0c;而且命令繁杂&#xff0c;每一次启动项目都可能会因为忘记启动方式而频繁报错。现在可以通过supervisor来管理&#xff0c;只需要配置几个文件&#xff0c;就可以轻松通过简单一致的命令启动工程&…

C++ day55 判断子序列 不同的子序列

题目1&#xff1a;392 判断子序列 题目链接&#xff1a;判断子序列 对题目的理解 判断字符串s是否为t的子序列 字符串s和字符串t的长度大于等于0&#xff0c;字符串s的长度小于等于字符串t的长度&#xff0c;本题其实和最长公共子序列的那道题很相似&#xff0c;相当于找两…

HashMap相关专题

前置知识&#xff1a;异或运算 异或运算介绍 异或有什么神奇之处&#xff08;应用&#xff09;&#xff1f; &#xff08;1&#xff09;快速比较两个值 &#xff08;2&#xff09;我们可以使用异或来使某些特定的位翻转&#xff0c;因为不管是0或者是1与1做异或将得到原值的相…

IntelliJ IDEA 2023.2新特性详解第三弹!Docker、Kubernetes等支持!

9 Docker 在 Docker 镜像层内预览文件 现在可以在 Services&#xff08;服务&#xff09;工具窗口中轻松访问和预览 Docker 镜像层的内容。 从列表选择镜像&#xff0c;选择 Show layers&#xff08;显示层&#xff09;&#xff0c;然后点击 Analyze image for more informati…

ES6对象

1.对象简写 ES6中规定可以直接在对象中写入变量和函数作为对象的属性和方法&#xff0c;此时属性名为变量名, 属性值为变量的值。对象简写在未来的使用频率极其高。 let namelarry;let age12;let obj{name,age,//es5 sayName:function(){}// sayName(){// console.log(t…

<软考>软件设计师-2操作系统(总结)

(一) 进程管理 1 操作系统概述 1-1 操作系统定义: 能有效地组织和管理系统中的各种软/硬件资源&#xff0c;合理地组织计算机系统工作流程&#xff0c;控制程序的执行&#xff0c;并且向用户提供一个良好的工作环境和友好的接口。 1-2 操作系统的作用: 1 通过资源管理提高计…

7+WGCNA+机器学习+实验+泛癌分析,多要素干湿结合

今天给同学们分享一篇生信文章“Analysis and Experimental Validation of Rheumatoid Arthritis Innate Immunity Gene CYFIP2 and Pan-Cancer”&#xff0c;这篇文章发表在Front Immunol期刊上&#xff0c;影响因子为7.3。 结果解读&#xff1a; DEG筛选和数据预处理 数据在…

Helplook VS Google Docs:一对一比较

还记得Google Docs在2006年一炮走红的时候吗&#xff1f;它很大程度地改变了协作方式&#xff0c;也减少了附加文件和频繁保存的麻烦。相比Microsoft Word&#xff0c;很多人更喜欢Google Docs的简单性。 但是时代也在不断地发展。像HelpLook这样的新竞争对手也可以提供先进的…

设计模式总目录

目录 设计模式 1. 创建型模式 1.1 工厂方法模式 1.2 抽象工厂模式 1.3 单例模式 1.4 建造者模式 1.5原型模式 2. 结构型模式 2.1 适配器模式 2.2 装饰器模式 2.3 代理模式 2.4 外观模式 2.5 桥接模式 2.6 组合模式 2.7 享元模式 3. 行为型模式 3.1 策略模式 …

字符集——带你了解UTF-8的前世今生

文章目录 字符集的来历汉字和字母的编码特点Unicode字符集字符集小结编码和解码开发约定 字符集的来历 计算机是美国人发明的&#xff0c;由于计算机能够处理的数据只能是0和1组成的二进制数据&#xff0c;为了让计算机能够处理字符&#xff0c;于是美国人就把他们会用到的每一…

前端面试高频考点—事件循环Event loop

目录 事件循环 执行步骤 概念讲解 主线程 微任务(micro task) 宏任务(macro task) Event Loop经典例题 这段代码的执行结果是什么&#xff1f; 正确答案&#xff1a; 具体流程&#xff1a; 事件循环 主线程从"任务队列"中读取执行事件&#xff0c;这个过程…

通俗讲解分布式锁:场景和使用方法

对于锁大家肯定不会陌生&#xff0c;比如 synchronized 关键字 和 ReentrantLock 可重入锁&#xff0c;一般我们用其在多线程环境中控制对资源的并发访问。但是随着业务的发展&#xff0c;分布式的概念逐渐出现在我们系统中&#xff0c;我们在开发的过程中经常需要进行多个系统…

字符数组和字符串例题

1、相邻字符判相等 题目描述 输入一行字符&#xff08;长度小于等于1000&#xff09;&#xff0c;判断其中是否存在相邻两个字符相同的情形&#xff0c;若有&#xff0c;则输出该相同的字符并结束程序(只需输出第一种相等的字符即可)。否则输出No。 输入要求 输入一行字符&…

File类—递归文件搜索执行脚本文件

文章目录 一、需求分析二、File类2.1 File对象的创建2.2 File判断和获取方法2.3 创建和删除方法2.4 遍历文件夹方法 三、Runtime类—常见api四、递归文件搜索执行脚本文件 一、需求分析 在本篇博客中&#xff0c;我们想通过递归文件的方式&#xff0c;在D:\\判断下搜索QQ.exe这…

麒麟V10安装kerberos客户端

麒麟V10系统安装kerberos客户端 当系统具备yum镜像源的时候需要执行安装命令 yum install krb5-devel krb5-client krb5-libs -y 会提示报错 “未找到匹配的参数:krb5-client” 此时我们需要手动安装krb5-client 安装包链接放到了这里 链接: https://pan.baidu.com/s/1x1YVr6…

SQL Server的安装和首个库的创建

一、熟悉SQL Server的安装环境&#xff1b; 1.安装Microsoft的数据库管理系统SQL Server 2022 先把SQL Server 2022下载好后进行解压后出现以下界面然后点击基本进行安装 然后会出现以下界面&#xff1a; 一步步按照提示往下走即可&#xff0c;把SQL Server 2022安装完成后再…

【1day】Panabit 日志系统openid接口SQL注入漏洞

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、资产测绘 三、资产测绘 四、漏洞复现

Leetcode刷题笔记题解(C++):LCR 021. 删除链表的倒数第 N 个结点

思路&#xff1a;用双指针去遍历链表&#xff0c;删除left的下一个节点&#xff0c;注意的是n大于等于链表长度即删除第一个节点 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {…

tmux简单使用

它允许你在一个终端窗口中创建多个终端会话&#xff0c;并在它们之间进行切换。以下是tmux的一些主要用途和功能&#xff1a; 多窗口&#xff1a; Tmux允许你在一个终端中创建多个窗口。每个窗口可以包含一个或多个终端会话&#xff0c;你可以轻松地在这些窗口之间切换。面板分…

ifstream读取txt中的中文数据转成QString出现乱码

使用ifstream从txt文本中读取中文数据到string&#xff0c;再将string转成QString输出时出现了乱码。 分析&#xff1a;如果ifstream能成功从txt文本中读出中文数据&#xff0c;那大概率txt用的编码是ANSI编码&#xff08;GBK就是ANSI的一种&#xff09;&#xff0c;那么在转成…