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

每日算法-250526

每日算法学习记录 - 25.05.26

今天记录两道完成的算法题,分享一下解题思路和代码。


面试题 16.24. 数对和

题目描述:
题目图片
设计一个算法,找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。

💡 思路

排序 + 双指针

⚙️ 解题过程

这个问题要求我们找出数组中所有和为 target 的数对,并且每个数字只能使用一次。

  1. 排序:首先对数组进行排序。这样做的目的是便于我们使用双指针法,从两端向中间查找。
  2. 双指针
    • 初始化左指针 left 指向数组的开头(索引 0)。
    • 初始化右指针 right 指向数组的末尾(索引 nums.length - 1)。
  3. 遍历和判断
    • left < right 时,持续迭代:
      • 计算当前左右指针指向的两个数 num1 = nums[left]num2 = nums[right] 的和 currentSum = num1 + num2
      • 如果 currentSum == target:找到了一个数对。将 (num1, num2) 加入结果列表。因为每个数只能用一次,所以两个指针都需要移动,left++ 并且 right--,以寻找下一对可能的数对。
      • 如果 currentSum < target:说明当前和太小了,需要增大和。由于数组已排序,左边的数较小,右边的数较大,所以应将左指针 left++ 向右移动,尝试一个更大的 num1
      • 如果 currentSum > target:说明当前和太大了,需要减小和。应将右指针 right-- 向左移动,尝试一个更小的 num2
  4. 返回结果:当 left >= right 时,遍历结束,返回收集到的所有数对。

📈 复杂度

  • 时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN)
    • Arrays.sort(nums) 需要 O ( N log ⁡ N ) O(N \log N) O(NlogN) 时间。
    • 双指针遍历本身需要 O ( N ) O(N) O(N) 时间。
    • 因此,总时间复杂度由排序决定。
  • 空间复杂度: O ( log ⁡ N ) O(\log N) O(logN) O ( N ) O(N) O(N) (取决于排序算法的实现)

💻 Code

class Solution {public List<List<Integer>> pairSums(int[] nums, int target) {// 1. 排序数组Arrays.sort(nums);List<List<Integer>> resultPairs = new ArrayList<>();int left = 0;int right = nums.length - 1;// 2. 双指针遍历while (left < right) {int num1 = nums[left];int num2 = nums[right];int currentSum = num1 + num2;if (currentSum == target) {// 找到了一个数对resultPairs.add(Arrays.asList(num1, num2));// 移动双指针,继续寻找其他数对left++;right--;} else if (currentSum < target) {// 和太小,移动左指针left++;} else {// 和太大,移动右指针right--;}}return resultPairs;}
}

3371. 识别数组中的最大异常值

题目描述:
题目图片
给你一个整数数组 nums。数组中唯一一个不是众数的数字被称为「异常值」。数组的其余所有数字都是相等的「特殊数字」。请你返回「异常值」。

💡 思路

哈希表计数 + 数学推导/枚举

⚙️ 解题过程

题目指出,数组中有一个 “异常值”,其余所有数字都是相等的 “特殊数字”。设特殊数字的值为 s,异常值为 o。如果数组长度为 N,那么有 N-1s1o
数组总和 totalSum = (N-1) * s + o

  1. 预处理
    • 计算数组 nums 中所有元素的总和 sum
    • 使用哈希表 map 存储每个数字及其出现的次数。
  2. 枚举与验证
    • 初始化一个结果变量 ret 为一个足够小的值。
    • 遍历数组中的每一个数 candidateS。我们假设这个 candidateS 就是那个 “特殊数字” s
    • 根据公式 2s + o = sum (其中 scandidateSoexceptionVal),可以推导出潜在的异常值 exceptionVal = sum - 2 * candidateS
  3. 判断与更新
    • 检查计算出的 exceptionVal 是否存在于数组中。
    • 如果 exceptionVal 存在:
      • 情况一:exceptionVal == candidateS
        • 这意味着推断出的异常值和我们假设的特殊数字是同一个值。
        • 此时,要满足 "两个特殊数字 candidateS 和一个异常值 exceptionVal,这确保了至少有两个这样的数字。map.get(candidateS) > 1 是一个必要的条件,确保我们能取出 candidateS 作为特殊值,同时 exceptionVal (也等于 candidateS) 也能在数组中找到。
        • 如果条件满足,更新 ret = Math.max(ret, exceptionVal)
      • 情况二:exceptionVal != candidateS
        • 这意味着异常值和特殊数字是不同的。
        • 我们假设的 candidateS 是特殊数字,exceptionVal 是异常值。
        • 我们只需要 exceptionVal 存在于数组中即可(已通过 map.containsKey(exceptionVal) 检查)。同时,candidateS 作为特殊数字也必须存在 (我们是从 nums 中选取的,所以它肯定存在)。
        • 如果条件满足,更新 ret = Math.max(ret, exceptionVal)
  4. 返回结果:遍历结束后,ret 中存储的就是找到的最大的符合条件的异常值。

📈 复杂度

