Skip to content

276 Get Count Array (Lai)

Given an array A of length N containing all positive integers from [1...N]. How to get an array B such that B[i] represents how many elements A[j] (j > i) in array A that are smaller than A[i].

Assumptions:

  • The given array A is not null.

Examples:

  • A = { 4, 1, 3, 2 }, we should get B = { 3, 0, 1, 0 }.

Requirement:

  • time complexity = O(nlogn).

Solution:

public class Solution {
  public int[] countArray(int[] array) {
    // Write your solution here

    int[] result = new int[array.length];

    int[] indices = new int[array.length];
    for (int i = 0; i < array.length; i++){
      indices[i] = i;
    }

    int left = 0;
    int right = array.length-1;

    mergeSort(array, result, indices, left, right);
    return result;
  }

  private void mergeSort(int[] array, int[] result, int[] indices, int left, int right){
    if (left >= right){
      return;
    }

    int mid = left + (right- left)/2;
    mergeSort(array, result, indices, left, mid);
    mergeSort(array, result, indices, mid + 1, right);
    merge(array, result, indices, left, right);
  }

  private void merge(int[] array, int[] result, int[] indices, int left, int right){
    int mid = left + (right - left)/2;
    int leftIndex = left;
    int rightIndex = mid+1;

    int rightCount = 0;

    int[] sorted = new int[right - left + 1];
    int sortedIndex = 0;

    while (leftIndex <= mid && rightIndex <= right){
      if (array[indices[rightIndex]] < array[indices[leftIndex]]){
        rightCount++;
        sorted[sortedIndex] = indices[rightIndex];
        sortedIndex++;
        rightIndex++;
      }else{
        result[indices[leftIndex]] = result[indices[leftIndex]] + rightCount;
        sorted[sortedIndex] = indices[leftIndex];
        sortedIndex++;
        leftIndex++;
      }
    }

    while(leftIndex <= mid){
      result[indices[leftIndex]] += rightCount;
      sorted[sortedIndex] = indices[leftIndex];
      sortedIndex++;
      leftIndex++;
    }

    while(rightIndex <= right){
      sorted[sortedIndex] = indices[rightIndex];
      sortedIndex++;
      rightIndex++;
    }

    for (int i = left; i <= right; i++){
      indices[i] = sorted[i - left];
    }
  }
}


// TC: O(nlogn)
// SC: O(n)
public class Solution {
  public int[] countArray(int[] array) {
    // Write your solution here
    // The indexArray contians the indices in the original array,
    // original array.
    // The countArray is the actual return array.
    // The helper array is to help the merge sort.
    int[] indexArray = new int[array.length];
      // The indices are just 0 - (array.length -1)
    for (int i = 0; i < array.length; i++){
      indexArray[i] = i;
    }


    int[] countArray = new int[array.length];
    int[] helper = new int[array.length];
    mergeSort(array, indexArray, countArray, helper, 0, array.length - 1);
    return countArray;
  }

  private void mergeSort(int[] array, int[] indexArray, int[] countArray, int[] helper, int left, int right){
    if (left >= right){
      return;
    }

    int mid = left + (right - left)/2;
    mergeSort(array, indexArray, countArray, helper, left, mid);
    mergeSort(array, indexArray, countArray, helper, mid + 1, right);
    merge(array, indexArray, countArray, helper, left, mid, right);
  }

  private void merge(int[] array, int[] indexArray, int[] countArray, int[] helper, int left, int mid, int right){
    copyArray(indexArray, helper, left, right);
    int l = left;
    int r = mid + 1;

    int cur = left;
    while(l <= mid){
      // When sorting the indexArray, we use the corresponding value in the 
      // original array.
      if (r > right || array[helper[l]] <= array[helper[r]]){
        countArray[helper[l]] += (r - mid -1);
        indexArray[cur++] = helper[l++];
      }else{
        indexArray[cur++] = helper[r++];
      }
    }
  }

  private void copyArray(int[] indexArray, int[] helper, int left, int right){
    for (int i = left; i <= right; i++){
      helper[i] = indexArray[i];
    }
  }

}

// TC: O(nlogn)
// SC: O(n)