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

每日算法-250424

每日算法打卡 (24/04/25) - LeetCode 2971 & 1647

记录一下今天解决的两道 LeetCode 题目


2971. 找到最大周长的多边形

题目

Problem 2971 Description

思路

贪心

一个基本的多边形构成条件是:最长边必须小于其他所有边的长度之和
为了找到周长最大的多边形,我们应该尽可能地包含更多的边。因此,一个自然的贪心策略是先将所有可能的边长进行排序。

解题过程

  1. 排序:将边长数组 nums 从小到大排序。这是贪心策略的基础,方便我们从小到大尝试构建多边形。
  2. 遍历与累加:我们维护一个当前边长之和 sum。从最短的边开始累加。
  3. 判断合法性:当我们考虑加入第 i 条边 (长度为 nums[i]) 时,需要检查之前所有边的和 sum (即 nums[0] + ... + nums[i-1]) 是否大于 nums[i]
    • 根据多边形构成条件,如果 sum > nums[i],那么以 nums[i] 作为最长边,加上之前 i 条边(总共 i+1 条边)可以构成一个合法的多边形。其周长为 sum + nums[i]。因为我们希望周长尽可能大(包含尽可能多的边),所以我们记录下这个合法的周长。
    • 如果 sum <= nums[i],则无法以 nums[i] 作为最长边构成多边形。
  4. 更新最大周长:我们用一个变量 maxPerimeter 来记录遍历过程中遇到的最大合法周长。只有当 sum > nums[i] 时,我们才更新 maxPerimeter = sum + nums[i]
  5. 继续累加:无论当前 nums[i] 能否构成合法多边形,我们都将其加入 sum (sum += nums[i]),以便为后续判断更长的边做准备。
  6. 初始条件与返回:多边形至少需要3条边。我们从数组的第三个元素(索引 i = 2)开始检查。如果遍历结束后,maxPerimeter 仍然是初始值(例如 0 或 -1,表示从未找到合法的多边形),则返回 -1。否则,返回 maxPerimeter
  • 代码细节
    • sum 在代码中实际上是 nums[0] + ... + nums[i] 的前缀和。
    • trueSum 对应我们上面说的 maxPerimeter
    • index 在代码中记录的是构成最大周长多边形的最长边的索引。检查 index < 2 等价于检查是否找到了至少一个包含3条边的合法多边形(因为 index 初始为1,只有当 i=2 时满足条件,index 才会更新为2)。

复杂度

  • 时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN),主要是排序数组 nums 的时间。遍历数组需要 O ( N ) O(N) O(N)
  • 空间复杂度: O ( log ⁡ N ) O(\log N) O(logN) O ( N ) O(N) O(N),取决于排序算法使用的栈空间。如果忽略排序的辅助空间(或视为原地排序),则为 O ( 1 ) O(1) O(1)

Code

class Solution {public long largestPerimeter(int[] nums) {Arrays.sort(nums);long sum = nums[0] + nums[1];long trueSum = 0;int index = 1;for (int i = 2; i < nums.length; i++) {if (sum <= nums[i]) {sum += nums[i];} else {index = i;sum += nums[i];trueSum = sum;}}return index < 2 ? -1 : trueSum;}
}

1647. 字符频次唯一的最小删除次数

题目

Problem 1647 Description

思路

贪心

目标是最小化删除次数,使得所有存在字符的频次都是唯一的。
我们可以先统计每个字符的出现频次。为了方便处理冲突(频次相同),一个好的策略是处理排序后的频次。

