合并两个数组并对最后一个数组进行排序

时间:2017-03-01 12:22:39

标签: javascript arrays algorithm sorting puzzle

在一次采访中,我被问到以下问题。 我得到两个数组,它们都被排序。

BUT

阵列1将具有少量-1和阵列2将具有总数作为阵列1中的-1的总数。

所以在下面的例子中 array1有三个-1,因此array2有3个数字。

让我们说

var arrayOne = [3,6,-1,11,15,-1,23,34,-1,42];
var arrayTwo = [1,9,28];

两个数组都将被排序。

现在我必须编写一个程序,通过替换-1'来合并arrayOne中的arrayTwo,并且arrayOne应该按排序顺序。

所以输出将是

arrayOne = [ 1,3, 6, 9, 11, 15, 23, 28 ,34, 42 ]

应该在不使用任何排序API的情况下进行排序。

我写了以下代码



function puzzle01() {
  var arrayOne = [3, 6, -1, 11, 15, -1, 23, 34, -1, 42];
  var arrayTwo = [1, 9, 28];
  var array1Counter = 0,
    isMerged = false;

  console.log(" array-1 ", arrayOne);
  console.log(" array-2 ", arrayTwo);

  for (var array2Counter = 0; array2Counter < arrayTwo.length; array2Counter++) {
    isMerged = false;
    while (isMerged === false && array1Counter < arrayOne.length) {

      if (arrayOne[array1Counter] === -1) {
        arrayOne[array1Counter] = arrayTwo[array2Counter];
        isMerged = true;
      }

      array1Counter++;
    }
  } //for

  console.log(" array-1 + array-2 ", arrayOne);
  bubbleSort(arrayOne);
  console.log(" Sorted array ", arrayOne);
} //puzzle01

puzzle01();

// implementation of bubble sort for sorting the 
// merged array
function bubbleSort(arrayOne) {
  var nextPointer = 0,
    temp = 0,
    hasSwapped = false;
    
  do {
    hasSwapped = false;
    for (var x = 0; x < arrayOne.length; x++) {
      nextPointer = x + 1;
      if (nextPointer < arrayOne.length && arrayOne[x] > arrayOne[nextPointer]) {
        temp = arrayOne[x];
        arrayOne[x] = arrayOne[nextPointer];
        arrayOne[nextPointer] = temp;
        hasSwapped = true;
      }
    } //for
  } while (hasSwapped === true);
} // bubbleSort
&#13;
&#13;
&#13;

上述代码的输出是

 array-1  [ 3, 6, -1, 11, 15, -1, 23, 34, -1, 42 ]
 array-2  [ 1, 9, 28 ]
 array-1 + array-2  [ 3, 6, 1, 11, 15, 9, 23, 34, 28, 42 ]
 Sorted array  [ 1, 3, 6, 9, 11, 15, 23, 28, 34, 42 ]

从上面的代码可以看出,我首先合并了两个数组,然后对最后一个数组进行了排序。

只是想知道, 有没有更好的解决方案。

我的解决方案是否有任何缺陷。

请告诉我,这将有所帮助。

在阅读了所有非常有用的评论和答案后,我发现能够找到更快的解决方案。

让我们举个例子

var arrayOne = [3,6,-1,11,15,-1,32,34,-1,42,-1];
var arrayTwo = [1,10,17,56],

