当前位置: 首页 > news >正文

每日算法-250427

每日算法 - 2024年4月27日

记录今天学习和解决的LeetCode算法题。


561. 数组拆分 (Array Partition)

题目描述
Problem 561 Image

思路

贪心

解题过程

问题的目标是最大化 nmin(a_i, b_i) 对的总和。
假设我们有一对数 (a, b)a <= b,那么 min(a, b) = a。为了让总和最大化,我们应该尽可能地让每一对中的较小数 a 尽可能大。

考虑将数组 nums 排序。排序后,我们得到 nums[0] <= nums[1] <= nums[2] <= ... <= nums[2n-1]
如果我们把 nums[0]nums[1] 配对,min(nums[0], nums[1]) = nums[0]
如果我们把 nums[2]nums[3] 配对,min(nums[2], nums[3]) = nums[2]
以此类推,将 nums[2i]nums[2i+1] 配对,min(nums[2i], nums[2i+1]) = nums[2i]

可以证明,这种配对方式(即排序后将相邻元素配对)可以得到最大的 min 值之和。直观地想,如果我们不这样配对,例如将 nums[0]nums[2] 配对,那么 nums[1] 就必须与更大的数配对,这可能会导致 min 值变小。

因此,最优策略是:

  1. 对数组 nums 进行升序排序。
  2. 将排序后数组中下标为偶数(0, 2, 4, …)的元素加起来,即为最终答案。

复杂度

  • 时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN), 主要是排序所需的时间。
  • 空间复杂度: O ( log ⁡ N ) O(\log N) O(logN) or O ( N ) O(N) O(N), 取决于排序算法使用的额外空间(如果是原地排序,可以认为是 O ( 1 ) O(1) O(1),但递归栈可能需要 O ( log ⁡ N ) O(\log N) O(logN))。通常计为 O ( 1 ) O(1) O(1) O ( log ⁡ N ) O(\log N) O(logN)

Code

class Solution {public int arrayPairSum(int[] nums) {Arrays.sort(nums);int n = nums.length;int sum = 0;for (int i = 0; i < n; i += 2) {sum += nums[i];}return sum;}
}

2144. 打折购买糖果的最小开销 (Minimum Cost of Buying Candies With Discount)

题目描述
Problem 2144 Image

思路

贪心

解题过程

我们需要最小化购买糖果的总开销。优惠是“买二送一”,我们可以免费获得一组三个糖果中最便宜的那个。为了最大化优惠力度,我们应该让免费赠送的糖果尽可能昂贵。

贪心策略:

  1. 将所有糖果按价格 cost 升序排序。
  2. 从最贵的糖果开始考虑。每次选择当前最贵的三个糖果组成一组。
  3. 在这一组中,我们支付价格最高和第二高的糖果的费用,价格第三高的糖果(也就是这一组里最便宜的)则免费获得。
  4. 重复这个过程,直到所有糖果都被处理完。

具体实现:

  1. cost 数组进行排序。
  2. 从数组末尾(最贵的糖果)开始,每三个元素为一组进行处理 (i = n-1, n-2, n-3, 然后 i = n-4, n-5, n-6, …)。
  3. 在每组 (cost[i], cost[i-1], cost[i-2]) 中,我们将 cost[i]cost[i-1] 加入总开销 sum,而 cost[i-2] 是免费的,所以跳过。
  4. 注意处理边界情况:如果最后剩余的糖果不足三个(剩一个或两个),那么这些剩余的糖果都需要购买,因为无法触发“买二送一”的优惠。代码中的循环 i -= 3 和判断 i == 0 的情况处理了这一点。

复杂度

  • 时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN), 主要是排序所需的时间。
  • 空间复杂度: O ( log ⁡ N ) O(\log N) O(logN) or O ( N ) O(N) O(N), 取决于排序算法。

Code

class Solution {public int minimumCost(int[] cost) {int n = cost.length;if (n == 1) {return cost[0];} else if (n == 2) {return cost[0] + cost[1];}Arrays.sort(cost);int sum = 0;for (int i = n - 1; i >= 0; i -= 3) {sum += cost[i];if (i > 0) { sum += cost[i - 1]; }}return sum;}
}

3397. 执行操作后不同元素的最大数量 (Maximum Number of Distinct Elements After Operations)

题目描述
Problem 3397 Image

思路

贪心

解题过程

目标是经过操作后,数组中不同元素的数量最大化。每个元素 nums[i] 可以变为 [nums[i] - k, nums[i] + k] 区间内的任意整数。

为了使不同元素的数量尽可能多,我们希望相邻的元素尽可能不同。

贪心策略:

  1. 排序: 首先对数组 nums 进行升序排序。这使得我们可以更容易地处理相邻元素。
  2. 从右往左处理: 我们可以从数组的右端(最大值)开始向左处理。这样做的好处是,当我们决定 nums[i] 的新值时,nums[i+1] 的新值已经确定了,我们可以利用这个信息来最大化 nums[i]nums[i+1] 不同的可能性。
  3. 确定 nums[i] 的新值:
    • 对于 nums[n-1](最大的元素),我们可以将其变为 nums[n-1] + k,使其尽可能大。
    • 对于 nums[i] (i < n-1),我们希望它的新值 nums'[i] 满足:
      • nums[i] - k <= nums'[i] <= nums[i] + k (操作约束)
      • nums'[i] < nums'[i+1] (尽可能与右侧元素不同)
      • 为了给左边的元素 nums[i-1] 留出更多空间,我们希望 nums'[i] 尽可能大,但要小于 nums'[i+1]
    • 因此,nums'[i] 的理想目标是 min(nums[i] + k, nums'[i+1] - 1)
    • 同时,nums'[i] 不能小于 nums[i] - k
    • 所以,最终 nums'[i] = Math.max(nums[i] - k, Math.min(nums[i] + k, nums'[i+1] - 1))
    • 代码中 nums[i] 直接被修改后的值覆盖,x 是原始值 nums[i]ynums[i+1] 修改后的值减 1。
  4. 计数: 在修改 nums[i] 后,检查 nums[i] < nums[i+1] 是否成立。如果成立,说明 ii+1 位置的元素是不同的,计数器 ret 增加。
  5. 结果: 循环结束后,ret 记录了有多少对相邻元素是不同的。不同元素的总数是 ret + 1(因为 n 个元素之间有 n-1 个间隙,ret 个不同间隙意味着 ret+1 个不同的段/元素)。

优化:
如果一个数 x 可以变成 [x-k, x+k] 区间内的数,这个区间的大小是 2k + 1。如果数组中所有 n 个元素都能被分配到不同的值,那么最大不同数就是 n。这种情况在 2k + 1 >= n 时是有可能实现的(即使所有原始 nums[i] 都相同,它们也可以分散成 n 个不同的数,只要可用的范围 2k+1 足够大)。因此,如果 2k + 1 >= n,我们可以直接返回 n

复杂度

  • 时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN), 主要是排序所需的时间。贪心处理过程是 O ( N ) O(N) O(N)
  • 空间复杂度: O ( log ⁡ N ) O(\log N) O(logN) or O ( N ) O(N) O(N), 取决于排序算法。

Code

class Solution {public int maxDistinctElements(int[] nums, int k) {int n = nums.length;if (k * 2 + 1 >= n) {return n;}Arrays.sort(nums);nums[n - 1] += k;int i = n - 2;int ret = 0;while (i >= 0) {int x = nums[i];int y = nums[i + 1] - 1;nums[i] = Math.max(Math.min(x + k, y), x - k);if (nums[i] < nums[i + 1]) {ret++;}i--;}return ret + 1;}
}

相关文章:

  • 【Pandas】pandas DataFrame rtruediv
  • 2025.4.22 JavaScript 常用事件学习笔记
  • 开源财务软件:企业财务数字化转型的有力工具
  • TensorFlow 安装全攻略
  • Shell脚本-until语法结构
  • 香港GPU显卡服务器与GPU云服务器的区别
  • Tomcat的安装与配置
  • 【C++详解】C++入门(二)引用、内联函数、nullptr宏
  • Spark-Streaming核心编程:有状态转化操作与DStream输出
  • 高中数学联赛模拟试题精选第13套几何题
  • 【PyCharm- Python- ArcGIS】:安装一个和 ArcGIS 不冲突的独立 Python让PyCharm 使用 (解决全过程记录)
  • 第1讲、#PyTorch教学环境搭建与Tensor基础操作详解
  • 函数的使用
  • docker compose -p的踩坑经验
  • cached-property - 类属性缓存装饰器
  • 再学GPIO(二)
  • Milvus(8):密集向量、二进制向量、稀疏向量
  • 【Jupyter 启动时如何指定目录】
  • 《C和C++安全编码》课程笔记——第六章 并发
  • C++23 std::move_only_function:一种仅可移动的可调用包装器 (P0288R9)
  • 人社部:我国劳动力市场潜力足,韧性强
  • 中国黄金协会:一季度我国黄金产量同比增1.49%,黄金消费量同比降5.96%
  • 女乘客遭顺风车甩客、深夜丢高速服务区,滴滴霸道回应:赔五百元
  • 如何做大中国拳击产业的蛋糕?这项赛事给出办赛新思考
  • 我国首次发布铁线礁、牛轭礁珊瑚礁“体检”报告,菲炮制言论毫无科学和事实依据
  • 财政部部长:中方主张通过平等对话协商解决贸易和关税争议