解题过程

  1. 统计频次:使用一个数组(大小为26)统计字符串 s 中每个字符 (‘a’ 到 ‘z’) 的出现次数。
  2. 排序频次:将得到的频次(只考虑大于0的频次,或者处理整个频次数组)进行升序排序。
  3. 处理冲突(贪心):从后往前(即从最大的频次开始)遍历排序后的频次数组 hash
    • 我们检查当前频次 hash[i] 是否大于等于它前一个的频次 hash[i-1]
    • 如果 hash[i] <= hash[i-1],说明出现了频次冲突或者顺序不对(因为已经排序了,所以只会是相等的情况)。我们需要减少 hash[i-1]的值,使其严格小于 hash[i]
    • 贪心选择:为了最小化删除次数,我们将冲突的频次 hash[i-1] 减少到 max(0, hash[i] - 1)。这样既保证了唯一性,又使得减少的量(即删除的字符数)最少。
    • 累加删除次数:将原始频次与修改后频次之差累加到总删除次数 count 中。
    • 注意:修改后的频次 hash[i-1]必须大于等于 0。如果目标值 hash[i] - 1小于 0,则必须将当前频次降为 0,删除次数就是其原始值。
  4. 返回结果:遍历完成后,count 即为所需的最小删除次数。

复杂度

  • 时间复杂度: O ( N + K log ⁡ K + K ) = O ( N ) O(N + K \log K + K) = O(N) O(N+KlogK+K)=O(N)
    • O ( N ) O(N) O(N) 用于遍历字符串统计频次 (N 为字符串长度)。
    • O ( K log ⁡ K ) O(K \log K) O(KlogK) 用于排序频次数组 (K 为字符集大小,这里是 26,是常数)。
    • O ( K ) O(K) O(K) 用于遍历频次数组处理冲突。
    • 因为 K 是常数 (26),所以 K log ⁡ K K \log K KlogK K K K 都是 O ( 1 ) O(1) O(1)。因此,总时间复杂度由 O ( N ) O(N) O(N) 主导。
  • 空间复杂度: O ( K ) = O ( 1 ) O(K) = O(1) O(K)=O(1)
    • 需要一个大小为 K (26) 的数组来存储频次。

Code

class Solution {public int minDeletions(String ss) {char[] s = ss.toCharArray();int[] hash = new int[26];for (char c : s) {hash[c - 'a']++;}Arrays.sort(hash);int count = 0;for (int i = 24; i >= 0; i--) {if (hash[i] == 0) {break;}if (hash[i] >= hash[i + 1]) {count += (hash[i + 1] - 1) <= 0 ? hash[i] : hash[i] - (hash[i + 1] - 1);hash[i] = Math.max((hash[i + 1] - 1), 0);}}return count;}
}

相关文章:

  • 黑客密码:解锁互联网提问的智慧密码
  • 解决NSMutableData appendData性能开销太大的问题
  • Linux命令行基础入门详解
  • 09前端项目----分页功能
  • 通过监督微调(SFT)提升AI Agent效果的完整指南
  • 2025年3月电子学会青少年机器人技术(五级)等级考试试卷-实际操作
  • 小刚说C语言刷题——1317正多边形每个内角的度数?
  • 项目班——0419——chrono时间库
  • Redis 与 Memcache 全面对比:功能、性能与应用场景解析
  • mysql——索引事务和JDBC编程
  • 项目——高并发内存池
  • RHCE练习1
  • C语言——函数
  • Spring Security认证流程
  • nacos配置springboot配置信息,并且集成金仓数据库
  • 精选面试题
  • 【解决】Android Gradle Sync 报错 Could not read workspace metadata
  • 程序员鱼皮最新项目-----AI超级智能体教程(一)
  • 04-stm32的标准外设库
  • 【C语言】C语言动态内存管理
  • 迎接神十九乘组回家,东风着陆场各项工作已准备就绪
  • 涉军民事案件类型日益增多,最高法新规明晰管辖争议问题
  • 孙燕姿演唱会本周末开唱,小票根如何在上海释放大活力
  • 韩国检方以受贿嫌疑起诉前总统文在寅
  • 解放日报:上海一季度GDP同比增长5.1%,两大新动能助推经济“开门红”
  • 冒充县领导亲戚十年骗取38箱香菇木耳,河南一男子被判拘役