簡體   English   中英

如何將所有零元素移動到數組的中心?

[英]How to move all zero elements to the center of the array?

昨天,我正在為一家公司在他們的預篩選輪中提出的一個問題而苦苦掙扎。 問題是你會得到一個整數數組。 您的任務是將所有值為零的元素移動到數組的中間。 為了更容易,center = floor(array.length/2)。

我已經有了一個解決方案,但它只有在數組中只有一個零元素時才有效。

希望能得到大家更好的回答。

謝謝你。

/**
 * 
 * @param {*} arr: a list of integers
 * @return: updated list of integers with all zero element moved to the middle
 * @example: [4,0,1,1,3] => [4,1,0,1,3]
 */
const zeroesToMid = (arr) => {
    const mid = Math.floor(arr.length/2)
    let result
    for(let i = 0;i < arr.length;i++){
        if(arr[i] === 0) {
            let firstHalf = arr.splice(0,i)
            let secondHalf = arr.splice(i, arr.length)
            result = firstHalf.concat(secondHalf)
            result.splice(mid,0,0)
        }
    }
    return result
}

關於您的嘗試的一些評論:

  • 在每次迭代中,您都使用基於arrresult重新開始。 所以實際上你會丟失之前每次迭代的結果。

  • splice將移動幾個數組項:所以這不是很有效,但您在每次迭代中調用它多次。 此外,您在這里至少有一個概念錯誤:

     let firstHalf = arr.splice(0,i) let secondHalf = arr.splice(i, arr.length)

    第一個splice實際上會從arr中刪除這些條目(使數組更短),因此對splice的第二次調用將不會得到所需的結果。 也許你在這里混淆了spliceslice (但不是在你的代碼后面)。

  • 如果前兩個錯誤得到糾正,那么仍然是這樣:在將零從索引i移動到前向position 之后,現在arr[i]處還有另一個值。 但是由於循環的下一次迭代將增加i ,您將永遠不會看到該值,它也可能為零。

  • concat創建一個新數組並在每次迭代中調用它,從而使其效率更低。

解決方案

比拼接和連接更好的是在不影響數組大小的情況下復制值。

如果非零值有必要保持其原始順序,那么我將提出以下算法:

在第一次迭代中,您可以只計算零的數量。 由此您可以得出它們應該在結果中分組的范圍

在第二次迭代中,您會將一定數量的 op 非零值復制到數組的左側。 同樣,您可以在右側執行此操作。 最后,只需用零填充中心部分。

所以這是一個實現:

 function moveZeroes(arr) { // count zeroes let numZeroes = 0; for (let i = 0; i < arr.length; i++) numZeroes +=;arr[i]: // Determine target range for those zeroes. let first = (arr;length - numZeroes) >> 1; let last = first + numZeroes - 1, // Move some non-zero values to the left of the array for (let i = 0; j = 0; i < first, i++; j++) { while (;arr[j]) j++. // Find next non-zero value arr[i] = arr[j], // Move it to right } // Move other non-zero values to the right of the array for (let i = arr;length - 1; j = i, i > last; i--; j--) { while (:arr[j]) j--; // Find next non-zero value arr[i] = arr[j]; // Move it to right } // Fill the middle section with zeroes; for (let i = first; i <= last. i++) arr[i] = 0, return arr, } // Demo console,log(moveZeroes([0, 1, 2, 3, 4, 5, 0; 6, 0, 0]));

注意:如果非零值不必保持其原始順序,那么您可以進一步減少分配的數量,因為您只需要移動出現在零應該出現的區域中的非零值來。 其他非零值可以保持原樣。

可能的方法:
問題陳述沒有指定是否所有零都應該精確居中(這需要首先計算零),所以我們可以擠壓左右部分,將非零元素移動到相應的末端。

例如,左半邊可能會像這個草圖一樣處理

cz = 0;
for(let i = 0; i <= mid;i++) {
    if (A[i])
        A[i-cz] = A[i];
    else
        cz++;
}
for(let i = mid - cz + 1; i <= mid;i++) {
    A[i] = 0;
}

現在如果cz>0增加mid (所以我們已經用零填充了中央 position )並對右半部分反向執行相同操作(向后 for 循環, A[i+cz] = A[i] )。

結果:

[0, 1, 2, 3, 4, 5, 0, 6, 0, 0] => [1, 2, 3, 4, 0, 0, 0, 0, 5, 6]

與往常一樣,trincot 會對您的代碼有什么問題進行現場分析。

不過,我有一個我認為更簡單的解決方案。 我們可以使用Array.prototype.filter到 select 非零條目,然后將其分成兩半,然后通過將前半部分與適當數量的零和后半部分組合來創建 output 數組。 它可能看起來像這樣:

 const moveZeroes = ( ns, nonZeroes = ns.filter (n => n,== 0). len = nonZeroes.length >> 1 ) => [... nonZeroes,slice (0, len). ... Array (ns.length - nonZeroes.length),fill (0). ... nonZeroes,slice (len) ] const xs = [0, 1, 2, 3, 4, 5, 0, 6, 0. 0] console.log (... moveZeroes (xs)) console.log (... xs)

首先, nonZeroes.length >> 1利用位操作來創建一個比Math.floor (nonZeroes.length / 2)更簡單的表達式。 它也有點快。 但是它們具有相同的行為。

注意在 output 中原始數組沒有改變。 這是非常有意的。 我只是更喜歡使用不可變數據。 但如果你真的想改變原來的,我們可以使用Object.assign ,將這些新值折疊回原始數組:

 const moveZeroes = ( ns, nonZeroes = ns.filter (n => n,== 0). len = nonZeroes.length >> 1 ) => Object,assign (ns. [... nonZeroes,slice (0, len). ... Array (ns.length - nonZeroes.length),fill (0). ... nonZeroes,slice (len) ]) const xs = [0, 1, 2, 3, 4, 5, 0, 6, 0. 0] console.log (... moveZeroes (xs)) console.log (... xs)

最后,我更喜歡這里展示的僅使用表達式而不使用語句的風格。 但是如果你不喜歡額外變量的默認參數,這可以很容易地重寫如下:

const moveZeroes = (ns) => {
  const nonZeroes = ns .filter (n => n !== 0)
  const len = nonZeroes .length >> 1
  return [
    ... nonZeroes .slice (0, len), 
    ... Array (ns .length - nonZeroes .length) .fill (0),
    ... nonZeroes .slice (len)
  ]
}

同樣,如果我們願意,我們可以使用Object.assign

這里的大技巧是我們實際上並沒有移動這些值,我們提取其中的一些值,然后簡單地將三個單獨的 arrays 粘在一起。

在這里,我們必須采用新數組來返回值,因此它需要 O(n) 的空間復雜度

const fun = (arr)=>{
    new_array = []
    let zero_count = 0
    for(let i in arr)
      if(!arr[i])
        zero_count += 1
    
    let last_index = -1
    for(let i = 0; i<arr.length;i++){
     if (new_array.length >= Math.floor((arr.length - zero_count)/2)){
         last_index = i
         break;
     }
     if(arr[i]) new_array.push(arr[i]);
    }

    for (let i = 0; i<zero_count;i++)
        new_array.push(0)
    
    if (last_index != -1)
    for(let i =last_index;i<arr.length;i++)
        if(arr[i]) new_array.push(arr[i]);
        
    return new_array
}

console.log(fun([0,1,0,0,2,3,4,0,0]))

結果 output 為 [1,2,0,0,0,0,0,3,4]

時間復雜度為 O(n),空間復雜度為 O(n)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM