【问题标题】:Find the N'th highest number in unsorted array在未排序的数组中查找第 N 个最高的数字
【发布时间】:2015-04-11 14:57:04
【问题描述】:

今天在一次采访中,有人告诉我写一个程序,它将输出未排序数组中第 n 大的数字,

我用javascript解决了这个问题,程序如下,

var fn50 = function(){
    var reverseSort = function(myArray,highest){
        var x = 0,
            y = 0,
            z = 0,
            temp = 0,
            totalNum = myArray.length, // total numbers in array
            flag = false, // is the numbers sorted in reverse while iteration
            isAchieved = false; // whether we achieved the nth highest

        while(x < totalNum){
            y = x + 1; // start comparing 'yth' number which is next to 'xth' number.

            if(y < totalNum){
                // start comparing 'xth' with the next number, and if 'xth' number less than its next position number, just swipe them
                for(z = y; z < totalNum; z++){

                    if(myArray[x] < myArray[z]){
                        temp = myArray[z];
                        myArray[z] = myArray[x];
                        myArray[x] = temp;
                        flag = true; // if number swiping done ?
                    }else{
                        continue;
                    }   
                }                   
            }

            if(flag){
                flag = false;
            }else{
                x++; // x holds the max number in series, now move to next position to find next highest number 
                if(x > highest){ // if x is what the desired max number which we want flag it and break the loop to escape further iteration.
                    isAchieved = true;
                }   
            }
            if(isAchieved){
                break;
            }
        }

        print(myArray[(highest - 1)]);  
    };

    reverseSort([12,56,78,34,11,100,95],4); // passing the unsorted array of number's, and finding the 4th highest number
};

fn50();

我得到了所需的输出,即上面数组中的答案是 56,这是第四大数字。

但面试官告诉了一个更好的解决方案。

您能否告诉我或给我一个提示,如何有更好的解决方案。 一些数据结构技术?

【问题讨论】:

  • 嗯,这比对数组进行排序,然后从结果中取出第四个元素更复杂吗?如arr.sort()[3]?既然语言已经有了,为什么还要编写自己的排序?
  • @torazaburo 它必须是 arr.sort(function(a, b) { return a-b; }),因为 .sort() 进行词汇排序
  • @Andreas 当然,你是对的,那是伪代码。

标签: javascript arrays sorting


【解决方案1】:

排序和选择kth 最高的数字需要O(n log(n)) 时间,其中n 是元素的数量。在参考书目中,有medians of medians algorithm,它允许我们选择线性时间最高或最小的k,无论k 有什么值。如果您询问所需元素是否可以是数组的中位数,您可以了解面试官是否考虑过这种算法。中位数是位置n / 2的元素,被认为是最难的情况。

