前端算法小白攻略17-leetcode(煎饼排序)

419 阅读1分钟

前言

没想到有一天我们会把摊煎饼的技术运用到算法解题上,当然是联想,我们前面做过的链表翻转就是这个道理,今天我们要实现的是数组翻转,一个道理。

题目描述

969. 煎饼排序

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

一次煎饼翻转的执行过程如下:

选择一个整数 k ,1 <= k <= arr.length 反转子数组 arr[0...k-1](下标从 0 开始) 例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。

以数组形式返回能使 arr 有序的煎饼翻转操作所对应的 k 值序列。任何将数组排序且翻转次数在 10 * arr.length 范围内的有效答案都将被判断为正确。

示例 1:

输入:[3,2,4,1]
输出:[4,2,4,3]
解释:
我们执行 4 次煎饼翻转,k 值分别为 4,2,4,和 3。
初始状态 arr = [3, 2, 4, 1]
第一次翻转后(k = 4):arr = [1, 4, 2, 3]
第二次翻转后(k = 2):arr = [4, 1, 2, 3]
第三次翻转后(k = 4):arr = [3, 2, 1, 4]
第四次翻转后(k = 3):arr = [1, 2, 3, 4],此时已完成排序。

提示:
1 <= arr.length <= 100
1 <= arr[i] <= arr.length
arr 中的所有整数互不相同(即,arr 是从 1 到 arr.length 整数的一个排列)

解题思路

  1. 此题的概要就是将一个非重复数字数组通过k次翻转得到一个升序的数字数组,而我们要获得最终的结果就是每次翻转数组元素的个数的一个集合
  2. 就是说我们每次翻转后需要将本次翻转的元素个数记录下来push到一个数组中
  3. 如何翻转?
  • 升序数组,我们可以先把数组中元素最大的给翻到最前面,左一翻,然后再右一翻,给最大的再给翻到末尾,这就完成了升序数组中一个数的翻转,记录下这两次翻转的元素个数,因为数组下标从0开始,所以每次数组最大值的索引+1就是翻转元素的记录个数,记录完后我们让翻转完成的数pop出去
  • 注意:
    1)当最大值下标索引为末位时无需翻转
    2)当最大值下标为首位时,只需要进行第二步首尾翻转
  • 如此循环遍历数组,直至数组中还剩一个元素,我们就不用再翻转了

开始解题

/**
 * @param {number[]} arr
 * @return {number[]}
 */
var pancakeSort = function(arr) {
    let curArr = arr;
    let resArr = [];
    while(curArr.length>1) { // 数组中还剩最后一个就不用再翻了
        const maxIndex = getMaxIndex(curArr); // 获取最大值下标
        if(maxIndex){
            if(maxIndex !== curArr.length-1){ // 如果最大值下标不是最后一个元素才需要翻转
                resArr.push(maxIndex+1);
                reverse(curArr,maxIndex);
                reverse(curArr, curArr.length-1);
                resArr.push(curArr.length);
            }
        }else { // 如果最大值下标为0,那么就直接进行第二步的首尾翻转
            reverse(curArr, curArr.length-1);
            resArr.push(curArr.length);
        }
        
        curArr.pop(); // 翻转之后将已完成翻转升序任务的末尾数出栈
    }
    return resArr;
};

var getMaxIndex = function(arr) {
    let maxIndex=0;
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] > arr[maxIndex]){
            maxIndex = i;
        }
    }
    return maxIndex;
}

var reverse = function(arr, maxIndex) {
    let i = 0,j = maxIndex - i; // maxIndex其实就是要翻转的末位数下标
    while(i < j) { // 这里的翻转可以简写[arr[i],arr[j]] = [arr[j],arr[i]],但是用到的内存会增加
        let temp = arr[j]; 
        arr[j] = arr[i];
        arr[i] = temp;
        i++;
        j--;
    }
}