leetcode_1046_最后一块石头的重量

该博客介绍了如何利用Python解决一个关于石头粉碎的问题,即找到最后剩余的一块石头的重量。文章通过两种方法实现了一个大顶堆:一是使用Python内置的heapq库,二是自定义堆类。在每一轮中选取最重的两块石头进行粉碎,直至只剩一块石头或没有石头。最后给出了示例和解题思路,并提供了完整的代码实现。
摘要由CSDN通过智能技术生成

最后一块石头的重量

描述

简单

有一堆石头,每块石头的重量都是正整数。

每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为 xy,且 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值