排序数组的最小交换次数

时间:2019-03-17 17:54:32

标签: javascript arrays

我需要做这样的事情:假设我有一个数组:

 [3, 4, 1, 2]

我需要交换3和4,以及1和2,所以我的数组看起来像[4, 3, 2, 1]。现在,我可以执行sort()。在这里,我需要计算将初始数组更改为最终输出所需的迭代次数。示例:

// I can sort one pair per iteration
let array = [3, 4, 1, 2, 5]
let counter = 0;

//swap 3 and 4
counter++;
// swap 1 and 2
counter++;
// 5 goes to first place
counter++

// now counter = 3 <-- what I need

编辑:这是我尝试过的。并非总是如此,这是由于以下问题:Bubble sort algorithm JavaScript

let counter = 0;
    let swapped;
    do {
        swapped = false;
        for (var i = 0; i < array.length - 1; i++) {
            if (array[i] < array[i + 1]) {
                const temp = array[i];
                array[i] = array[i + 1];
                array[i + 1] = temp;
                swapped = true;
                counter++;
            }
        }
    } while (swapped);

编辑:并非一直都是正确的,例如,因为我可以从最后到第一交换位置。查看上面的示例代码,现在已对其进行编辑。

9 个答案:

答案 0 :(得分:2)

  

这是我到目前为止尝试过的最佳代码,也被认为是最佳代码   由hackerrank回答:

E_NOTICE : type 8 -- Undefined variable: name -- at line 18
  

reference

答案 1 :(得分:2)

//You are given an unordered array consisting of consecutive integers  [1, 2, 3, ..., n] without any duplicates.
//still not the best

function minimumSwaps(arr) {
     let count = 0;
    for(let i =0; i< arr.length; i++){
        if(arr[i]!=i+1){
            let temp = arr[i];
            arr[arr.indexOf(i+1)] =temp;
            arr[i] = i+1;
            count =count+1;
        }
    }
    return count;
}

答案 2 :(得分:1)

除非您已经对计算机科学或真正的数学天才有所了解,否则该问题的解决方案不是很直观,但这全都取决于求逆的次数和所产生的周期。

如果您是计算机科学的新手,我建议使用以下资源来补充该解决方案:

如果我们将反转定义为:

arr [i]> arr [j]

其中i是当前索引,j是以下索引-

然后,如果不存在任何反转,则数组已经按顺序排列并且不需要排序。

例如:

[1,2,3,4,5]

因此,交换次数与反转次数有关,但并不直接相关,因为每个反转都可能导致一系列交换(与单个交换EX:[3,1,2]相对)。

因此,如果考虑以下数组:

[4,5,2,1,3,6,10,9,7,8]

此数组由三个周期组成。

循环1-4,1,3(两次掉期)

第二个循环-5,2(一次交换)

循环3-6(0次掉期)

第四轮-10、9、7、8(3次掉期)

现在这是CS和Math魔术真正发挥作用的地方:每个周期只需要经过一次就可以正确地对其进行排序,而这始终是正确的。

另一种说法是-可以对任何循环进行排序的最小交换次数是该循环中的元素数减去一个,或更明确的是:

最小掉期=(周期长度-1)

因此,如果我们将每个周期的最小交换次数相加,则该总数将等于原始数组的最小交换数。

这是我尝试解释为什么该算法有效的原因:

如果我们认为任何连续的数字集只是数字行的一部分,那么任何以零开头的集合都应等于其自己的索引(如果该集合表示为Javascript数组)。这个想法成为根据元素自身的值以编程方式确定in元素是否已处于正确位置的标准。

如果当前值不等于其自身的索引,则程序应检测到循环开始并记录其长度。当while循环达到循环中的原始值时,它将在循环中将最小交换次数添加到计数器变量。

无论如何,这是我的代码-非常冗长,但应该可以:

