并归排序的应用 I
1. 题目列表
题目列表:
序号 | 题目 | 难度 |
---|---|---|
1 | 315. 计算右侧小于当前元素的个数 | 困难 |
2. 应用
2.1. Leetcode 315. 计算右侧小于当前元素的个数
2.1.1. 题目
给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例 1:
输入:nums = [5,2,6,1]
输出:[2,1,1,0]
解释:
- 5 的右侧有 2 个更小的元素 (2 和 1)
- 2 的右侧仅有 1 个更小的元素 (1)
- 6 的右侧有 1 个更小的元素 (1)
- 1 的右侧有 0 个更小的元素
2.1.2. 解题思路
这里,我们需要借助并归排序的思想:在每一次合并两个有序数组的时候,两个子数组都会按照从小到大的顺序合并,那么,每合并一个左侧的子数组中的元素时,它可以通过右侧的子数组中的待合并元素的位置,就是当前两个子数组中小于当前元素的个数。这样,我们只需要完成所有子数组的合并,即可得到每一个元素右侧小于它的元素个数了。
这里,我们以数组
在并归排序的在某一个步骤,我们会按照从小到大的顺序依次合并两个子数组:
当我们依次合并两个子数组时,在某一个时刻,应该合并
也就是说,在对
注意,因为每一次子数组的合并,都会对结果产生贡献,因此,我们需要将所有的结果累加起来。
总结:这里,我们主要利用了并归排序的思路,在每一次合并过程中,都可以通过右侧的子数组,求出小于当前元素的个数。
2.1.3. 算法步骤
这里,我们定义一个数据结构
class Node { int val; int id; Node(int val, int id) { this.val = val; this.id = id; } }
同时,我们需要定义两个变量:
-
数组
用于记录每一个索引位置所对应元素的右侧小于它的元素个数。 -
数组
用于对 做并归排序。
算法步骤:
-
先将原始数组
中的数值,记录到数组 中; -
对数组
使用并归排序;-
在每次合并两个子数组时,对于每一个左侧子数组中的元素,右侧小于它的元素个数都可以通过右侧子数组中待合并元素的位置得到;
-
递归合并完所有的子数组,即可得到结果。
-
2.1.4. 代码实现
class Solution { private class Node { int val; int id; Node(int val, int id) { this.val = val; this.id = id; } } private Node[] temp; private int[] count; public List<Integer> countSmaller(int[] nums) { int n = nums.length; count = new int[n]; temp = new Node[n]; Node[] nodes = new Node[n]; for (int i = 0; i < n; i++) { nodes[i] = new Node(nums[i], i); } sort(nodes, 0, n - 1); List<Integer> result = new LinkedList<>(); for (int c : count) { result.add(c); } return result; } private void sort(Node[] nodes, int left, int right) { if (left == right) { return; } int mid = left + (right - left) / 2; sort(nodes, left, mid); sort(nodes, mid + 1, right); merge(nodes, left, mid, right); } private void merge(Node[] nodes, int left, int mid, int right) { for (int i = left; i <= right; i++) { temp[i] = nodes[i]; } int i = left, j = mid + 1, k = left; while (i <= mid && j <= right) { if (temp[i].val > temp[j].val) { nodes[k] = temp[j++]; } else { nodes[k] = temp[i++]; count[nodes[k].id] += j - mid - 1; // 合并左侧子树的时候,累加结果 } k++; } while (i <= mid) { nodes[k] = temp[i++]; count[nodes[k].id] += j - mid - 1; // 合并左侧子树的时候,累加结果 k++; } while (j <= right) { nodes[k++] = temp[j++]; } } }
参考:
本文作者:LARRY1024
本文链接:https://www.cnblogs.com/larry1024/p/17991689
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步