Step1:我将遍历arrayTwo。取下一个元素(即&#39; 1&#39;)并与arrayOne的下一个元素(即&#39; 3&#39;)进行比较并进行比较。

步骤2a:如果array1的元素大于array2的元素而不是swap数组元素。现在转到array1的下一个元素。

OR

步骤2b:如果array1的元素等于-1,则交换数组元素。现在转到array2的下一个元素。

第3步:转到第1步。

所以

在上面的例子中

第一次迭代,     array1 = [1,6,-1,11,...]     array2 = [3,10,17,56]

第二次迭代,     array1 = [1,3,-1,11,..]     array2 = [6,10,17,56]

第三次迭代,     array1 = [1,3,6,11 ..]     array2 = [-1,10,17,56]

第四次迭代     array1 = [1,3,6,10,..]     array2 = [ - 1,11,17,56]

等等。

最后我会得到输出

array1 = [ 1, 3, 6, 10, 11, 15, 17, 32, 34, 42, 56 ]
array2 = [-1,-1,-1]

请找到以下代码,

function puzzle02(arrayOne,arrayTwo){   
    var array1Counter = 0,
        array2Counter = 0,       
        hasMinusOneOccurred = false;

    console.log(" array-1 ",arrayOne);
    console.log(" array-2 ",arrayTwo);  


    while(array2Counter < arrayTwo.length){ // iterate through array2

        do{
            if(arrayOne[array1Counter] === -1){ // if -1 occurred in array1
                hasMinusOneOccurred = true;

                // swaping numbers at current position of array1
                // with current position of array2 
                swap(arrayOne,arrayTwo,array1Counter,array2Counter);

                // recheck if the current value is greater than other values
                // of array1
                if(recheckAndSort(arrayOne,array1Counter) === true){
                    array1Counter = -1;// recheck array1 from start
                }else{
                    // recheck the current array1 counter, for doing so go 1 count back
                    // so that even if the counter is incremented it points to current
                    // number itself 
                    array1Counter--; 
                }

            }else if(arrayOne[array1Counter] > arrayTwo[array2Counter]){
                swap(arrayOne,arrayTwo,array1Counter,array2Counter);
            }else{
                array1Counter++;
                continue;   
            }

            array1Counter++;            
        }while(hasMinusOneOccurred === false); // end of do-while

        array2Counter++;
        hasMinusOneOccurred = false;

    }//end of while

    console.log(" Sorted array ",arrayOne);

    function swap(arr1,arr2,arr1Index,arr2Index){
        var temp = arr2[arr2Index];
        arr2[arr2Index] = arr1[arr1Index];
        arr1[arr1Index] = temp;
    }// end of swap 

    // this method is call if -1 occures in array1
    function recheckAndSort(arrayOne,array1Counter){
        var isGreaterVal = true,
            prevCounter = 0,
            nextCounter = 0,
            temp = 0,
            recheckFromStart = false;


        if(array1Counter === 0){ // if -1 occurred at first position of array1.

            // flag to check if -1 occurrec at first position
            // if yes, iterate array1 from start
            recheckFromStart = true; 

            // iterate forward to check wether any numbers are less than current position,
            // if yes than move forward
            for(var j = 0; isGreaterVal; j++){
                nextCounter = j + 1;

                if(arrayOne[nextCounter] === -1){
                    // swaping numbers of array1 between next to current                    
                    swap(arrayOne,arrayOne,nextCounter,j);
                    isGreaterVal = true; 

                }else if(arrayOne[nextCounter] < arrayOne[j]){
                    // swaping numbers of array1 between next to current
                    swap(arrayOne,arrayOne,nextCounter,j);
                    isGreaterVal = true;

                }else{
                    isGreaterVal = false;
                }

             }//end of for

         }else{// if -1 occurred in the middle position of array1 and is been swaped then
            // iterate backwards to check if any number less then current position exists,
            // if yes than shift backwards.
            for(var i = array1Counter; isGreaterVal; i--){
                prevCounter = i - 1;

                if(arrayOne[prevCounter] > arrayOne[i]){

                    // swaping numbers of array1 between previous to current                    
                    swap(arrayOne,arrayOne,prevCounter,i);
                    isGreaterVal = true; 
                }else{
                    isGreaterVal = false;
                }

            }// end of for  
        }

        return recheckFromStart;        
    }// end of recheckAndSort
} // end of puzzle02

调用上述功能后

puzzle02([3,6,-1,11,15,-1,32,34,-1,42,-1],[1,10,17,56]);

上述代码的输出是,

 array-1  [ 3, 6, -1, 11, 15, -1, 32, 34, -1, 42, -1 ]
 array-2  [ 1, 10, 17, 56 ]
 Sorted array  [ 1, 3, 6, 10, 11, 15, 17, 32, 34, 42, 56 ]

感谢。

11 个答案:

答案 0 :(得分:2)

您可以尝试以下方法:

逻辑

  • 创建一个将返回的新数组。
  • 检查arrayTwo中的第一个元素,并将其保存在变量中val
  • 循环arrayOne并检查当前值是否大于val,将其推入数组并将i的值减1以检查下一个值以及当前元素。< / LI>
  • 现在检查当前元素。如果它小于0,则忽略它,否则将值推送到数组。
  • 返回此阵列。

&#13;
&#13;
function mergeAndSort(a1, a2) {
  var matchCount = 0;
  var ret = [];

  for (var i = 0; i < a1.length; i++) {
    var val = a2[matchCount];
    if (a1[i] > val) {
      ret.push(val)
      matchCount++
      i--;
      continue;
    }
    if (a1[i] > 0) {
      ret.push(a1[i]);
    }
  }
  console.log(ret.join())
  return ret;
}


var arrayOne = [3, 6, -1, 11, 15, -1, 23, 34, -1, 42]
var arrayTwo = [7, 19, 38];
var arrayThree = [1, 9, 28];
var arrayFour = [1,2,5]

mergeAndSort(arrayOne, arrayTwo)
mergeAndSort(arrayOne, arrayThree)
mergeAndSort(arrayOne, arrayFour)
&#13;
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}
&#13;
&#13;
&#13;

