一日一题:煎饼排序

225 阅读2分钟

给你一个整数数组 arr ,请使用 煎饼翻转 **完成对数组的排序。

大致思路可以:

数组中的元素都不相同

    1. 首先找到最大的数的位置,将其翻转到队首,然后翻转整个数组,最大的数就到队尾了
    1. 然后找到第二大的数,将其翻转到队首,然后翻转除了最大数之外的整个数组,第二大的数也处于对于正确的位置
    1. 以此类推...

根据下图可以更好的理解:

image.png

① 对于[3, 2, 4, 1],第一次最大的值是4,首先选择位置k = 3将它翻转至队首,然后选择位置k = 4翻转,此时得到的数组为[1, 3, 2, 4]4已ready。

② 对于[1, 3, 2, 4],不考虑43是最大值,将3通过选择k = 2翻转到队首,然后选择位置k = 3(除4之外)翻转队列,得到[2, 1, 3, 4], 此时3已ready。

③ 对于[2, 1, 3, 4],不考虑342是最大值,2已处于队首,选择位置k = 2翻转到除34外最大值的位置,得到[1, 2, 3, 4],排序完成

代码实现的时候,需要考虑:

  • 当最大值已处于排序之后的位置,就不需要操作
  • 如果处于队首,翻转至队首的操作也可以忽略

注意题目中表明,这个对实现很有帮助

  • arr 中的所有整数互不相同(即,arr 是从 1 到 arr.length 整数的一个排列)

这个对的

var pancakeSort = function(arr) {
    const N = arr.length
    // arr是从1到arr.length的一个排列
    // 那么第一个最大值应该是 arr.length
    let right = N
    const result = []
    while(right > 0) {
        // 如果队尾已是最大值,继续找下一个最大值
        if (arr[right - 1] === right) {
            right--
            continue
        }
        // 找到最大值的位置
        const index = arr.indexOf(right)
        if (index !== 0) {
            // 如果不在队首,将其翻转到队首
            arr = reverseByIdx(arr, index + 1)  
            result.push(index + 1) 
        }    
        // 翻转到队尾
        arr = reverseByIdx(arr, right)
        // 收集答案
        result.push(right)
        right--           
    }
    return result
};

// 将array中的[1, idx)进行翻转
const reverseByIdx = (arr, idx) => {
    const s = arr.slice(0, idx)
    s.reverse()
    return s.concat(arr.slice(idx))
}
  • 时间复杂度: O(n^2),寻找最大值扫描一次,翻转进行了两次扫描
  • 空间复杂度: O(1)