【问题标题】:Reverse array in-place using split-merge method使用拆分合并方法就地反转数组
【发布时间】:2022-01-23 12:01:18
【问题描述】:

我正在尝试就地反转 JS 中的数组(不使用额外的数组)。 我正在使用 split-merge recursive (我首先将数组分成两半,然后分别重新排列每一半,然后结合两种排列的结果)。 如果数组长度为奇数,则似乎会出现问题,在这种情况下,将存在一个包含单个项目的数组和另一个包含两个项目的数组。

例子

reverseArrayInPlace([1, 5, 0, 4, 6]) 应该像这样工作:

1- reverseArrayInPlace([1,5,0]) -> 返回以下调用

  • reverseArrayInPlace([1, 5]) -> 返回 [5, 1]
  • reverseArrayInPlace([0]) -> 返回 [0]

现在应该合并和交换第一次调用的两个数组。结果应该是 [0,5,1]

2- reverseArrayInPlace([4, 6]) -> 返回 [6,4]

现在,调用 (1) 和调用 (2) 的结果必须合并和交换(也使用 concat); 这将使结果为:[6,4,0,5,1]。

我知道还有其他更简单的方法,但我想知道为什么我的代码没有返回正确的值。

let reverseArrayInPlace = ar => {

    let splitArray = arr => {
        if( arr.length === 1){
            console.log('length = 1', arr);
            return arr;
        }
        else if(arr.length === 2){
            console.log('length = 2', arr);
            let temp = arr[0]; arr[0] = arr[1]; arr[1] = temp;
            return arr;
        }
        else{
            reverseArrayInPlace(arr);
            //reverseArrayInPlace (ar2);
        }
    }
    let mergeArray = (arr1, arr2) => {
        console.log("Swapping : ", arr1, arr2);
        console.log('Concated : ',arr2.concat(arr1));

        if(arr1 === undefined)
            return arr2;
        else if(arr2 === undefined)
            return arr1;
        else
            return arr2.concat(arr1);
    }
    let half = Math.ceil(ar.length / 2);
    //console.log('half = ', half);

    ar1 = splitArray(ar.slice(0, half));
    ar2 = splitArray(ar.slice(half));
    //console.log(arr1, arr2);
    return mergeArray(ar1, ar2);
    
}
let ar = [1, 5, 0, 4, 6];
console.log(reverseArrayInPlace(ar));

【问题讨论】:

  • array.slice(), array.concat() 使用更多空间,因为返回一个新数组...
  • 我知道,但我在这里关心的是在代码中找到不会使递归过程得到正确结果的东西。
  • 你知道有一个reverse 方法,对吧?
  • 是的,但是玩递归是一件非常美妙的事情。

标签: javascript algorithm


【解决方案1】:

在您的拆分数组函数中,您错过了return

 let splitArray = arr => {
        if( arr.length === 1){
            console.log('length = 1', arr);
            return arr;
        }
        else if(arr.length === 2){
            console.log('length = 2', arr);
            let temp = arr[0]; arr[0] = arr[1]; arr[1] = temp;
            return arr;
        }
        else{
            ***RETURN*** reverseArrayInPlace(arr);
            //reverseArrayInPlace (ar2);
        }
    }

我在 chrome navigateur 中使用调试器一步一步地进行,并注意到您的 step 1- reverseArrayInPlace([1,5,0]) -> returns the below calls 上的 ar1 为空 所以结果只包含第二部分:反转的第二个数组[6,4]

【讨论】:

  • 是的。谢谢弗洛伦特。我知道这很简单,但如果没有你的帮助,我无法理解。谢谢。
【解决方案2】:

缺少return 语句是最初的问题,但更广泛地说,这不是真正的inplace 算法,因为它仍然通过创建新数组来保留O(n) 辅助内存。

对于一个就地算法,不应该有 O(n) 的辅助内存使用。相反,还要创建 splitArraymergeArray 就地函数,以便始终只有一个数组被变异。

为此,您需要传递将成为拆分/合并操作主题的子数组的开始/结束索引。

splitArray 的第一个基本情况中包含空数组情况也更安全:所以使用<= 1 而不是=== 1

以下是您根据该想法更改的代码:

let reverseArrayInPlace = (arr, start=0, end=ar.length) => {

    let splitArray = (start, end) => {
        if (end - start <= 1) return;
        if (end - start === 2) {
            let temp = arr[start]; arr[start] = arr[start+1]; arr[start+1] = temp;
        }
        else{
            reverseArrayInPlace(arr, start, end);
        }
    }
 
    let mergeArray = (start, mid, end) => {
        arr.splice(start, 0, ...arr.splice(mid, end - mid));
    }

    let half = (start + end) >> 1;
    splitArray(start, half);
    splitArray(half, end);
    mergeArray(start, half, end);
    return arr;
}

let ar = [1, 5, 0, 4, 6];
console.log(reverseArrayInPlace(ar));

您也不需要单独处理第二种基本情况。如果您将这种情况作为递归情况处理,则该操作将正常工作。

以下是您根据该想法更改的代码:

let reverseArrayInPlace = (arr, start=0, end=ar.length) => {

    let splitArray = (start, end) => {
        if (end - start > 1) reverseArrayInPlace(arr, start, end);
    }
  
    let mergeArray = (start, mid, end) => {
        arr.splice(start, 0, ...arr.splice(mid, end - mid));
    }
  
    let half = (start + end) >> 1;
    splitArray(start, half);
    splitArray(half, end);
    mergeArray(start, half, end);
    return arr;
}

let ar = [1, 5, 0, 4, 6];
console.log(reverseArrayInPlace(ar));

【讨论】:

    猜你喜欢
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 2021-04-05
    • 2019-11-02
    • 1970-01-01
    • 2011-04-01
    相关资源
    最近更新 更多