  • 时间复杂度: O ( N ) O(N) O(N)
    • 计算总和和构建哈希表需要 O ( N ) O(N) O(N) 时间。
    • 遍历数组(或哈希表的键集,最坏情况 N N N 个不同元素)进行检查,每次哈希表操作为 O ( 1 ) O(1) O(1) 平均时间。总共是 O ( N ) O(N) O(N)
  • 空间复杂度: O ( N ) O(N) O(N)
    • 哈希表在最坏情况下可能需要存储 N N N 个不同的数。

💻 Code

class Solution {public int getLargestOutlier(int[] nums) {int largestOutlier = -2001; Map<Integer, Integer> counts = new HashMap<>();long totalSum = 0; for (int x : nums) {totalSum += x;counts.put(x, counts.getOrDefault(x, 0) + 1);}for (int specialNumCandidate : nums) { int potentialOutlier = (int) (totalSum - 2 * (long)specialNumCandidate);if (counts.containsKey(potentialOutlier)) {if (potentialOutlier == specialNumCandidate) {if (counts.get(potentialOutlier) > 1) {largestOutlier = Math.max(largestOutlier, potentialOutlier);}} else {largestOutlier = Math.max(largestOutlier, potentialOutlier);}}}return largestOutlier;}
}

http://www.xdnf.cn/news/654589.html

相关文章:

  • GitLab 18.0 正式发布,15.0 将不再受技术支持,须升级【三】
  • 消防营区管理升级:豪越科技智能仓储与装备管理的力量
  • 【Java项目测试报告】:在线音乐平台(Online-Music)
  • 开发过的一个Coding项目
  • top查看 CPU使用情况
  • 【Java学习笔记】单例设计模式
  • C++23 std::start_lifetime_as:用于隐式生存期类型的显式生存期管理函数 (P2590R2)
  • Java网络编程中的I/O操作:从字节流到对象序列化
  • DJI上云API官方demo学习
  • JavaSE核心知识点04工具04-01(JDK21)
  • 【opencv】vs2019中配置opencv
  • 同一个核磁共振(MRI)检查中,不同序列的图像之间空间坐标定位如何实现
  • Redis | 缓存技术对后端的重要性
  • STM32之SPI——外部FLASH和RFID
  • 宫格导航--纯血鸿蒙组件库AUI
  • 树莓派超全系列教程文档--(47)如何使用内核补丁
  • QT中常用的类
  • Cesium 实战 26 - 自定义纹理材质 - 实际应用之飞线(抛物线)
  • 并发的产生及对应的解决方案之服务架构说明
  • 第1章第1节:安全运维基础思维与体系建设-安全运维的定义与核心目标
  • Ext系列文件系统
  • 分布式缓存:证明分布式系统的 CAP 理论
  • [闲谈]C语言的面向对象
  • 易境通WMS系统:赋能快消品海外仓高效管理
  • 完美解决Docker镜像无法拉取问题(转载)
  • 服务器的IP是什么东西?
  • uniapp-商城-69-shop(2-商品列表,点击商品展示,商品的详情, vuex的使用,rich-text使用)
  • ESP8266_AP机械手 第三篇Uniapp遥控器
  • ElasticSearch--DSL查询语句
  • 信创 CDC 实战 | OGG、Attunity……之后,信创数据库实时同步链路如何构建?(以 GaussDB 数据入仓为例)