注意:不检查arrayTwo中的元素数量,因为它明确提到它将是相同的。

答案 1 :(得分:2)

有一个干净的O(N)就地解决方案。

首先将所有arrayOne-1下方)移至前方,然后“{1}}。这只需要一次向后传递。

然后通过在--arrayTwo的尾部之间迭代移动最小元素并覆盖下一个arrayOne来执行合并。差距将缩小,但--的元素仍然存在空间。

arrayTwo

包装:

 3,  6, --, 11, 15, --, 23, 34, --, 42
 1,  9, 28

融合:

 3,  6, --, 11, 15, --, 23, 34, --, 42

 3,  6, --, 11, 15, --, 23, --, 34, 42

 3,  6, --, 11, 15, --, --, 23, 34, 42

 3,  6, --, 11, --, --, 15, 23, 34, 42

 3,  6, --, --, --, 11, 15, 23, 34, 42

 3, --, --, --,  6, 11, 15, 23, 34, 42

 --, --, --, 3,  6, 11, 15, 23, 34, 42

答案 2 :(得分:0)

您可以在一个循环中迭代arrayOne,然后arrayTwo

这个想法是将目标索引与实际索引分开。第一个循环忽略-1并保留目标索引。

如果实际值大于arrayTwo的第一个值,则交换两个值,并且在arrayTwo中,通过迭代和交换grater值来进行排序。

然后将实际项目分配给目标索引。

两个指数都会增加。

最后,arrayTwo的所有项目都会添加到arrayOne

function order(arrayOne, arrayTwo) {
    var i = 0, j, l = 0;
    while (i < arrayOne.length) {
        if (arrayOne[i] === -1) {
            i++;
            continue;
        }
        if (arrayTwo[0] < arrayOne[i]) {
            [arrayOne[i], arrayTwo[0]] = [arrayTwo[0], arrayOne[i]];
            j = 0;
            while (arrayTwo[j] > arrayTwo[j + 1]) {
                [arrayTwo[j], arrayTwo[j + 1]] = [arrayTwo[j + 1], arrayTwo[j]];
                j++;
            }
        }
        arrayOne[l++] = arrayOne[i++];
    }
    j = 0;
    while (l < arrayOne.length) {
        arrayOne[l++] = arrayTwo[j++];
    }
    return arrayOne;
}