但对于面试来说,这是一个复杂的算法。如果k 通常很小,您可以基于heap 的结构应用以下算法。您可以在线性时间内将数组转换为堆。然后提取k 乘以最大元素。这将花费O(n + k * log(n)) 的时间,对于小的k = ο(n / log(n) 来说是线性的。

k 与常数一样小,例如 4,具有更简单的线性算法。每次我们扫描数组并删除最大的。这将花费O(k * n) 时间,因为k 是恒定的,O(k * n) = O(n)

【讨论】:

  • >每次我们扫描数组并删除最大的。这将花费 O(k * n) 时间,并且因为 k 是常数,所以 O(k * n) = O(n)。这在现实世界中不是效率低下吗,因为从数组的开头删除会导致所有剩余元素的移动?
【解决方案2】:

我尝试使用快速选择 as JuniorCompressor suggested 来实现这一点。 但我想知道这是否真的是最快的方法。我想枢轴的计算可以提高效率。

var nthLargest = function(list, n) {
  var i, a = 0, b = list.length, m, pivot;
  if(n < 1) throw new Error("n too small");
  if(list.length < n) throw new Error("n too large");
  list = list.slice(0);
  var swap = function(list, a, b) {
    var temp = list[a];
    list[a] = list[b];
    list[b] = temp;
  }
  //returns the index of the first element in the right sublist
  var partition = function(list, pivot, a, b) {
    b--;
    while(a <= b) {
      if(list[a] <= pivot) a++;
      else if(list[b] > pivot) b--;
      else swap(list, a, b);
    }
    return a;
  }
  while(b - a > 1) {
    for(i = a, pivot = 0; i < b; i++) {
      pivot += list[i];
    }
    pivot /= b-a;
    m = partition(list, pivot, a, b);
    if(b - m >= n) a = m; // select right sublist
    else { // select left sublist
      if(m === b) return list[a]; // all elements in sublist are identical
      n -= b - m;
      b = m;
    }
  }
  if(n !== 1) throw new Error();
  return list[a];
}

【讨论】:

    【解决方案3】:
    <script>
        function nthlargest(array, highest) {
            array.sort();
            l=array.length;
            if(highest>l)
                return("undefined");
            else
                return(array[l-highest+1]);
        }
        document.write(nthlargest([23, 652, 43, 89, 23, 90, 99, 88], 2));
    </script>
    

    【讨论】:

      【解决方案4】:

      排序是我能想到的最简单的方法。

      但您似乎创建了自己的排序实现。

      为什么不使用Array.sort 函数?

      function nthHighest(numbers, n) {
          var sorted = numbers.sort(function (a, b) {
              return a - b;
          });
          return sorted[sorted.length - n];
      }
      

      你可以通过反向排序来简化算法,这只是意味着b - a而不是a - b,那么你不需要从后面拉,这只是一个表面上的改进。

      function nthHighest(numbers, n) {
          var sorted = numbers.sort(function (a, b) {
              return b - a;
          });
          return sorted[n - 1];
      }
      

      您还可以遍历数组一次,将每个元素按排序顺序复制到一个新数组中,然后再一次,将第 N 个元素取到最后一个元素,使用下划线实现二分查找。

      function nthHighest(numbers, n) {
          var sorted = [];
          numbers.forEach(function (number) {
              sorted.splice(_.sortedIndex(sorted, number), 0, number);
          });
          return sorted[numbers.length - n];
      }
      

      但这基本上是对同一概念的转折:排序并取 N。由于重组,这种方法在链表上的表现也比纯数组更好,但这可以是一个单独的练习。

      【讨论】:

      • 排序可能是最简单的方法,但不是最快的方法,如 JuniorCompressor explained
      • 他们说的不是更快,而是说的更好。目前尚不清楚这意味着什么。排序几乎从来都不是做任何事情的最快方法。
      • 这是一个面试问题,看在上帝的份上。除非他在谷歌面试工作,否则他们主要想看看他的大脑是否在运作。我怀疑他们是否期望他掌握了 Knuth 的四卷半数值算法。我的猜测是,“排序(使用内置排序)并取第四个元素”的答案会得分 100%。
      • 我同意,这就是为什么我要帮助找到更简单的排序方法(意味着更少的代码),而不是尝试优化每一纳秒的性能。如果面试官真的期望得到比排序更快的计算答案,我会感到惊讶。
      • @Brandon,不是真的。当提出关于算法的问题时,“更好”一词意味着更少的时间复杂度。 Array.sort 内部运行 2 个 for 循环,这是最坏的情况 O(2n) - 这意味着对于数组中的 n 个项目,您将有一个代码将执行 n*n 次以获得结果。这被认为是不好的。如果复杂度可以降低到O(n)O(n*log(n)),那就更好了
      【解决方案5】:

      我想出了自己的解决方案:

      const nthlargest = (arr, n) => {
          let newArr = [arr[0]];
          for (let index = 1; index < arr.length; index++) {
              const element = arr[index];
              // push to end
              if (element > newArr[index - 1]) {
                  newArr.push(element);
              } else {
                  let insertPos = 0;
                  // if greater than first and less than last
                  if (newArr[0] < element && element < newArr[index - 1]) {
                      for (let j = 0; j < newArr.length; j++) {
                          if (newArr[j] > element) {
                              insertPos = j;
                          }
                      }
                  }
                  //insert at specified pos
                  newArr.splice(insertPos, 0, element);
              }
          }
          return newArr[n];
      }
      
      console.log(nthlargest([43, 56, 23, 89, 88, 90, 99, 652], 4));
      // counting from 0
      // 89
      

      这没有对原始数组进行排序,否则会容易得多。

      【讨论】:

        【解决方案6】:

        使用排序数组方法

        function nthLargest(array, n){
        
            array.sort(function(a, b) {
                return b - a; //organises the array in descending organises
              });
        
            let i = n - 1; //i is the index of the nth largest number
            
            console.log(array[i]);
        
        }
        

        【讨论】:

          猜你喜欢
          • 2021-12-16
          • 1970-01-01
          • 2016-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-10
          相关资源
          最近更新 更多