export const minimumSwaps = (arr) => {

  //This function returns the lowest value
  //from the provided array.
  //If one subtracts this value the from
  //any value in the array it should equal
  //that value's index.
  const shift = (function findLowest(arr){
      let lowest=arr[0];
      arr.forEach((val,i)=>{
          if(val<lowest){
              lowest=val;
          }
      })
      return lowest;
  })(arr);

  //Declare a counter variable
  //to keep track of the swaps.
  let swaps = 0;

  //This function returns an array equal
  //in size to the original array provided. 
  //However, this array is composed of 
  //boolean values with a value of false.
  const visited = (function boolArray(n){
      const arr=[];
      for(let i = 0; i<n;i++){
          arr.push(false);
      }
      return arr;
    })(arr.length);

  //Iterate through each element of the
  //of the provided array.
  arr.forEach((val, i) => {

    //If the current value being assessed minus
    //the lowest value in the original array
    //is not equal to the current loop index,
    //or, if the corresponding index in
    //the visited array is equal to true,
    //then the value is already sorted 
    if (val - shift === i || visited[i]) return;

    //Declare a counter variable to record
    //cycle length.
    let cycleLength = 0;

    //Declare a variable for to use for the 
    //while loop below, one should start with
    //the current loop index
    let x = i;

    //While the corresponding value in the
    //corresponding index in the visited array
    //is equal to false, then we 
    while (!visited[x]) {

      //Set the value of the current
      //corresponding index to true
      visited[x] = true;

      //Reset the x iteration variable to
      //the next potential value in the cycle  
      x = arr[x] - shift;

      //Add one to the cycle length variable
      cycleLength++;
    };

    //Add the minimum number of swaps to
    //the swaps counter variable, which
    //is equal to the cycle length minus one
    swaps += cycleLength - 1;

  });

  return swaps

}

答案 3 :(得分:0)

我假设您有两个原因要测量排序需要执行的迭代次数。因此,我将为您提供一些理论(如果数学过于密集,不要担心),然后提供一些实际应用。

有很多排序算法,其中一些算法基于要排序的项目数,具有可预测的迭代次数,其中一些算法仅基于要排序的项目的顺序以及哪一个项目就很幸运如何选择称为 pivot 的内容。因此,如果优化对您非常重要,那么您将需要针对排序算法选择正确的算法。否则,请使用通用算法。

这里是用于学习目的的最受欢迎的排序算法,它们每个都有最小,最坏和平均的运行情况。值得一提的是,Heapsort,Radix和binary-sort不仅仅是一个理论/学习练习。

快速排序

最坏情况:Θ( n 2)

