767 重构字符串(大根堆--贪心)

1. 问题描述:

给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。若可行,输出任意可行的结果。若不可行,返回空字符串。

示例 1:

输入: S = "aab"
输出: "aba"

示例 2:

输入: S = "aaab"
输出: ""

注意:

  • S 只包含小写字母并且长度在[1, 500]区间内。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reorganize-string

2. 思路分析:

① 一开始的时候没有啥思路,感觉处理起来很麻烦,于是看了一下官网的题解,发现提供的方法一的基于大根堆的贪心算法很巧妙,也很好理解可以学习一下其中的思路,首先需要判断判断是否存在可行的结果,我们可以使用字典来统计字符串中各个字符出现的次数,可以发现当字符串中字符的最大出现次数如果大于(len(S) + 1) // 2肯定没有可行的答案的,直接返回空串即可,当存在可行答案的我们先构建一个列表,遍历字典并且将字符出现的次数以及当前的字符形成一个元祖加入到列表中,因为使用的是python语言,所以可以使用python中的标准库heapq模块中的heapify方法将列表转换为小根堆,然后遍历这个列表,每一次的时候都弹出堆顶的两个元素,因为我们希望每一次拿取的的字符出现的次数都是最大的,而heapq模块形成的是小根堆(小根堆堆顶元素是最小的)所以我们在将列表转换为小根堆的时候需要在元组的第一个元素字符出现的次数前加上一个负号这样次数越大的就会排列在堆的前面,这相当于形成的是大根堆),每一次从堆中拿取两个字符,然后字典对应的字符数目减1,我们在拿取字符的时候因为是需要维持堆的不变形,所以需要使用heappop方法来弹出元素,并且拿取当前的两个字符之后假如次数还是大于0那么我们还将字符出现的次数以及对应的字符形成的元组加入到列表中,加入元素的时候同样需要维持堆的不变性,所以需要使用heappush加入元素,并且只有当列表中的元素大于1的时候才执行循环,因为每一次都拿取两个字符,所以当字符串的长度为奇数的时候会剩下一个字符串,所以循环结束之后需要将最后一个字符添加到结果集中,官网提供的动画感觉很容易理解这个大根堆的做法

② 主要是每一次拿取的两个字符都是出现次数最大的,而且在添加与弹出元素的时使用到了heapq模块的方法所以会在修改堆的时候会维持堆的不变性,下面是力扣中的一张图片:

767 重构字符串(大根堆--贪心)_第1张图片

3. 代码如下:

import collections
import heapq


class Solution:
    def reorganizeString(self, S: str) -> str:
        if len(S) < 2: return S
        dic = collections.defaultdict(int)
        for c in S:
            dic[c] += 1
        count = max(dic.values())
        if count > (len(S) + 1) // 2: return ""
        # heapq默认创建的是小根堆, 将列表初始化为一个堆, 第一个参数使用负数是使得次数较大的排列在前面也就是相当于创建的是大根堆
        queue = [(-x[1], x[0]) for x in dic.items()]
        # 将列表转化为一个小根堆
        heapq.heapify(queue)
        res = ""
        while len(queue) > 1:
            # 弹出并返回heap的最小元素
            t1, letter1 = heapq.heappop(queue)
            t2, letter2 = heapq.heappop(queue)
            res += letter1
            res += letter2
            # 对应字母的次数减1
            dic[letter1] -= 1
            # 对应字母的次数减1
            dic[letter2] -= 1
            if dic[letter1] > 0:
                heapq.heappush(queue, (-dic[letter1], letter1))
            if dic[letter2] > 0:
                heapq.heappush(queue, (-dic[letter2], letter2))
        # 处理字符串长度为奇数只剩下一个字符的情况
        if queue:
            res += queue[0][1]
        return res

 

你可能感兴趣的:(力扣,堆)