console.log(order([3, 6, -1, 11, 15, -1, 23, 34, -1, 42], [7, 19, 38]));
console.log(order([3, 6, -1, 11, 15, -1, 23, 34, -1, 42], [1, 9, 28]));
console.log(order([3, 6, -1, 11, 15, -1, 23, 34, -1, 42], [1, 2, 5]));
console.log(order([3, 6, -1, 11, 15, -1, 23, 34, -1, 42], [43, 44, 45]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 3 :(得分:0)

您应该执行insertion sort之类的操作。由于两个数组都是排序的(-1s除外),array2中的最小数字将放在第一个元素和第一个元素之间的某个位置,array2的第二个元素将放在第一个元素之后的任何位置array1中的-1和array1中的第二个-1之前或之后的等等。

因此,您必须仅在array2的一部分中插入array1的特定元素,而不是整个数组。此外,array2的每个元素都必须考虑array1的不同细分或子数组。因此,此逻辑的有效时间复杂度为O(n+m),其中narray1的长度,marray2的长度。

答案 4 :(得分:0)

不能像

那样

将arrayTwo的每个项目与arrayOne的每个项目进行比较 如果它比arrayOne更大,插入项目,并在迭代arrayOne时删除所有-1。

答案 5 :(得分:0)

这实际上是一个有趣的问题。有许多排序算法,最有效的排序算法始终从一个&#34;不可更改的&#34;数组,所以不改变其中的值。然而,你的目标是在遇到-1时更改值,以便从第二个数组中获取值。

因此,您需要一种不会分割数组的排序算法,因为如果第二个数组的最后一个元素是1(最低),则必须将其移动到开头。如果你正在使用一种分解算法来分解数组(快速排序中的分而治之的策略)或使用递归,那么它可能会有问题,因为它无法移动到主数组的开头。除非你知道主阵列。

您需要的是一种执行逐步算法的算法。

我使用的算法是冒泡排序,它会逐步检查每个元素。如果值为-1并且将其位置正确地移动到数组,则更容易替换该值。但是,效率并不高。也许我会编辑我的帖子,看看我是否可以改进它。

&#13;
&#13;
function mergeAndSort(arr1, arrMergeIn) {
  // merge + sort using arr1 as large one
  var mergeIndex = 0;

  for (var i = 0; i < arr1.length; ++i) {
    if (arr1[i] === -1) arr1[i] = arrMergeIn[mergeIndex++];
    var j = i;
    while (j > 0 && arr1[j - 1] > arr1[j]) {
      var tmp = arr1[j - 1];
      arr1[j - 1] = arr1[j];
      arr1[j] = tmp;
      j--
    }
  }
  return arr1;
}

// one liner console output
function showArray(arr) {
console.log(arr.join(','));
}


showArray(mergeAndSort([3, 6, -1, 11, 15, -1, 23, 34, -1, 42], [7, 19, 38]));

showArray(mergeAndSort([3, 36, -1, 1, 10, -1, 9, 34, -1, 42], [17, 9, 38]));

showArray(mergeAndSort([3, 36, -1, 1, 10, -1, 9, 34, -1, 42], [17, 9, 1]));

showArray(mergeAndSort([-1, 36, -1, 1, 10, -1, 9, 34, -1, 42], [17, 9, 100, 1]));

showArray(mergeAndSort([-1, -1, 1, 100, -1, 9, 34, -1], [17, 9, 9, 1]));
&#13;
&#13;
&#13;

或者,您可以使用其他策略:替换&#34; -1&#34;具有来自该另一个数组的元素的元素,并对其执行有效的算法。虽然在最坏的情况下,&#34; -1&#34; s位于数组的末尾,这意味着存在~N操作+排序算法的额外平均复杂度(高效)其中有~N * log(N))

答案 6 :(得分:0)

这是一个简单而紧凑的合并排序算法实现。只有与元素相同的操作量。

我通过创建一个与两个数组相同数量的元素的数组来实现这一点,然后迭代该数组。

每次迭代:

  • 如果两个数组都有元素(并且最小元素不是-1),它会将最小元素移动到结果中。
  • 如果只有一个数组仍然有元素(并且下一个元素不是-1),它会将该数组中的第一个元素移动到结果中。

最后根据您的规范

将结果分配给第一个数组

const mergeSort = (a, b) => Object.assign(a, 
  new Int32Array(a.length + b.length).reduce(m => {
    const el = [
      [a, b][+!(a[0] <= b[0])], 
      [a, b][+!a.length]][+!(a.length && b.length)
    ].shift()
    if(el !== -1) m.push(el)
    return m
  }, [])
)

const arr1 = [1,3,5,7,9]
const arr2 = [0,2,4]

mergeSort(arr1, arr2)

console.log(arr1) // [0,1,2,3,4,5,7,9]

答案 7 :(得分:0)

让我重新说明这项任务的三个最重要的方面:

  • 两个数组都已排序并包含正整数(Array1中的-1个占位符除外)
  • -1是无意义的占位符(它在Array1中的位置是随机的)
  • Array1 length等于输出数组长度

伪逻辑:

  • 将array1和array2从第一个位置解析到数组末尾
  • 忽略array1中的-1值
  • 如果array1 [当前位置]&lt; = array2 [当前位置]然后将array1 [当前位置]写入合并数组并移动到array1中的下一个位置;否则对array2应用相同

代码示例:

            public static void AMerge()
        {
            int[] array1 = new int[] { 3, 6, -1, 11, 15, -1, 23, 34, -1, 42 };
            int[] array2 = new int[] { 1, 9, 28 };
            int[] arrayMerged = new int[array1.Length];

            int array1Index = 0;
            int array2Index = 0;

            for (int arrayMergedIndex = 0; arrayMergedIndex < array1.Length; arrayMergedIndex++)
            {
                while (array1[array1Index] == -1) array1Index++; //ignore -1 placeholders
                if ((array1Index < array1.Length && array2Index >= array2.Length) 
                    || array1[array1Index] <= array2[array2Index])  //choose which array will provide current merged value
                {
                    arrayMerged[arrayMergedIndex] = array1[array1Index];
                    array1Index++;
                }
                else
                {
                    arrayMerged[arrayMergedIndex] = array2[array2Index];
                    array2Index++;
                }
            }

            char[] charsToTrim = { ',', ' '};
            string arrayMergedString = "{";
            foreach (int f in arrayMerged) arrayMergedString += f.ToString() + " ";
            arrayMergedString = arrayMergedString.TrimEnd(charsToTrim) + "}";
            Console.WriteLine(arrayMergedString);
            Console.ReadKey();
        }
    }

注意:

  • 优化速度=&gt;创建新的arrayMerged;空间优化需要在else分支中移动array1元素

答案 8 :(得分:-1)

你应该使用Merge sort中的合并函数,并修改它以便它不会创建一个新数组,而是使用array1,并在从array2插入一个元素后执行转换,这将转换元素在右边直到下一个-1,从而覆盖-1。

答案 9 :(得分:-1)

&#13;
&#13;
function merger(a1, a2) {
  var i = 0;
  var j = 0;

  while (i < a1.length && j < a2.length) {
    if (a1[i] > a2[j]) {
      // Swap values
      var temp = a2[j];
      a2[j] = a1[i];
      a1[i] = temp;
      i++;
    } else if (a1[i] !== -1 && a1[i] <= a2[j]) {
      i++;
    } else {
      var temp = a2[j];
      a2[j] = a1[i];
      a1[i] = temp;
      i++;
      j++;
    }
  }

  return a1;
}

var arrayOne = [3, 5, -1, 11, 15, -1, 23, 34, -1, 42];
var arrayTwo = [6, 19, 38];

console.log(merger(arrayOne, arrayTwo))
&#13;
&#13;
&#13;

对于某些前提条件(没有其他数字&lt; 0,a1应该小于a2等 - 这些都可以处理)这应该解决JS中的问题。

答案 10 :(得分:-1)

由于它们都已排序,因此String(describing: type(of: self)) 项的顺序应与arrayTwo-1的顺序相匹配。然后工作变得简单,可以按如下方式实施;

arrayOne

编辑:我认为上层解决方案在问题的一般逻辑中确实更有意义。如果-1s的位置没有任何意义,那么他们有什么用处?我们只需删除-1,然后在function replaceMissing(a,b){ var i = 0; return a.map(n => n < 0 ? b[i++] : n); } var arrayOne = [3,6,-1,11,15,-1,23,34,-1,42], arrayTwo = [7,19,38]; result = replaceMissing(arrayOne,arrayTwo); console.log(result);中的适当索引处简单插入arrayTwo项。这可以非常简单地完成如下。

arrayOne