煎饼排序问题

题目

(1)给你一个整数数组 arr ,请使用 煎饼翻转 完成对数组的排序。
(2)一次煎饼翻转的执行过程如下:

  • 选择一个整数 k ,1 <= k <= arr.length
  • 反转子数组 arr[0…k-1](下标从 0 开始)

(3)例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。
(4)以数组形式返回能使 arr 有序的煎饼翻转操作所对应的 k 值序列。任何将数组排序且翻转次数在 10 * arr.length 范围内的有效答案都将被判断为正确。
(5)示例如下:
输入:[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个元素到第k-1个元素,每完成一次反转,就记录下k的值。直到数组变成有序递增数组时停止反转,然后输出记录的所有的k值。
  • 思路:先找到数组中最大的元素,将其反转到数组的最后一位;再找到数组中第二大的元素,将其反转到数组的倒数第二位,依次重复。
  • 具体方法:
    • 先找到数组中最大的元素,并将其反转到数组的第一个位置,再将其反转到数组的最后一个位置。
    • 然后找到数组中第二大的元素,并将其反转到数组的第一个位置,再将其反转到数组的倒数第二个位置。
    • 重复上述两步操作,直到整个数组变为有序递增的数组时停止反转。

代码

  • C++代码
# include <stdio.h>
# include <vector>

using namespace std;

class Solution {
public:
    // 对arr的第1个元素到第n-1个元素进行反转,并将反转后每个元素在arr中的索引更新到idx数组中
    void reverse(vector<int>& arr, int n, vector<int>& idx) {
        for (int i = 0, j = n - 1; i < j; i++, j--) {
            swap(arr[i], arr[j]);
            idx[arr[i]] = i;
            idx[arr[j]] = j;
        }
    }

    vector<int> pancakeSort(vector<int>& arr) {
        vector<int> idx(arr.size() + 1);    // 记录arr的每个元素在arr数组中的索引
        vector<int> ret;        // 存放k的值
        int k = 0;

        // 记录arr的每个元素在arr中的索引,由题知,arr中的元素是从1到arr.length的一个整数排列,则arr[i]的最小值为1,
        // 对应到idx中,则索引是从1开始存储值的,因此idx的大小是arr.size() + 1
        for (int i = 0; i < arr.size(); i++) {
            // 技巧:索引是0、1、2、3...递增的,arr中值最大的数对应着idx的最大索引,arr中第二大的数对应着idx
            // 的第二大索引,则根据idx的索引能依次找到arr中从小到大的值。
            idx[arr[i]] = i;
        }

        
        // 从arr的最大值开始反转
        for (int i = arr.size(); i >= 1; i--) {
            
            // 第一步:将arr的最大值反转到arr的第1个位置。
            if (idx[i] != 0) {      // idx[i]的值为arr的元素在arr中的索引,当索引为0时,只有一个元素,此时不需要反转
                k = idx[i] + 1;     // 煎饼反转的策略是反转第1个元素到第k-1个元素,反转时要包含最大的值,因此索引要加1
                ret.push_back(k);
                reverse(arr, k, idx);   // 对arr的第1个元素到第k-1个元素进行反转,并将反转后元素在arr中的索引更新到idx中。
            }

            // 第二步:将arr的最大值从第1个位置反转到最后一个位置。
            if (i != 1) {       // i=1对应着arr的索引0,此时只有1个元素,1个元素不需要反转。
                k = i;
                ret.push_back(k);
                reverse(arr, k, idx);
            }
        }
        return ret;
    }
};


int main() {
    vector<int> arr;
    arr.push_back(3);
    arr.push_back(2);
    arr.push_back(4);
    arr.push_back(1);

    Solution *solution = new Solution();
    vector<int> ret = solution->pancakeSort(arr);

    for (int i = 0; i < ret.size(); i++) {
        printf("%d  ", ret[i]);
    }
    return 0;
}
  • Python代码
# -*- coding: utf-8 -*-

from typing import List


class Solution:
    # 对arr的第1个元素到第k - 1个元素进行反转,并将反转后每个元素在arr中的索引更新到idx数组中
    def reverse(self, arr, k, idx):
        i = 0
        j = k - 1
        while i < j:
            arr[i], arr[j] = arr[j], arr[i]
            idx[arr[i]] = i
            idx[arr[j]] = j
            i += 1
            j -= 1

    def pancakeSort(self, arr: List[int]) -> List[int]:
        idx = [-1 for i in range(len(arr) + 1)]     # 记录arr的每个元素在arr数组中的索引
        ret = []        # 存放k的值
        k: int = 0

        # 记录arr的每个元素在arr中的索引,由题知,arr中的元素是从1到arr.length的一个整数排列,则arr[i]的最小值为1,
        # 对应到idx中,则索引是从1开始存储值的,因此idx的大小是arr.size() + 1
        for i in range(len(arr)):
            # 技巧:索引是0、1、2、3...递增的,arr中值最大的数对应着idx的最大索引,arr中第二大的数对应着idx
            # 的第二大索引,则根据idx的索引能依次找到arr中从小到大的值。
            idx[arr[i]] = i

        # 从arr的最大值开始反转
        for i in range(len(arr), 0, -1):

            # 第一步:将arr的最大值反转到arr的第1个位置。
            if idx[i] != 0:     # idx[i]的值为arr的元素在arr中的索引,当索引为0时,只有一个元素,此时不需要反转
                k = idx[i] + 1  # 煎饼反转的策略是反转第1个元素到第k-1个元素,反转时要包含最大的值,因此索引要加1
                ret.append(k)
                self.reverse(arr, k, idx)   # 对arr的第1个元素到第k-1个元素进行反转,并将反转后元素在arr中的索引更新到idx中。

            # 第二步:将arr的最大值从第1个位置反转到最后一个位置。
            if i != 1:      # i=1对应着arr的索引0,此时只有1个元素,1个元素不需要反转。
                k = i
                ret.append(k)
                self.reverse(arr, k, idx)

        return ret


def main():
    solution = Solution()
    arr = [3, 2, 4, 1]
    ret = solution.pancakeSort(arr)
    print(ret)


if __name__ == "__main__":
    main()

说明

  • 对应LeetCode第969题。
  • 链接:https://leetcode-cn.com/problems/pancake-sorting/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值