Problem 969

Abstract / Summary

Arrange a list of numbers by repeatedly flipping sections to sort them into increasing order

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 0969.py

class Solution:
    def pancakeSort(self, arr: List[int]) -> List[int]:
        for need in range(len(arr), 0, -1):
            where = arr.index(need)
            # already at correct position
            if where == len(arr):
                continue

            # flip largest value to front
            arr[:where + 1] = arr[:where + 1][::-1]
            yield where + 1

            # flip it to its final position and remove it
            arr = arr[1:need][::-1]
            yield need
15 lines | 509 bytes | submitted November 28, 2023 | GitHub   30% comment ratio | tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 0% (0k+ submissions).
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The provided implementation defines a Solution class with a pancakeSort method that produces a sequence of flip operations required to sort an input list of distinct integers using the pancake sorting technique. The method is written as a generator, yielding each flip size as it is determined, which allows the caller to consume the operations lazily.

Core Logic

The algorithm proceeds by iterating over the target values in descending order, from the largest element down to 1. For each target value (need), it first locates the current position of that value in the working list (where = arr.index(need)). If the element is already positioned at the end of the unsorted portion, the loop skips further work for that iteration.

When the element is not at its final location, two flips are performed:

  1. Bring the target to the front - the slice up to and including where is reversed, moving the desired element to index 0. The size of this flip (where + 1) is yielded.

    arr[:where + 1] = arr[:where + 1][::-1]
    yield where + 1
  2. Move the target to its final position - the prefix that now contains the target is reversed again, this time covering the whole unsorted prefix (need). The slice operation also discards the element that has just been placed correctly, effectively shrinking the working list for the next iteration. The size of this second flip (need) is yielded.

    arr = arr[1:need][::-1]
    yield need

The loop continues until all values have been positioned, at which point the generator exhausts.

Edge-Case Handling

The code gracefully handles several boundary conditions without explicit branching:

  • Single-element input - The outer loop runs once with need = 1. The index of 1 is 0, the condition where == len(arr) is false, so the element is flipped to the front (a no-op) and then the second flip reduces the list to an empty slice. The generator yields 1 twice, which is a valid sequence for a single element.

  • Element already at its final spot - When where equals the length of the current working list, the continue statement skips both flips, avoiding unnecessary work.

  • Target already at the front - If where is 0, the first slice reversal is a no-op but still yields 1. The subsequent slice arr[1:need][::-1] correctly removes the front element and reverses the remaining prefix, preserving the algorithm’s invariant.

  • Empty list - The range in the outer loop evaluates to an empty sequence, so the generator produces no output, which is appropriate for an already sorted (trivially empty) collection.

Performance Optimizations

Several choices in the implementation contribute to efficient execution:

  • In-place slice reversal - The first flip modifies the original list segment directly (arr[:where + 1] = ...), avoiding the allocation of a new list for that operation.

  • Progressive reduction of the working list - By reassigning arr to a sliced and reversed sub-list (arr = arr[1:need][::-1]), the algorithm discards the portion that has already been sorted. This reduces the size of subsequent index searches and slice operations, leading to fewer element inspections as the loop advances.

  • Generator pattern - Using yield streams each flip size as soon as it is known, eliminating the need for an intermediate collection to store all results. This reduces memory pressure, especially for large inputs where the number of flips can be proportional to the list length.

  • Direct use of list.index - The built-in index method is implemented in C and provides fast linear search for the target value, which is generally faster than a manual Python loop.

Overall, the method combines concise Pythonic constructs with careful in-place modifications and lazy output generation to achieve an effective pancake sorting routine.

written by openai gpt

ELI5 - Simplified Explanation

Imagine a stack of pancakes sitting on a plate. Some are big and some are small, but they are all mixed up. To make a neat stack, all the big ones should be at the bottom and the small ones should be at the top.

Because flipping the whole stack is the only way to move them, think of a giant spatula sliding under the pancakes to turn them over. The code looks for the biggest pancake that is still in the wrong spot and slides the spatula under it. By flipping them, that big pancake moves to the very top. Then, another flip moves it all the way down to the bottom where it belongs.

The code repeats this process over and over. It picks the next biggest pancake, moves it to the top, then sends it to its new home at the bottom. Each time a pancake finds its final spot, the pile gets a little bit smaller because that pancake is finished. Eventually, every pancake is sorted from smallest on top to biggest on the bottom, just like a perfect breakfast tower. Every time a flip happens, the code remembers the move.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 27 | median = 3 | μ = 4.22 | σ = 2.02

Complexity Analysis

Time: polynomial
As a rule of thumb, the maximum input size for one second execution time is
  • factorial: up to 10 elements
  • exponential: up to 20 elements
  • polynomial: a few thousand elements
  • loglinear: up to 100,000 elements
  • linear: a few million elements
  • logarithmic: a billion elements
  • constant: practically unlimited
generated automatically

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Rust Go TS
LeetcodeHelp C++ Python Java
Progiez C++ Python Java
github aylei Rust
BigEggStudy C#
black-shadows C++
charles-wangkai Java
everthis JS
fpdjsns C++
fsq C++
halfrost Go
haoel Python
JoshCrozier JS
keineahnung2345 C++
lkwq007 Python
MacJim C++
suxrobGM C#
trung-hn Python
varunu28 Java
XiaotaoGuo C++
YuriSpiridonov Python
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, Python, Rust, TypeScript
LeetcodeHelp C++, Java, Python
Progiez C++, Java, Python
aylei Rust
BigEggStudy C#
black-shadows C++, C++
charles-wangkai Java
everthis JavaScript
fpdjsns C++
fsq C++
halfrost Go
haoel Python
JoshCrozier JavaScript
keineahnung2345 C++
lkwq007 Python
MacJim C++
suxrobGM C#
trung-hn Python
varunu28 Java
XiaotaoGuo C++
YuriSpiridonov Python
37 links | 23 authors | 8 languages

Videos

3 videos   did my crawler come up with invalid videos ? drop me a line.

Solved On The Same Day

10 solutions   November 28, 2023

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality