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

算法学习记录08——并归的应用(LeetCode[315])

前文算法学习记录07——归并排序的实现与优化

并归的应用(LeetCode[315])

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

归并排序思想的核心思路

归并排序的过程是将数组不断二分,排序后合并。在合并过程中,我们可以同步统计 “右侧小于当前元素的数量”,原因如下:

  • 归并排序处理的是两个已排序的子数组(左半部分 left 和右半部分 right)。
  • 当合并时,若左半部分的元素 left[i] 大于右半部分的元素 right[j],则 right[j] 及 right 中 j 之后的所有元素都小于 left[i](因为 right 已排序),因此可直接统计数量。

举例说明(实在不懂,自己画个图,很好懂的)

假设我们有两个已排序的子数组:​

  • 左子数组 left = [(5, 0), (6, 2)](元素值为 5、6,原始索引为 0、2)​
  • 右子数组 right = [(2, 1), (1, 3)](元素值为 2、1,原始索引为 1、3)​
    注意:这里的右子数组在实际归并过程中已经过排序,正确的有序右子数组应为 right = [(1, 3), (2, 1)](按值从小到大排列)。​

合并过程分析:​

  • 初始化指针 i=0(指向 left[0] = (5, 0)),j=0(指向 right[0] = (1, 3))。​
    • 比较 left[0].值=5 和 right[0].值=1:5 > 1。​
    • 由于 right 是有序的([1, 2]),right[j=0] 之后的所有元素(即 [2])也都小于 5。​
    • 因此,right 中小于 5 的元素数量为 len(right) - j = 2 - 0 = 2(元素 1 和 2)。​
    • 所以 counts[0] += 2(原始索引 0 对应的元素 5,右侧有 2 个更小的元素)。​
  • 移动左指针 i=1(指向 left[1] = (6, 2)),j 仍为 0。​
    • 比较 left[1].值=6 和 right[0].值=1:6 > 1。​
    • right[j=0] 之后的元素([2])仍小于 6,数量为 2 - 0 = 2。​
    • 因此 counts[2] += 2(原始索引 2 对应的元素 6,右侧暂时统计到 2 个更小的元素)。​
  • 移动左指针 i 超出左数组长度,将右数组剩余元素加入结果,合并结束。

代码实现

class Solution(object):def countSmaller(self, nums):""":type nums: List[int]:rtype: List[int]"""n = len(nums)temp = [0] * n##添加的内容#########################################################for i, num in enumerate(nums):nums[i] = (i, num)res = [0] * n####################################################################def merge(l, mid, h):"""合并 nums[l..mid-1] 和 nums[mid..h-1]"""for i in range(l, h):temp[i] = nums[i]i, j = l, midp = lwhile i < mid and j < h:if temp[i][1] <= temp[j][1]:nums[p] = temp[i]##添加的内容#################################################res[temp[i][0]] += j - mid###########################################################i += 1else:nums[p] = temp[j]j += 1p += 1while i < mid:nums[p] = temp[i]##添加的内容##################################################res[temp[i][0]] += j - mid#############################################################i += 1p += 1while j < h:nums[p] = temp[j]j += 1p += 1def sort(l, h):"""递归排序 nums[l..h-1]"""if h - l <= 1:returnmid = l + (h - l) // 2sort(l, mid)sort(mid, h)if nums[mid - 1][1] <= nums[mid][1]:returnmerge(l, mid, h)sort(0, n)return res # 修改

总结

一、为什么归并排序能解决 “右侧小于当前元素的数量” 问题?

核心原因是归并排序的分治过程天然具备 “比较左右两部分元素” 的特性,可以在排序的同时统计右侧小元素的数量。

  • 归并排序将数组分成左右两部分,递归排序后合并。
  • 合并时,当左半部分的元素 nums[i] 大于右半部分的元素 nums[j] 时,说明右半部分中从 j 到末尾的所有元素都小于 nums[i](因为右半部分已排序)。
  • 因此,可直接累加这些元素的数量到 counts[i] 中,实现 “一边排序一边统计”。

二、什么样的题型适合用归并排序解决?

归并排序的核心价值在于分治过程中对 “左右两部分有序子数组” 的比较和合并,因此适合以下场景:

  • 涉及 “逆序对” 的问题如:统计逆序对数量、求右侧小于当前元素的数量、数组中的第 K 个最大逆序对数目等。归并排序在合并时能高效统计逆序关系。
  • 需要在排序过程中附加统计 / 计算如:合并两个有序数组时记录某些条件的出现次数,或在分治中同步处理子问题的结果(如统计区间内的特定关系)。
  • 要求 O (n log n) 时间复杂度,且问题可分解为子问题:归并排序的分治思想适合将问题拆解为规模更小的子问题,且子问题的解可合并为原问题的解。
http://www.dtcms.com/a/531978.html

相关文章:

  • 【机器人学中的状态估计】3.6.6 习题证明
  • Kafka生产者详解(下):数据去重(幂等性)与数据有序
  • Data Ingestion: Architectural Patterns
  • 网站建设心得体会范文郑州男科医院排行哪家最好
  • 【datawhale秋训营】动手开发RAG系统(应急安全方向) TASK02
  • 怎么搜索整个网站内容网站怎么做成app
  • Python3 集合
  • 九冶建设有限公司官方网站sem优化怎么做
  • MATLAB基于灰靶决策模型的高校信息化设备供应商选择研究
  • java类与对象
  • AI 应用层革命(一)——软件的终结与智能体的崛起
  • Linux Crontab命令详解:轻松设置周期性定时任务
  • beef-xss网页无法访问
  • JavaEE初阶——多线程(3)线程安全
  • AI 开发告别 “孤岛”:MCP + 火山引擎
  • 做网站怎么开发程序建设网站改版
  • 招生管理平台需求分析文档
  • 设计模式-代理模式(Proxy)
  • Apache IoTDB(8):时间序列管理——从创建到分析的实战指南
  • IntelliJ IDEA 四种项目构建:从普通 Java 到 Maven Web 项目
  • 深入浅出数据结构:堆的起源、核心价值与实战应用
  • 智能行李架:快速找到最佳行李位
  • ArcGIS如何根据属性字段符号化面要素
  • 洛阳企业网站建设深圳网站建设系统
  • 面试题-React
  • 【HarmonyOS】GC垃圾回收
  • 字节跳动Seed团队推出 Seed3D 1.0:从单张图像生成仿真级 3D 模型
  • 大连城市建设档案馆官方网站单页竞价网站
  • MATLAB基于博弈论组合赋权灰靶模型的煤矿安全综合评价
  • word删除含有指定内容的行