本文是对 2022.04.16 双周赛的回顾
LeetCode6060. 找到最接近 0 的数字
#数组
题目描述
给你一个长度为
n
的整数数组nums
,请你返回nums
中最 接近0
的数字。如果有多个答案,请你返回它们中的 最大值 。
1 | 示例 1: |
解题思路
(1). 先排序数组,然后看数组是否全体 大于等于 0 或者 小于等于 0,是的话就直接输出答案了;
(2). 否则一次遍历数组,用一个变量记录最大的负数,当遍历到 0
,直接输出 0
,如果遍历到第一个正数,则比较最大的负数和最小的正数谁距离 0
更近。
时间复杂度
O(Nlog(N))
解题代码
1 | func findClosestNumber(nums []int) int { |
LeetCode6061. 买钢笔和铅笔的方案数
#动态规划 #枚举
题目描述
给你一个整数 total ,表示你拥有的总钱数。同时给你两个整数 cost1 和 cost2 ,分别表示一支钢笔和一支铅笔的价格。你可以花费你部分或者全部的钱,去买任意数目的两种笔。
请你返回购买钢笔和铅笔的 不同方案数目 。
1 | 示例 1: |
解题思路
(1). 仔细观察示例的解题过程,是通过枚举钢笔的数量来确定铅笔可能的数量,那么我们也可以使用枚举的方式来判断;
(2). 那么怎样能够快速的枚举呢?可以先通过动态规划,确定在总金额不变的情况下,全部用来买钢笔或铅笔能够最多买多少支;
(3). 在枚举钢笔数量的时候,剩余的钱全都可以用来购买铅笔,那么总方案数就可以根据这两者来确定。
时间复杂度
O(N)
解题代码
1 | func waysToBuyPensPencils(total int, cost1 int, cost2 int) int64 { |
LeetCode6062. 设计一个 ATM 机器
#模拟 #贪心
题目描述
一个 ATM 机器,存有 5 种面值的钞票:20 ,50 ,100 ,200 和 500 美元。初始时,ATM 机是空的。用户可以用它存或者取任意数目的钱。
取款时,机器会优先取 较大 数额的钱。
- 比方说,你想取 $300 ,并且机器里有 2 张 $50 的钞票,1 张 $100 的钞票和1 张 $200 的钞票,那么机器会取出 $100 和 $200 的钞票。
- 但是,如果你想取 $600 ,机器里有 3 张 $200 的钞票和1 张 $500 的钞票,那么取款请求会被拒绝,因为机器会先取出 $500 的钞票,然后无法取出剩余的 $100 。注意,因为有 $500 钞票的存在,机器 不能 取 $200 的钞票。
请你实现 ATM 类:
- ATM() 初始化 ATM 对象。
- void deposit(int[] banknotesCount) 分别存入 $20 ,$50,$100,$200 和 $500 钞票的数目。
- int[] withdraw(int amount) 返回一个长度为 5 的数组,分别表示 $20 ,$50,$100 ,$200 和 $500 钞票的数目,并且更新 ATM 机里取款后钞票的剩余数量。如果无法取出指定数额的钱,请返回 [-1] (这种情况下 不 取出任何钞票)。
1 | 示例 1: |
解题思路
(1). 首先我们构建 ATM
类,这个类需要什么元素呢?
- 首先需要一个数组
paperAmount
来保存所有的钞票面额 - 一个
map
来记录对应面额的数量 - 一个变量记录总金额
- 一个变量记录最大面额对应的
paperAmount
数组中的索引号
(2). 对于Deposit
方法,每次更新对应的元素即可;
(3). 令输出为ret
,首先看银行内总金额是否能支持amount
数额的兑取,然后ret
是一个长度为5
的数组,用于保存各类型钞票的数量;
(4). 对于Withdraw
方法,先看是否有对应的面额正好是amount
的值,如果是的话直接取出;否则就要看最大面额的钞票是否超过了amount
,如果没有超过,则必须从最大面额中先取出,为了避免超时,这里需要尽可能的将能用最大面额 cover 的部分全部取出来;如果超过了,那么就从次大的面额到最小面额依次比对,直到能满足要求;
(5). 如果没有任何面额能够满足剩余金额的要求,那么只能证明无法取出这个amount
对应的钞票,要将之前取出来的钞票重新存进银行,那么就要调用Deposit
方法,将ret
数组存入银行。
解题代码
1 | type ATM struct { |
LeetCode6063. 节点序列的最大得分
#图 #枚举
题目描述
给你一个 n 个节点的 无向图 ,节点编号为 0 到 n - 1 。
给你一个下标从 0 开始的整数数组 scores ,其中 scores[i] 是第 i 个节点的分数。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] ,表示节点 ai 和 bi 之间有一条 无向 边。
一个合法的节点序列如果满足以下条件,我们称它是 合法的 :
- 序列中每 相邻 节点之间有边相连。
- 序列中没有节点出现超过一次。
节点序列的分数定义为序列中节点分数之 和 。
请你返回一个长度为4
的合法节点序列的最大分数。如果不存在这样的序列,请你返回-1
。
1 | 示例 1: |
1 | 输入:scores = [5,2,9,8,4], edges = [[0,1],[1,2],[2,3],[0,2],[1,3],[2,4]] |
1 | 示例 2: |
1 | 输入:scores = [9,20,6,4,11,12], edges = [[0,3],[5,3],[2,4],[1,3]] |
解题思路
(1). 试试枚举可不可以。(做题时优先考虑最简单的算法)枚举谁呢?可以枚举点,也可以枚举边;
(2). 简化问题可以帮助我们找到思路。如果序列只要求 33 个点,要如何枚举?只要求 33 个点的话,可以枚举端点,也可以枚举中间的点;
(3). 枚举中间的点是最方便的,算出与其相邻的分数最大的两个点即可。这意味着枚举中间的相比枚举两边的要更好写,效率也更高。顺着这个思路去思考原问题;
(4). 设序列为 a−x−y−b
(−
表示边),枚举 edges
中的每条边,作为序列正中间的那条边,即 x−y
;
(5). 我们需要把与 x
相邻的点中,分数最大且不同于 y
和 b
的点作为 a
;把与 y
相邻的点中,分数最大且不同于 x
和 a
的点作为 b
;
(6). 与 x
相邻的点中,由于只需要与 y
和 b
不一样,我们仅需要保留分数最大的三个点,a
必定在这三个点中;
(7). 剩下要做的,就是在枚举 edges
前,预处理出这三个点。代码实现时,可以用排序、堆、分治(nth_element)或者手动维护求前三大。最优的时间复杂度为 O(n+m)
。
解题代码
1 | func maximumScore(scores []int, edges [][]int) int { |
- Post title:早起刷题(Day 15)
- Post author:洪笳淏
- Create time:2022-04-17 17:25:00
- Post link:https://jiahaohong1997.github.io/2022/04/17/早起刷题(Day 15)/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.