4.8烧饼排序问题

4.8 递归解决烧饼排序问题

4.8.1 问题描述

给你一个整数数组 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 范围内的有效答案都将被判断为正确。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/pancake-sorting
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 假设盘子上有n块面积大小不同的烧饼,如何用一把锅铲进行若干次翻转,让这些烧饼有序地排序,小的在上,大的在下?
  • 也就是如何使用算法得到一个翻转序列,使得烧饼堆变得有序?给定数组A,我们可以对其进行多次翻转,选择一个小于等于len(A)的正整数k,如何反转A的前k个元素的顺序

4.8.2 思路分析

  • 首先来看一组样例手工分析:输入A=[3,2,4,1],算法返回[4,2,4,3]
    • [1] k = 4,A=[1,4,2,3]
    • [2] k = 2 ,A=[4,1,2,3]
    • [3] k = 4,A=[3,2,1,4]
    • [4] k = 3,A=[1,2,3,4]
  • 可以使用递归来解决这个问题,为什么说这个问题具有递归性质呢?比如我们需要实现这样一个函数(明确递归函数定义)
//cakes是一堆烧饼,函数会将前n个烧饼排序
void sort(int[] cakes,int n);
  • 如果找到前n个烧饼中最大的那个,然后设法将这个它翻转到最底下

  • 接下来,对于上面的这n-1块烧饼,如何排序呢?依然是:是先从这n-1个烧饼中找到最大的一个,然后把它放到底下,在递归调用pancakeSort(A,n-1-1)

  • 总结一下思路就是

    • 找到n个烧饼中最大的那个
    • 把这个最大的烧饼移到最底下
    • 递归调用pancakeSort(A,n-1)
    • base-case:当n==1的时候,排序1个烧饼则不需要翻转
  • 如何设法将某块烧饼翻到最后呢?

    • 比如第3块并是最大的,我们想把它换到最后,也就是换到第n块
    • 用锅铲将前3块烧饼翻转一下,这样最大的就翻到了最上面
    • 用锅铲将前n块烧饼全部翻转,这样最大的就翻到了第n块,也就是最后一块

4.8.3 代码实现

class Solution {
    private LinkedList<Integer> ans = new LinkedList<>();

    public List<Integer> pancakeSort(int[] arr) {
        sort(arr,arr.length);
        return ans;
    }
    //将前n块烧饼排序
    private void sort(int[] cakes,int n){
        //base-case
        if(n==1){
            return;
        }
        //寻找最大烧饼的索引
        int maxCake = 0;
        int maxCakeIndex = 0;
        for(int i = 0;i<n;i++){
            if(cakes[i] > maxCake){
                maxCakeIndex = i;
                maxCake = cakes[i];
            }
        }
        //第一次翻转,将最大烧饼翻到最上面
        reverse(cakes,0,maxCakeIndex);
        //记录这一次翻转
        ans.add(maxCakeIndex+1);
        //第二次翻转,将最大烧饼翻到最下面
        reverse(cakes,0,n-1);
        ans.add(n);
        sort(cakes,n-1);
    }
    private void reverse(int[] arr,int i,int j){
        while(i<j){
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i++;j--;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值