问题描述
引用自以下博客
星期五的晚上,一帮同事在希格玛大厦附近的“硬盘酒吧”多喝了几杯。程序员多喝了几杯之后谈什么呢?自然是算法问题。有个同事说:“我以前在餐 馆打工,顾客经常点非常多的烙饼。店里的饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好——小的在上面,大的在下面。由于我 一只手托着盘子,只好用另一只手,一次抓最上面的几块饼,把它们上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。我后来想,这实际上是个 有趣的排序问题:假设有n块大小不一的饼,那最少要翻几次,才能达到最后大小有序的结果呢?你能否写出一个程序,对于n块大小不一的烙饼,输出 最优化的翻饼过程呢?
问题解法
首先,我们将最大和最上面的烙饼的位置倒换:
接下来,我们将中间夹着的部分在进行翻转得到如下的饼堆:
再接下来,我们将最上面和最下面的互换,并将中间的饼再翻转:
由于翻转过后,我们恒知道有一块饼最终将不参与排序,这也就意味着我们最多只需要重复n-1
次的排序操作即可。
代码编写
class MyPanCake:
def __init__(self,cakeCounts=5) -> None:
self.cakeCounts = cakeCounts
self.cakes = [] # 创建一个放饼的“盘子”
self.makeCakes()
self.result = [] # 创建一个排好序的盘子“副本”
def makeCakes(self):
# 创建一个元组列表,分别存储饼的编号和大小
self.cakes = [(i+1,self.cakeCounts - i) for i in range(self.cakeCounts)]
print(self.cakes)
def sortCakes(self):
for i in range(self.cakeCounts-1):
# 取出最大的那一张饼
largest = max(self.cakes,key=lambda x:x[1])
largestIndex = self.cakes.index(largest)
# 临时拿个盘子存着这张病
temp = self.cakes[largestIndex]
# 判断第一张饼是不是最大的饼
if largestIndex == 0:
# 如果是,则忽略
pass
else:
# 如果不是,则将最大的那张饼放到最上面,并把最上面的饼放到最大的那张饼的位置
self.cakes[largestIndex] = self.cakes[0]
self.cakes[0] = temp
# 将中间部分翻转
self.cakes[1:-1].reverse()
# 将最大的那张饼放到最下面
theLast = self.cakes[-1]
self.cakes[-1] = self.cakes[0]
self.cakes[0] = theLast
# 再将中间部分翻转
self.cakes[1:-1].reverse()
# 将最后一块饼从前向后插入到结果中
self.result.append(self.cakes[-1])
print(f"Cakes left : {self.cakes}")
# 将最后一块饼从饼堆中删除
self.cakes.pop(-1)
# 最后一块饼堆里的饼就是排序后的“最底下”的那块饼
self.result.append(self.cakes[0])
# 将结果翻转,使其从小到大排列
self.result.reverse()
def getResult(self):
print(f"Cakes after sorting (ascending=True) : {self.result}")
if __name__ == "__main__":
cake = MyPanCake()
cake.sortCakes()
cake.getResult()
运行结果
Cakes on plate are : [(1, 5), (2, 4), (3, 3), (4, 2), (5, 1)]
Cakes left : [(5, 1), (2, 4), (3, 3), (4, 2), (1, 5)]
Cakes left : [(4, 2), (5, 1), (3, 3), (2, 4)]
Cakes left : [(4, 2), (5, 1), (3, 3)]
Cakes left : [(5, 1), (4, 2)]
Cakes after sorting (ascending=True) : [(5, 1), (4, 2), (3, 3), (2, 4), (1, 5)]