【问题标题】:Creating an array of medians. Java创建一个中位数数组。爪哇
【发布时间】:2020-06-06 00:47:52
【问题描述】:

我无法找到此练习的解决方案:

Given scores, an array of integers representing all test and assignment scores, your task is to return an array of integers where output[i] represents the median grade after all marks up to (and including) scores[i] have been entered. Your instructor is a generous marker, so they always round the median up to the nearest integer.

median* - The median of an N-element sequence is defined as follows: If N is odd, the median is the element which stands in the middle of the sequence after it is sorted. If N is even, the median is the average (mean) of the two "middle" elements of the sequence after it is sorted.

Example

•For scores = [100, 20, 50, 70, 45] the output should be medianScores(scores) = [100, 60, 50, 60, 50].

After each score is entered, the median is recalculated as follows:
◦For [100], the median is 100 since it's the only element.
◦For [20, 100], the median is (20 + 100)/2 = 60 since there's an even number of elements.
◦For [20, 50, 100], the median is 50 (middle element).
◦For [20, 50, 70, 100], the median is (50 + 70)/2 = 60(mean of the two middle elements).
◦For [20, 45, 50, 70, 100], the median is 50 again (middle element).


Input / Output

我一直在尝试获得一个有效的代码,到目前为止,如果数组的长度是奇数,则该代码可以工作,但如果它是偶数,则返回不正确的结果;

 public static int[] getMedian(int[] arr){

    int[] sortedArr = new int[arr.length];
    int length = arr.length-1;
    int odd = arr.length-1;
    int even = arr.length-1;

    for(int i=0;i<arr.length;i++) {

        sortedArr[length] = arr[i];
        Arrays.sort(sortedArr);

        if (length % 2 == 0) {
            arr[i] = sortedArr[odd];
            odd--;
        } else {
            arr[i] = (sortedArr[even] + sortedArr[even - 1]) / 2;
            even--;
        }
        length--;
    }
return arr;

}

该算法通过将 arr 中的元素添加到 sortedArr 来工作。元素被排序,然后它检查 sortedArr 是偶数还是奇数。如果是偶数,arr[i] 成为中间元素,如果是奇数,arr[i] 是中间元素之和除以 2。

我会感谢你的帮助。

【问题讨论】:

  • 如果数组的长度甚至“中断”是什么意思?我正在使用偶数数组长度对其进行测试,并且程序没有崩溃。你的意思是输出不正确?
  • @djharten 是的,结果不正确,我为错误的术语道歉,我还是新手
  • 您需要将偶数和奇数除以二。此外, sortedArr 中只有默认数据。
  • 我建议使用Arrays.copyOfRange 从原始数组创建子数组,因为sort 将始终对整个数组进行排序(包括尚未设置的元素(零)) 使用仅对范围进行排序的sort 方法:sort(但不在sortedArr[length] 处添加元素,使用i)(Obs:evenodd 必须从@987654331 计算@,子数组的大小)
  • 在每次迭代时对数组进行排序似乎效率不高。你对效率有一些限制吗?数组的最大大小是多少?

标签: java arrays algorithm loops for-loop


【解决方案1】:

未优化的解决方案。

首先是计算数组中位数的方法:

/** Generous or not: one to round up, zero to round down. */
private static final int generous = 1;

private static int median(int[] arr) {
    Arrays.sort(arr);
    int mid = arr.length / 2;
    if (mid + mid == arr.length) { // little optimized "is it even"
        return (arr[mid-1] + arr[mid] + generous) / 2;
    } else {
        return arr[mid];
    }
}

然后为每个子数组调用它:

// passed array will be (partially) sorted
private static int[] getMedian(int[] arr) {
    int[] result = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
        result[i] = median(Arrays.copyOfRange(arr, 0, i+1));
    }
    return result;
}

一点优化:不创建子数组,只传递要考虑的长度

private static int median(int[] arr, int len) {
    Arrays.sort(arr, 0, len);
    int mid = len / 2;
    if (mid + mid == len) { // little optimized "is it even"
        return (arr[mid-1] + arr[mid] + generous) / 2;
    } else {
        return arr[mid];
    }
}

getMedian()中,称为

result[i] = median(arr, i+1);

【讨论】:

    【解决方案2】:

    为了提高效率,第一步是确定更好的算法。

    让我们调用median[]创建的数组。

    我会使用两个堆:

    • k/2k/2+1 的最大堆 left 的最小值直到第 k 个索引,取决于 k 是偶数还是奇数。
    • right 的最小堆 k/2 最高值直到第 k 个索引

    那么,

    if k is even, median[k] = (left.max() + right.min())/2
    if k is odd, median[k] = left.max()
    

    初始化:

    left <- min (scores[0], scores[1])
    right <- max (scores[0], scores[1])
    

    然后,对于每个新值 x = scores[k],您必须管理两个堆,这取决于 k 是偶数还是奇数,以及 xleft.max()right.min() 之间的比较。重要的是两个堆保持正确的大小。这意味着有时一个值会从一个堆转移到另一个堆。

    如果k 是偶数(k-1 是奇数):

    If x < left.max() then x -> left, left.max() -> right (corresponding value removed from left)
    else: x -> right
    

    如果k奇数:

    If x < right.min() then x -> left
    else: x -> right, right.min() -> left (corresponding value removed from right)
    

    全局复杂度:O(nlogn)

    我不太了解java。如果java没有堆,我想你可以使用PriorityQueue

    【讨论】:

      【解决方案3】:

      您在将数组复制到 sortedArray 时覆盖了现有值。

          public static void main(String[] args) {
              int[] ret = getMedian(new int[]{100,20,50,70,45});
              System.out.println(Arrays.toString(ret));
          }
      
          public static int[] getMedian(int[] arr) {
      
              int[] sortedArr = new int[arr.length];
              int[] retArr = new int[arr.length];
              int len = 1;
              int realLength = arr.length-1;
      
              for (int i = 0; i < arr.length; i++) {
      
                  sortedArr[realLength-i] = arr[i];
                  Arrays.sort(sortedArr);
                 // arrays are accessed in reverse so adjust is needed using
                 // array length.
                  if (len % 2 == 1) {
                      // use middle value
                      retArr[i] = sortedArr[realLength-len/2];
                  } else {
                      // average middle values 
                      retArr[i] = (sortedArr[realLength-len/2]
                              + sortedArr[realLength-len/2 + 1]) / 2;
                  }
                  len++;
              }
              return retArr;
          }
      
      }
      
      

      【讨论】: