LeetCode_堆(1-10)

  1. 第215题:数组中的第k个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

解法一:排序,再返回倒数第k个元素。
但是堆排序的时间复杂度:O(nlogn),空间复杂度O(1),这个时间复杂度并不理想,让我们试着用额外空间来优化时间复杂度。

代码1:

class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        nums.sort()
        return nums[-k]

解法二:创建一个小顶堆,将所有数组中的元素加入堆中,并保持堆的大小小于等于 k。这样,堆中就保留了前 k 个最大的元素。这样,堆顶的元素就是正确答案。
(python自带的heapq模块实现的是最小堆,没有提供最大堆的实现。)

向大小为 k 的堆中添加元素的时间复杂度为 O(logk),我们将重复该操作 N 次,故总时间复杂度为 O(nlogk)。

在 Python 的 heapq 库中有一个 nlargest 方法,具有同样的时间复杂度,能将代码简化到只有一行。

本方法优化了时间复杂度,但需要O(k) 的空间复杂度,用于存储堆元素。

代码2:

class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        return heapq.nlargest(k,nums)[-1]
                    
  1. 第264题: 丑数II

编写一个程序,找出第 n 个丑数。

丑数就是只包含质因数 2, 3, 5 的正整数。

示例:

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:

1 是丑数。
n 不超过1690。

思想:2种思想。堆和动态规划:
(1)堆:最小堆。因为丑数是2,3,5的倍数,我们要不断地把它们的倍数压入堆中,再按顺序弹出。要注意比如6(2×3,3×2),这种就要弹出两次。也有可能数字是要弹出多次的。所以要写while循环,弹出重复的最小数字。

时间复杂度:nlogn

class Solution(object):
    def nthUglyNumber(self, n):
        """
        :type n: int
        :rtype: int
        """
        heap = [1]
        heapq.heapify(heap)   # 列表转换成堆
 
        for _ in range(n):
            result = heapq.heappop(heap) # 弹出最小值,也就是第一位heap[0]
            while heap and result == heap[0]:
                 result = heapq.heappop(heap)
            a,b,c = result*2,result*3,result*5  #要准备把倍数,推入堆中
            for t in [a,b,c]:
                heapq.heappush(heap,t)
        return result

(2) 动态规划。

后面的丑数一定是由前面的丑数乘以2、3或5得到。所以第n个丑数一定是由前n-1个数中的某3个丑数(分别记为index2、index3、index5)分别乘以2、3或者5得到的数中的最小数, 即第n个丑数由 [index2]*2、[index3]*3、[index5]*5中的最小数得出。循环中,让它们分别和当前第n个丑数比较,若和当前第n个丑数相等,则更新它们的值。注:一次最少更新一个值(如遇到当前第n个丑数是6时,index2和index3都要更新)。

class Solution(object):
    def nthUglyNumber(self, n):
        """
        :type n: int
        :rtype: int
        """
        idx2 = 0
        idx3 = 0
        idx5 = 0
        res = [1]
        while len(res)<n:
            res.append(min(res[idx2]*2, res[idx3]*3, res[idx5]*5))
            if res[idx2]*2 == res[-1]:
                idx2 +=1
            if res[idx3]*3 == res[-1]:
                idx3 +=1
            if res[idx5]*5 == res[-1]:
                idx5 +=1
        return res[-1]

附:回顾第263题:丑数(简单题)

编写一个程序判断给定的数是否为丑数。

丑数就是只包含质因数 2, 3, 5 的正整数。

示例 1:

输入: 6
输出: true
解释: 6 = 2 × 3
示例 2:

输入: 8
输出: true
解释: 8 = 2 × 2 × 2
示例 3:

输入: 14
输出: false
解释: 14 不是丑数,因为它包含了另外一个质因数 7。

说明:

1 是丑数。
输入不会超过 32 位有符号整数的范围: [−2^31, 2^31 − 1]。

class Solution(object):
    def isUgly(self, num):
        """
        :type num: int
        :rtype: bool
        """
        if num <= 0:
            return False
        for i in [2,3,5]:
            while num%i == 0:
                num /= i 
        return num == 1
  1. 第313题:超级丑数 Super Ugly Number

编写一段程序来查找第 n 个超级丑数。

超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。

示例:

输入: n = 12, primes = [2,7,13,19]
输出: 32
解释: 给定长度为 4 的质数列表 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。
说明:

1 是任何给定 primes 的超级丑数。
给定 primes 中的数字以升序排列。
0 < k ≤ 100, 0 < n ≤ 10^6, 0 < primes[i] < 1000 。
第 n 个超级丑数确保在 32 位有符整数范围内。

思路一:采用堆的思想。就类似于264题的丑数II。超级丑数是primies=[xx,xx,xx,xx]中的数的倍数,我们要不断地把它们的倍数压入堆中,再按顺序弹出。

但这个思路,在这边存在问题,就是可能会超出时间限制。

class Solution(object):
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        heap = [1]
        heapq.heapify(heap)

        for _ in range(n):
            result = heapq.heappop(heap)
            while heap and result == heap[0]:
                result = heapq.heappop(heap)
            for p in primes:
                t = result*p
                heapq.heappush(heap, t)
           
        return result

思路二:将丑数II的3个指针,改为多个指针。第n个丑数一定是由前n-1个数中的某k个丑数 分别乘以primes[xx,xx,xx,xx]中的数,所得到的最小数。

class Solution(object):
    def nthSuperUglyNumber(self, n, primes):
        """
        :type n: int
        :type primes: List[int]
        :rtype: int
        """
        results = [1 for _ in range(n)]
        pointers = [0 for _ in range(len(primes))]

        for i in range(1,n):   #循环results,其第一位已经定了是1
            nextMin = 0xffffffff
            for j in range(len(primes)):
                nextMin =  min(nextMin,results[pointers[j]]*primes[j])
                results[i] = nextMin
            for j in range(len(primes)):
                if nextMin == results[pointers[j]]*primes[j]:
                    pointers[j] += 1
        return results[-1]
  1. 第347题:前K个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]
说明:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

解法一:运用到heapq.nlargest,这个函数可接收参数key,用于dict或其他数据结构类型使用

class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        
        dict = {}
        for num in nums:
            if num not in dict:
                dict[num] = 1
            else:
                dict[num] += 1
        
        return heapq.nlargest(k, dict, key = dict.get)

解法二: 将构建字典部份,改成 collections.Counter(),一行代码解决。

class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        
        count = collections.Counter(nums)  
     
        return heapq.nlargest(k, count, key = count.get)
    
  1. 第355题:设计推特 Design Twitter

设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文。你的设计需要支持以下的几个功能:

postTweet(userId, tweetId): 创建一条新的推文
getNewsFeed(userId): 检索最近的十条推文。每个推文都必须是由此用户关注的人或者是用户自己发出的。推文必须按照时间顺序由最近的开始排序。
follow(followerId, followeeId): 关注一个用户
unfollow(followerId, followeeId): 取消关注一个用户

示例:

Twitter twitter = new Twitter();

// 用户1发送了一条新推文 (用户id = 1, 推文id = 5).
twitter.postTweet(1, 5);

// 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
twitter.getNewsFeed(1);

// 用户1关注了用户2.
twitter.follow(1, 2);

// 用户2发送了一个新推文 (推文id = 6).
twitter.postTweet(2, 6);

// 用户1的获取推文应当返回一个列表,其中包含两个推文,id分别为 -> [6, 5].
// 推文id6应当在推文id5之前,因为它是在5之后发送的.
twitter.getNewsFeed(1);

// 用户1取消关注了用户2.
twitter.unfollow(1, 2);

// 用户1的获取推文应当返回一个列表,其中包含一个id为5的推文.
// 因为用户1已经不再关注用户2.
twitter.getNewsFeed(1);

代码:

