难度:中等
目录
一、问题描述
这里直接采用LeetCode上面的描述。
给你一个整数数组 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 <= arr.length <= 100
- 1 <= arr[i] <= arr.length
- arr 中的所有整数互不相同(即,arr 是从 1 到 arr.length 整数的一个排列)
二、思路
1、解题思路
根据题目中的信息,一次煎饼翻转 可以完成对前面 n 个元素的翻转。
即:
- 从原来的序列:;
- 翻转为:。
因此我们可以在 k 个元素中,找到一个最大的元素的下标为 index 然后执行下操作:
- 将 index 以及之前的所有元素进行 煎饼翻转,可以将 当前最大元素 置于 首部。
- 在将当前剩下的所有元素 i 个元素进行 煎饼翻转,可以将 当前最大元素 置于 尾部。
由上面可知,进行 两次煎饼翻转 就能够将一个最大数置于末尾。
因此遍历完 arr,即可完成煎饼排序。
2、极端情况判断
- 每次找到 当前最大值 的下标后,如果该最大值就是在当前末尾,在进行翻转的话是无效翻转。
3、极端情况解决
- 每次找到 当前最大值 的下标后,要进行判断该最大值是否已经在末尾,如果已经在末尾则直接进行下一次判断。
三、解题
1、代码实现
class Solution {
public:
vector<int> pancakeSort(vector<int>& arr) {
vector<int> ans;
//每次执行一次煎饼翻转,能够将剩余一个最大的数翻转到 当前末尾
for(int i = arr.size(); i > 1; i--){
//max_element 返回区间内 最大值的物理地址
//通过物理地址相减 获得当前 最大值的 下标位置
int index = max_element(arr.begin(), arr.begin() + i) - arr.begin();
//如果当前最大值已经是最后一位 则不需要进行煎饼翻转
if(index == i - 1){
continue;
}
//将最大值 煎饼翻转到首位
reverse(arr.begin(),arr.begin() + index + 1);
//将当前 首位 的最大值 煎饼翻转到当前末尾
reverse(arr.begin(),arr.begin() + i );
ans.push_back(index + 1);
ans.push_back(i);
}
return ans;
}
};
2、时间复杂度 and 空间复杂度
时间复杂度:,n 为 arr 的大小
空间复杂度:
四、总结
这题的核心思想就是,每次通过两次翻转,将当前最大数,置于尾部。遍历完后,就完成排序了,这里用到了 max_element( ); 函数。该函数的功能是:返回范围内最大数的物理地址,解引用的话返回的则是最大值;这里通过地址相减返回了该最大值的下标。