构造计数数组的时间复杂度优于O(n ^ 2)

时间:2016-06-06 17:21:53

标签: c arrays algorithm sorting

给定大小为A[]的数组n,构建两个数组C_min[]C_max[],以便 C_min[i]表示小于A[i]A[0 to i]C_max[i]的元素数量 A[i]表示A[i to n-1]

中大于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}
#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)更好的算法,但是this post促使我想到一些更好的方法,但是我无法应用类似的逻辑(在这里提到的)

在给定的帖子中,给出的问题是在数组中找不到反转。如果array [i]&gt; array [j]和j&gt;然后它形成一个反转。例如,序列2,4,1,3,5有三个反转(2,1),(4,1),(4,3)。
用于解决此问题的想法是合并排序算法。

  

在合并过程中,让我用于索引左子数组(L [])和j   对于右子阵列(R [])。在merge()的任何步骤,如果L [i]更大   比R [j],则有(mid - i + 1)反转,其中mid是   中间索引传递给合并排序的合并功能。因为离开了   和右子阵列进行排序,因此所有剩余的元素都在   left-subarray(L [i + 1],L [i + 2] ... L [mid])将大于R [j]

此逻辑的代码如下:

    public void sendMessage(View view) {
    AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            try {
                GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
                String to = notificationKey; // the notification key
                AtomicInteger msgId = new AtomicInteger();
                String id = Integer.toString(msgId.incrementAndGet());
                Bundle data = new Bundle();
                data.putString("hello", "world");

                gcm.send(to, id, data);
                Log.e(TAG, "sendMessage done.");
            } catch (Exception ex) {
                Log.e(TAG, ex.toString());
            }
            return null;
        }
    };
    task.execute();
}

所以这个计数数组问题可以在类似的行上完成。

  

是否可以在优于O(n ^ 2)-time?

的情况下构造计数数组

1 个答案:

答案 0 :(得分:1)

假设您保留了一个数组S,其中S [0..x]是A [0..x]的排序版本。然后当你已经计算出C_min [0..x]时计算C_min [x + 1]将相当于将A [x + 1]插入S(O(log n)操作)并在其中定位A [x + 1] S(最坏的情况是,另一个O(log n)操作)。这将使计算所有C_min O(n log n)。计算C_max将类似,但需要自己的S版本,计算C_min和C_max O(n log n)。