最后一块石头的重量
描述
简单
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为 x
和 y
,且 x <= y
。那么粉碎的可能结果如下:
- 如果
x == y
,那么两块石头都会被完全粉碎; - 如果
x != y
,那么重量为x
的石头将会完全粉碎,而重量为y
的石头新重量为y-x
。
最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。
示例:
输入:[2,7,4,1,8,1]
输出:1
解释:
先选出 7 和 8,得到 1,所以数组转换为 [2,4,1,1,1],
再选出 2 和 4,得到 2,所以数组转换为 [2,1,1,1],
接着是 2 和 1,得到 1,所以数组转换为 [1,1,1],
最后选出 1 和 1,得到 0,最终数组转换为 [1],这就是最后剩下那块石头的重量。
提示:
1 <= stones.length <= 30
1 <= stones[i] <= 1000
解题
每次粉碎后再选最重的石头,及每次都要重新排序
这里选择大顶堆
但python自带的堆是小顶堆,可以先取负数
from typing import List
import heapq
class Solution:
def lastStoneWeight(self, stones: List[int]) -> int:
heap = [-stone for stone in stones]
heapq.heapify(heap)
while len(heap) > 1:
x = heapq.heappop(heap)
y = heapq.heappop(heap)
if x != y:
heapq.heappush(heap, x - y)
return -heap[0] if len(heap) == 1 else 0
或者自己简单实现一个堆(具体堆的介绍这里不展开)
class Solution:
def lastStoneWeight(self, stones: List[int]) -> int:
heap = MyHeap(desc=True)
for stone in stones:
heap.push(stone)
print(heap.heap)
while heap.size > 1:
x = heap.pop()
y = heap.pop()
if x != y:
heap.push(x - y)
return heap.top() if heap.size == 1 else 0
class MyHeap:
def __init__(self, desc=False):
'''
初始化
:param desc: 默认小顶堆
'''
self.heap = []
self.desc = desc
@property
def size(self):
return len(self.heap)
def top(self):
if len(self.heap) > 0:
return self.heap[0]
return None
def push(self, element):
self.heap.append(element)
self._sift_up(self.size - 1)
def pop(self):
self._swap(0, self.size - 1)
element = self.heap.pop()
self._sift_down(0)
return element
def _swap(self, i, j):
self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
def _cmp(self, a, b):
'''
当desc为False,表示小顶堆,返回 a < b表示需要进行交换
当desc为True,表示大顶堆,返回 a > b表示需要进行交换
:param a:
:param b:
:return:
'''
return a < b if self.desc else a > b
def _sift_up(self, index):
'''
自下向上调整
当当前节点和父节点需要调整时,进行调整
:param index: 当前节点的下标
:return:
'''
while index:
parent = (index - 1) // 2
if self._cmp(self.heap[index], self.heap[parent]):
break
self._swap(index, parent)
index = parent
def _sift_down(self, index):
'''
自上向下调整
当当前节点和左右子节点需要调整时,进行调整
:param index: 当前节点的下标
:return:
'''
while 2 * index + 1 < self.size:
cur = index
left = 2 * index + 1
right = 2 * index + 2
if self._cmp(self.heap[cur], self.heap[left]):
cur = left
if right < self.size and self._cmp(self.heap[cur], self.heap[right]):
cur = right
if cur == index:
break
self._swap(cur, index)
index = cur