最佳情况:Θ( n lg n

平均情况:Θ( n lg n

Here is a Quicksort implementation by Charles Stover

合并排序

最坏的情况:Θ( n lg n

最佳情况:Θ( n lg n

平均情况:Θ( n lg n

(请注意,它们都是一样的)

Here is a merge sort implementation by Alex Kondov

插入排序

最坏的情况:Θ( n 2

最佳情况:Θ( n

平均情况:Θ(n 2

(请注意,它的最坏情况和平均情况是相同的,但最好的情况是所有算法中最好的情况)

Here is an insertion sort implementation by Kyle Jensen

选择排序

最坏的情况:Θ(n 2

最佳情况:Θ(n 2

平均情况:Θ(n 2

(请注意,它们都是一样的,就像合并排序一样。)

Here is a selection sort algorithm written by @dbdavid updated by myself for ES6

您可以很容易地将迭代器变量添加到这些示例中的任何一个,以计算它们进行的交换次数,并与它们进行比较以查看哪种算法在哪种情况下效果最佳。

如果很有可能已经对项目进行了很好的排序,则插入排序是您的最佳选择。如果您完全不了解,那么在四种基本排序算法中,快速排序是您的最佳选择。

答案 4 :(得分:0)

可以使用sort()

使用我们的函数让JS引擎对数组进行排序:

let array=[3, 4, 1, 2, 5]
let counter=0

array.sort((a,b)=>{
  if(a<b){
    counter++ //Increase counter when swapping two elements
    return 1
  }else if(a>b){
    return -1
  }else{
    return 0
  }
})

console.log('Array:',array)
console.log('Counter:',counter)

此示例使用通用的数字排序功能,通过对交换两个元素时的计数进行扩展。

如果您不想对原始数组进行排序,则可以通过.slice()复制它:

let array=[3, 4, 1, 2, 5]
let counter=0

array.slice().sort((a,b)=>{
  if(a<b){
    counter++ //Increase counter when swapping two elements
    return 1
  }else if(a>b){
    return -1
  }else{
    return 0
  }
})

console.log('Array (unchanged):',array)
console.log('Counter:',counter)

答案 5 :(得分:0)

function minimumSwaps(arr) {

   var counter = 0;

   for (var i = arr.length; i > 0; i--) {
      var minval = Math.min(...arr); console.log("before", arr);
      var minIndex = arr.indexOf(minval);
      if (minval != = arr[0]) {
         var temp = arr[0];
         arr[0] = arr[minIndex];
         arr[minIndex] = temp; console.log("after", arr);
         arr.splice(0, 1);
         counter++;
      }
      else {
         arr.splice(0, 1); console.log("in else case")
      }

   } return counter;
}

这就是我调用交换函数的方式:

  

minimumSwaps([3,7,6,9,1,8,4,10,2,5]);

它与选择排序一起使用。逻辑如下:

  1. 遍历数组长度
  2. 如果第0个索引没有确定最小值,请查找数组中的最小元素,然后与数组中的First元素交换。
  3. 现在删除第一个元素。
  4. 如果不存在步骤2,请删除第一个元素(这是已经存在的最小值)
  5. 交换值时
  6. 增加计数器。
  7. 在for循环之后返回计数器值。

它适用于所有值。

但是,由于值约50,000超时而失败。

答案 6 :(得分:0)

此解决方案简单快捷。

function minimumSwaps(arr) {

    let minSwaps = 0;

    for (let i = 0; i < arr.length; i++) {
        // at this position what is the right number to be here
        // for example at position 0 should be 1
        // add 1 to i if array starts with 1 (1->n)
        const right = i+1;
        // is current position does not have the right number
        if (arr[i] !== right) {
            // find the index of the right number in the array
            // only look from the current position up passing i to indexOf
            const rightIdx = arr.indexOf(right, i);
            // replace the other position with this position value
            arr[rightIdx] = arr[i];
            // replace this position with the right number
            arr[i] = right;
            // increment the swap count since a swap was done
            ++minSwaps;
        }
    }

    return minSwaps;
}

答案 7 :(得分:0)

这是我的解决方案,但是它会使3个输入量很大的测试用例超时。对于较小的输入,它可以工作,并且不会因超时而终止。

function minimumSwaps(arr) {
  let swaps = 0;
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === i + 1) continue;
    arr.splice(i, 1, arr.splice(arr.indexOf(i + 1), 1, arr[i])[0]); //swap 
    swaps++;
  }
  return swaps;
}

我正在学习如何使其性能更高,欢迎任何帮助。

答案 8 :(得分:0)

这是我对JavaScript中的Main Swaps 2问题的解决方案。它通过了所有测试用例。我希望有人觉得它有用。

//this function calls the mainSwaps function..
function minimumSwaps(arr){
       let swaps = 0;

        for (var i = 0; i < arr.length; i++){
            var current = arr[i];
            var targetIndex = i + 1;
            if (current != targetIndex){
                swaps += mainSwaps(arr, i);
            }
        }

        return swaps;

}

//this function is called by the minimumSwaps function
function mainSwaps(arr, index){
    let swapCount = 0;
    let currentElement = arr[index];
    let targetIndex = currentElement - 1;
    let targetElement = arr[currentElement - 1];

    while (currentElement != targetElement){
        //swap the elements
        arr[index] = targetElement;
        arr[currentElement - 1] = currentElement;

        //increase the swapcount 
        swapCount++;

        //store the currentElement, targetElement with their new values..
        currentElement = arr[index];
        targetElement = arr[currentElement - 1];
    }

    return swapCount;
}

var myarray = [2,3,4,1,5];
var result = console.log(minimumSwaps(myarray));