【发布时间】:2026-02-16 00:10:01
【问题描述】:
给定一个大小为n的数组A[],构造两个数组C_min[]和C_max[]使得C_min[i]表示A[0 to i]和
中小于A[i]的元素数C_max[i] 表示A[i to n-1] 中大于A[i] 的元素个数
例如A[5] = {1,2,4,3,6} 那么C_min[] 和C_max[] 将是C_min[5] = {0,1,2,2,4}C_max[5] = {4,3,1,1,0}
我想不出比 O(n^2) 更好的算法,但 this post 促使我想出一些更好的方法来做到这一点,但我无法应用类似的逻辑(即帖子中提到)在这里。
在给定的帖子中,给出的问题是在数组中找到没有反转的。如果 array[i] > array[j] 并且 j>i 那么它形成一个反转。例如序列 2, 4, 1, 3, 5 有三个反转 (2, 1), (4, 1), (4, 3)。
用于解决这个问题的想法是归并排序算法。
在合并过程中,让i用于索引左子数组(L[])和j 对于右子数组(R[])。在 merge() 的任何一步,如果 L[i] 更大 比 R[j],则有 (mid – i+1) 个反转,其中 mid 是 中间索引传递给归并排序的归并函数。因为离开了 和右子数组是排序的,所以所有剩余的元素 左子数组 (L[i+1], L[i+2] ... L[mid]) 将大于 R[j]
这个逻辑的代码如下:
#include <bits/stdc++.h>
int _mergeSort(int arr[], int temp[], int left, int right);
int merge(int arr[], int temp[], int left, int mid, int right);
/* This function sorts the input array and returns the
number of inversions in the array */
int mergeSort(int arr[], int array_size)
{
int *temp = (int *)malloc(sizeof(int)*array_size);
return _mergeSort(arr, temp, 0, array_size - 1);
}
/* An auxiliary recursive function that sorts the input array and
returns the number of inversions in the array. */
int _mergeSort(int arr[], int temp[], int left, int right)
{
int mid, inv_count = 0;
if (right > left)
{
/* Divide the array into two parts and call _mergeSortAndCountInv()
for each of the parts */
mid = (right + left)/2;
/* Inversion count will be sum of inversions in left-part, right-part
and number of inversions in merging */
inv_count = _mergeSort(arr, temp, left, mid);
inv_count += _mergeSort(arr, temp, mid+1, right);
/*Merge the two parts*/
inv_count += merge(arr, temp, left, mid+1, right);
}
return inv_count;
}
/* This funt merges two sorted arrays and returns inversion count in
the arrays.*/
int merge(int arr[], int temp[], int left, int mid, int right)
{
int i, j, k;
int inv_count = 0;
i = left; /* i is index for left subarray*/
j = mid; /* i is index for right subarray*/
k = left; /* i is index for resultant merged subarray*/
while ((i <= mid - 1) && (j <= right))
{
if (arr[i] <= arr[j])
{
temp[k++] = arr[i++];
}
else
{
temp[k++] = arr[j++];
/*this is tricky -- see above explanation/diagram for merge()*/
inv_count = inv_count + (mid - i);
}
}
/* Copy the remaining elements of left subarray
(if there are any) to temp*/
while (i <= mid - 1)
temp[k++] = arr[i++];
/* Copy the remaining elements of right subarray
(if there are any) to temp*/
while (j <= right)
temp[k++] = arr[j++];
/*Copy back the merged elements to original array*/
for (i=left; i <= right; i++)
arr[i] = temp[i];
return inv_count;
}
/* Driver progra to test above functions */
int main(int argv, char** args)
{
int arr[] = {1, 20, 6, 4, 5};
printf(" Number of inversions are %d \n", mergeSort(arr, 5));
getchar();
return 0;
}
那么这个计数数组问题是否可以在类似的行上完成。
是否有可能在比 O(n^2)-time 更好的时间内构造计数数组?
【问题讨论】:
-
为什么无缘无故投反对票??我认为有些人在否决问题而不是建议解决方案或否决理由时感到勇敢:D
-
NMDV,发布相关信息是站外链接,不被接受。最好在这里发布辱骂数据 - 和你尝试了什么。
-
@AMomchilov 您所说的先前值是指什么,先前的意思是访问的最后一个数组索引或仅小于当前元素的最后一个值?
-
@chux 我尝试的是一种简单的蛮力方法,我认为不需要解释。它只有两个用于跟踪 cout 的 for 循环。在给定的链接中,问题是找到反转计数的数量,并且使用归并排序算法在 O(nlogn) 时间内找到它。
-
对数组进行排序需要花费
O(n*ln(n)),所以从排序列表开始。那时似乎微不足道。只需遍历数组
标签: c arrays algorithm sorting