class Twitter(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.timer = 0
        self.followings = collections.defaultdict(set)   # 关注的人,用set表示
        self.messages = collections.defaultdict(list)    # 推文列表

    def postTweet(self, userId, tweetId):
        """
        Compose a new tweet.
        :type userId: int
        :type tweetId: int
        :rtype: None
        """
        
        self.messages[userId].append([self.timer, tweetId])  # 时间戳+推文
        self.timer += 1

    def getNewsFeed(self, userId):
        """
        Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent.
        :type userId: int
        :rtype: List[int]
        """
        News = []
        News += self.messages[userId]
        for follower in self.followings[userId]:
            News += self.messages[follower]
        News = sorted(News, key=lambda x:x[0], reverse=True)
        return [news[1] for news in News][:10]
        

    def follow(self, followerId, followeeId):
        """
        Follower follows a followee. If the operation is invalid, it should be a no-op.
        :type followerId: int
        :type followeeId: int
        :rtype: None
        """
        if followeeId not in self.followings[followerId] and followerId != followeeId:
            self.followings[followerId].add(followeeId)

    def unfollow(self, followerId, followeeId):
        """
        Follower unfollows a followee. If the operation is invalid, it should be a no-op.
        :type followerId: int
        :type followeeId: int
        :rtype: None
        """
        if followeeId in self.followings[followerId]:
            self.followings[followerId].remove(followeeId)

# Your Twitter object will be instantiated and called as such:
# obj = Twitter()
# obj.postTweet(userId,tweetId)
# param_2 = obj.getNewsFeed(userId)
# obj.follow(followerId,followeeId)
# obj.unfollow(followerId,followeeId)
  1. 第373题: 查找和最小的k对数字

给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。

找到和最小的 k 对数字 (u1,v1), (u2,v2) … (uk,vk)。

示例 1:
输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

示例 2:
输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
[1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

示例 3:
输入: nums1 = [1,2], nums2 = [3], k = 3
输出: [1,3],[2,3]
解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]

思路一: 暴力解法

class Solution(object):
    def kSmallestPairs(self, nums1, nums2, k):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :type k: int
        :rtype: List[List[int]]
        """
        
        if not nums1 or not nums2:
             return []
       
        res = []
        for i in nums1:
             for j in nums2:
                 res.append([i,j])
        res = sorted(res, key = lambda x:x[0]+x[1])
        return res[:k]

思路二:采用堆的解法

class Solution(object):
    def kSmallestPairs(self, nums1, nums2, k):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :type k: int
        :rtype: List[List[int]]
        """

        import heapq
        if not nums1 or not nums2:
                return []
        heap = []
        res = []
        heapq.heappush(heap,(nums1[0]+nums2[0],0,0))
        visited = {(0,0)}  #记录,防止重复
        
        while heap and len(res) < k:
            _,i,j = heapq.heappop(heap)
            res.append([nums1[i],nums2[j]])
            ##  每次nums1或nums2移动
            if i+1 < len(nums1) and (i+1,j) not in visited:
                heapq.heappush(heap,(nums1[i+1]+nums2[j],i+1,j))
                visited.add((i+1,j))
            if j+1 < len(nums2) and (i,j+1) not in visited:
                heapq.heappush(heap,(nums1[i]+nums2[j+1],i,j+1))
                visited.add((i,j+1))
        return res  
        
  1. 第378题:有序矩阵中第k小的元素

给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。

示例:

matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,

返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n^2 。

思路一:二分法。看到这种有序(或者部分有序)的数组,一般考虑使用二分查找进行优化。
思路非常简单:
1.找出二维矩阵中最小的数left,最大的数right,那么第k小的数必定在left~right之间
2.mid=(left+right) / 2;在二维矩阵中寻找小于等于mid的元素个数count
3.若这个count小于k,表明第k小的数在右半部分且不包含mid,即left=mid+1, right=right,又保证了第k小的数在left~right之间
4.若这个count大于k,表明第k小的数在左半部分且可能包含mid,即left=left, right=mid,又保证了第k小的数在left~right之间
5.因为每次循环中都保证了第k小的数在left~right之间,当left==right时,第k小的数即被找出,等于right或left

注意:这里的left, mid, right是数值,不是索引位置。

class Solution(object):
    def kthSmallest(self, matrix, k):
        """
        :type matrix: List[List[int]]
        :type k: int
        :rtype: int
        """
        ## 1. 二分查找法
        l = matrix[0][0]        
        r = matrix[-1][-1]
        n = len(matrix)
        while l < r:
            mid = (l+r)//2
            count = 0   
            for i in range(n):
                 for j in range(n):
                    if matrix[i][j] <= mid:
                         count+=1                 
            if count < k:
                l = mid+1
            else:
                r = mid
        return l

思路二:堆。不用把每个元素都进堆,只需要把“最可能是最小值”的进堆即可。也就是说我们每次进堆的元素只要包括下一个最小的元素即可。

我们把左上角最小的元素和其索引进堆,然后每次把元素的右边的元素进堆。当是第一列元素的时候,把这个元素下面的元素也进堆。(不能把每一个元素的右边和下边都进堆,因为会重复)

class Solution(object):
    def kthSmallest(self, matrix, k):
        """
        :type matrix: List[List[int]]
        :type k: int
        :rtype: int
        """
        n = len(matrix)
        heap = []
        heapq.heappush(heap,(matrix[0][0],0,0))
        
        for _ in range(k):
            ans, i, j = heapq.heappop(heap)
            if j == 0 and i+1<n:
                heapq.heappush(heap,(matrix[i+1][j],i+1,j))
            if j+1<n:
                heapq.heappush(heap,(matrix[i][j+1],i,j+1))
        return ans
  1. 第451题:根据字符出现频率排序

给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

示例 1:
输入:
“tree”

输出:
“eert”

解释:
'e’出现两次,'r’和’t’都只出现一次。
因此’e’必须出现在’r’和’t’之前。此外,"eetr"也是一个有效的答案。

示例 2:
输入:
“cccaaa”

输出:
“cccaaa”

解释:
'c’和’a’都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。

示例 3:
输入:
“Aabb”

输出:
“bbAa”

解释:
此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意’A’和’a’被认为是两种不同的字符。

class Solution(object):
    def frequencySort(self, s):
        """
        :type s: str
        :rtype: str
        """
        look_up = {}
        for ch in s:
            if ch not in look_up:
                look_up[ch] = 1
            else:
                look_up[ch] += 1
        # look_up = dict(collections.Counter(s))   #可以快速生成字典
        look_up = sorted(look_up.items(), key = lambda x:x[1], reverse = True)
        result = []
        for char,count in look_up:
            result.extend([char]*count)
        return "".join(result)
  1. 第659题:分割数组为连续子序列

输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数。返回你是否能做出这样的分割?

示例 1:
输入: [1,2,3,3,4,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3
3, 4, 5

示例 2:
输入: [1,2,3,3,4,4,5,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3, 4, 5
3, 4, 5

示例 3:
输入: [1,2,3,4,4,5]
输出: False

提示:
输入的数组长度范围为 [1, 10000]

思想:count[x]:每个数字的出现次数, tails[x] :恰好在 x 之前结束的链的数目。

现在我们逐一考虑每个数字,如果有一个链恰好在 x 之前结束,我们将 x 加入此链中。否则,如果我们可以新建立一条链就新建。

备注:
dict和Counter的区别。dict,当key不存在时,会报错。而Counter继承了dict类,当key不存在时,返回0。

class Solution(object):
    def isPossible(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        count = collections.Counter(nums)    # 使用Counter形式,即当key不存在时,返回0。不会报错
        tails = collections.Counter()        # Counter()继承dict类
        
        for x in nums:
            if count[x] == 0:
                continue
            elif tails[x] > 0:       ## 一定要先判断count[x] == 0 和 tails[x] >0
                tails[x] -= 1
                tails[x+1] += 1
                count[x] -= 1 
    
            elif count[x+1]>0 and count[x+2]>0:
                    count[x+1] -= 1
                    count[x+2] -=1
                    count[x] -= 1
                    tails[x+3] +=1
                       
            else:
                return False
        return True
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值