algorithm - 如何更改合并排序以计算数组与排序数组的距离?
问题描述
注意:这个问题与倒数问题不同。
数组与排序数组的距离定义为:
dist(A)=Sumation(j-i) for any i<j that A[i]>A[j]
. 简单地说,它可以在 O(n^2) 中计算。我的问题是如何更改合并排序以计算 O(n log n) 中的距离?例如:
input: 5 2 3 4 1
output: 16
我不想计算反转! 此功能与反转不同。
input: 5 2 3 4 1
dist(A): 16
inversions(A): 7
解决方案
这可以在二叉搜索树的帮助下轻松完成。您需要维护右子树中存在的节点索引的总和以及右子树中存在的节点数。因此,每当您插入一个新节点并且它向任何节点的左侧移动时,距离都会更新为
`(no of nodes in right subtree* index of val which is to be inserted) - sum of indices of nodes present in right subtree)`
让我们来看看输入
5, 2, 3, 4, 1
第一个节点的 val 为 5,距离现在为 0;
插入后的情况2
sizeOfRightSubTree : 1
index: 1
sumOfIndicesOnRight: 0
inserted: 2, distance: 1
插入后 3
sizeOfRightSubTree : 1
index: 2
sumOfIndicesOnRight: 0
inserted: 3, distance: 3
插入后 4
sizeOfRightSubTree : 1
index: 3
sumOfIndicesOnRight: 0
inserted: 4, distance: 6
插入 1 后。请注意,它必须向左移动两次才能到达其最终位置,因此距离会更新两次。
sizeOfRightSubTree : 1
index: 4
sumOfIndicesOnRight: 0
sizeOfRightSubTree : 3
index: 4
sumOfIndicesOnRight: 6
inserted: 1, distance: 16
以下是java代码
public class DistanceFromSortedArray
{
class Node {
int val;
Node left;
Node right;
int index;
int sumOfIndicesOnRight;
int sizeOfRightSubTree;
Node(int num, int index)
{
this.val = num;
this.index = index;
sizeOfRightSubTree = 1;
sumOfIndicesOnRight = index;
}
void addIndexToRight(int index)
{
sizeOfRightSubTree++;
sumOfIndicesOnRight += index;
}
int distance(int index)
{
return sizeOfRightSubTree*index - sumOfIndicesOnRight;
}
}
private Node head;
private int distance;
public int calculate(int[] nums){
head = null;
distance = 0;
for(int i=0; i<nums.length; i++){
insert(nums[i], i);
}
return distance;
}
private void insert(int num, int index)
{
Node toInsert = new Node(num, index);
if(head == null){
head = toInsert;
return;
}
Node current = head;
Node previous = null;
while (current != null){
previous = current;
if(current.val > num){
distance += current.distance(index);
current = current.left;
}
else {
current.addIndexToRight(index);
current = current.right;
}
}
if(previous.val > num){
previous.left = toInsert;
}
else {
previous.right = toInsert;
}
}
}
这里有几个测试用例
@Test
public void calculate()
{
int[] nums = {5, 2, 3, 4, 1};
assertEquals(16, new DistanceFromSortedArray().calculate(nums));
}
@Test
public void reverseCalculate()
{
int[] nums = {5, 4, 3, 2, 1};
assertEquals(20, new DistanceFromSortedArray().calculate(nums));
}
@Test
public void SizeTwoCalculate()
{
int[] nums = {4, 5};
assertEquals(0, new DistanceFromSortedArray().calculate(nums));
int [] nums2 = {5, 4};
assertEquals(1, new DistanceFromSortedArray().calculate(nums2));
}
@Test
public void twistedCalculate()
{
int[] nums = {8, 3, 6, 5, 7, 1};
assertEquals(26, new DistanceFromSortedArray().calculate(nums));
}
@Test
public void AllSameCalculate()
{
int[] nums = {1, 1, 1, 1, 1, 1};
assertEquals(0, new DistanceFromSortedArray().calculate(nums));
}
推荐阅读
- pandas - 使用 sklearn 或 pandas 进行一次热编码后,如何在混合数据集(数值 + 分类)上应用 KNN
- windows - 此时收到消息 0 是意外的批处理脚本
- node.js - 从内存中的字符串发送文件,但仍包含 etag 功能
- javascript - 如何将事件处理程序传递给兄弟组件?
- python - 用于 youtube dl 的 Python Discord 队列
- android - 设备 minSDK 低于使用的 SDK
- kubernetes - Grafana 显示来自 influxdb 的死 kubernetes pod
- ionic3 - ionic cordova:当我从文件选择器插件获取内容:// url 时,如何在 android 库的 img 标签中显示图像
- java - 如何选择 Kafka transaction.id
- java - 将 BytesWritable 转换为 com.vividsolutions.jts.geom.Geometry