最小堆最大堆基础概念与经典题目(Leetcode题解-Python语言)

是一种特别的完全二叉树,符合以下两个定义即为堆:

1、完全二叉树;

2、每一个节点的值都必须大于等于或者小于等于其孩子节点的值。若是大于等于,即为最大堆,若是小于等于,即为最小堆。显然,最大堆的根节点是最大值,最小堆的根节点是最小值

深度为kkk的二叉树至多总共有2k+1{2^{k + 1}}2k+1个节点(定义根节点所在深度k0{k_0}k0=0),节点数正好是2k+1{2^{k + 1}}2k+1的二叉树就称为满二叉树;如果对满二叉树的节点编号,有二叉树的节点可以与编号一一对应的话,该二叉树就称为完全二叉树(又或者说,完全二叉树除最后一层外的其余层都是满的,并且最后一层要么是满的,要么在右边缺少连续若干节点)。

完全二叉树有两个特点:

1、具有nnn个节点的完全二叉树的深度为⌊log⁡2n+1⌋\left\lfloor{{{\log }_2}n + 1}\right\rfloorlog2n+1(注:⌊⌋\left\lfloor {} \right\rfloor表示向下取整)

2、如果用数组表示完全二叉树,并且根节点存储在数组的索引1的位置的时候,任何一个节点的父节点索引位置为该节点的索引位置/2,任何一个节点的左孩子节点的索引位置为该节点的索引位置*2,任何一个节点的右孩子节点的索引位置为该节点的索引位置*2+1

从零开始用Python实现最小堆的代码如下:

# 「最小堆」的实现
import sysclass MinHeap:def __init__(self, heapSize):# heapSize用于数组的大小,因为数组在创建的时候至少需要指明数组的元素个数self.heapSize = heapSize# 使用数组创建完全二叉树的结构,然后使用二叉树构建一个「堆」self.minheap = [0]*(heapSize+1)# realSize用于记录「堆」的元素个数self.realSize = 0#  添加元素函数def add(self, element):self.realSize += 1# 如果「堆」中元素的个数大于一开始设定的数组的个数,则返回「Add too many elements」if self.realSize > self.heapSize:print("Add too many elements!")self.realSize -= 1return# 将添加的元素添加到数组中self.minheap[self.realSize] = element# 新增元素的索引位置index = self.realSize# 新增元素的父节点的索引位置# 注意,如果用数组表示完全二叉树,并且根结点存储在数组的索引1的位置的时候,任何一个节点的父节点索引位置为「该节点的索引位置/2」,任何一个节点的左孩子节点的索引位置为「该节点的索引位置*2」,任何一个节点的右孩子节点的索引位置为「该节点的索引位置*2+1」parent = index // 2# 当添加的元素小于父节点时,需要将父节点的值和新增元素的值交换while (self.minheap[index] < self.minheap[parent] and index > 1):self.minheap[parent], self.minheap[index] = self.minheap[index], self.minheap[parent]index = parentparent = index // 2# 获取堆顶元素函数def peek(self):return self.minheap[1]# 删除堆顶元素函数def pop(self):# 如果当前「堆」的元素个数为0, 则返回「Don't have any element」if self.realSize < 1:print("Don't have any element!")return sys.maxsizeelse:# 当前「堆」中含有元素# self.realSize >= 1removeElement = self.minheap[1]# 将「堆」中的最后一个元素赋值给堆顶元素self.minheap[1] = self.minheap[self.realSize]self.realSize -= 1index = 1# 当删除的元素不是孩子节点时while (index < self.realSize and index <= self.realSize // 2):# 被删除节点的左孩子节点left = index * 2# 被删除节点的右孩子节点right = (index * 2) + 1# 当删除节点的元素大于 左孩子节点或者右孩子节点,代表该元素的值大,此时需要将该元素与左、右孩子节点中最小的值进行交换if (self.minheap[index] > self.minheap[left] or self.minheap[index] > self.minheap[right]):if self.minheap[left] < self.minheap[right]:self.minheap[left], self.minheap[index] = self.minheap[index], self.minheap[left]index = leftelse:self.minheap[right], self.minheap[index] = self.minheap[index], self.minheap[right]index = rightelse:breakreturn removeElement# 返回「堆」的元素个数def size(self):return self.realSizedef toString(self):print(self.minheap[1 : self.realSize+1])if __name__ == "__main__":# 测试用例minHeap = MinHeap(5)minHeap.add(3)minHeap.add(1)minHeap.add(2)# [1,3,2]minHeap.toString()# 1print(minHeap.peek())# 1print(minHeap.pop())# 2print(minHeap.pop())# 3print(minHeap.pop())minHeap.add(4)minHeap.add(5)# [4,5]minHeap.toString()

实现最大堆的代码如下:

# 「最大堆」的实现
import sysclass MaxHeap:def __init__(self, heapSize):# heapSize用于数组的大小,因为数组在创建的时候至少需要指明数组的元素个数self.heapSize = heapSize# 使用数组创建完全二叉树的结构,然后使用二叉树构建一个「堆」self.maxheap = [0]*(heapSize+1)# realSize用于记录「堆」的元素个数self.realSize = 0#  添加元素函数def add(self, element):self.realSize += 1# 如果「堆」中元素的个数大于一开始设定的数组的个数,则返回「Add too many elements」if self.realSize > self.heapSize:print("Add too many elements!")self.realSize -= 1return# 将添加的元素添加到数组中self.maxheap[self.realSize] = element# 新增元素的索引位置index = self.realSize# 新增元素的父节点的索引位置# 注意,如果用数组表示完全二叉树,并且根结点存储在数组的索引1的位置的时候,任何一个节点的父节点索引位置为「该节点的索引位置/2」,任何一个节点的左孩子节点的索引位置为「该节点的索引位置*2」,任何一个节点的右孩子节点的索引位置为「该节点的索引位置*2+1」parent = index // 2# 当添加的元素大于父节点时,需要将父节点的值和新增元素的值交换while (self.maxheap[index] > self.maxheap[parent] and index > 1):self.maxheap[parent], self.maxheap[index] = self.maxheap[index], self.maxheap[parent]index = parentparent = index // 2# 获取堆顶元素函数def peek(self):return self.maxheap[1]# 删除堆顶元素函数def pop(self):# 如果当前「堆」的元素个数为0, 则返回「Don't have any element」if self.realSize < 1:print("Don't have any element!")return sys.maxsizeelse:# 当前「堆」中含有元素# self.realSize >= 1removeElement = self.maxheap[1]# 将「堆」中的最后一个元素赋值给堆顶元素self.maxheap[1] = self.maxheap[self.realSize]self.realSize -= 1index = 1# 当删除的元素不是孩子节点时while (index < self.realSize and index <= self.realSize // 2):# 被删除节点的左孩子节点left = index * 2# 被删除节点的右孩子节点right = (index * 2) + 1# 当删除节点的元素小于 左孩子节点或者右孩子节点,代表该元素的值小,此时需要将该元素与左、右孩子节点中最大的值进行交换if (self.maxheap[index] < self.maxheap[left] or self.maxheap[index] < self.maxheap[right]):if self.maxheap[left] > self.maxheap[right]:self.maxheap[left], self.maxheap[index] = self.maxheap[index], self.maxheap[left]index = leftelse:self.maxheap[right], self.maxheap[index] = self.maxheap[index], self.maxheap[right]index = rightelse:breakreturn removeElement# 返回「堆」的元素个数def size(self):return self.realSizedef toString(self):print(self.maxheap[1 : self.realSize+1])if __name__ == "__main__":# 测试用例maxHeap = MaxHeap(5)maxHeap.add(1)maxHeap.add(2)maxHeap.add(3)# [3,1,2]maxHeap.toString()# 3print(maxHeap.peek())# 3print(maxHeap.pop())# 2print(maxHeap.pop())# 1print(maxHeap.pop())maxHeap.add(4)maxHeap.add(5)# [5,4]maxHeap.toString()

实现堆的关键是插入删除,简单来说,以最小堆为例,插入操作就是把新的元素插入到二叉树的最后一个节点(保持完全二叉树),然后不断与其父节点比较大小,进行上移;删除操作就是把根节点元素与最后一个节点元素互换,删除最后一个节点(保持完全二叉树),然后根节点不断与其左右子节点比较大小,进行下移

在Python中,已经内置了堆的实现,即标准库heapq,官方文档在此。由于官方只实现了最小堆,若想实现最大堆,只需要把元素取负即可。

最小堆示例:

# 最小堆完整代码
import heapq# 新建一个列表
minHeap = []
# 将列表堆化,即将列表转换为最小堆
heapq.heapify(minHeap)
# 分别往最小堆中添加3,1,2
heapq.heappush(minHeap, 3)
heapq.heappush(minHeap, 1)
heapq.heappush(minHeap, 2)
# 查看最小堆的所有元素,结果为:[1,3,2]
print("minHeap: ",minHeap)
# 获取最小堆的堆顶元素
peekNum = minHeap[0]
# 结果为:1
print("peek number: ", peekNum)
# 删除最小堆的堆顶元素
popNum = heapq.heappop(minHeap)
# 结果为:1
print("pop number: ", popNum)
# 查看删除1后最小堆的堆顶元素,结果为:2
print("peek number: ", minHeap[0])
# 查看最小堆的所有元素,结果为:[2,3]
print("minHeap: ",minHeap)
# 获取堆的元素个数,即堆的长度
size = len(minHeap)
# 结果为:2
print("minHeap size: ", size)

最大堆示例:

# 最大堆完整代码
import heapq# 新建一个列表
maxHeap = []
# 将列表堆化,此时的堆是最小堆,我们需要将元素取反技巧,将最小堆转换为最大堆
heapq.heapify(maxHeap)
# 分别往堆中添加1,3,2,注意此时添加的是-1,-3,-2,原因是需要将元素取反,最后将最小堆转换为最大堆
heapq.heappush(maxHeap, 1*-1)
heapq.heappush(maxHeap, 3*-1)
heapq.heappush(maxHeap, 2*-1)
# 查看堆中所有元素:[-3, -1, -2]
print("maxHeap: ",maxHeap)
# 查看堆中的最大元素,即当前堆中最小值*-1
peekNum = maxHeap[0]
# 结果为:3
print("peek number: ", peekNum*-1)
# 删除堆中最大元素,即当前堆中最小值
popNum = heapq.heappop(maxHeap)
# 结果为:3
print("pop number: ", popNum*-1)
# 查看删除3后堆中最大值, 结果为:2
print("peek number: ", maxHeap[0]*-1)
# 查看堆中所有元素,结果为:[-2,-1]
print("maxHeap: ",maxHeap)
# 查看堆的元素个数,即堆的大小
size = len(maxHeap)
# 结果为:2
print("maxHeap size: ", size)

简单练手题

1046. 最后一块石头的重量

class Solution:def lastStoneWeight(self, stones: List[int]) -> int:heap = [-i for i in stones]heapq.heapify(heap)while heap:stone1 = heapq.heappop(heap) * -1if not heap:return stone1else:stone2 = heapq.heappop(heap) * -1stone1 = stone1 - stone2heapq.heappush(heap, stone1 * -1)return 0

只需要创建一个最大堆,每次弹出两个石头,进行相减后放回堆中,若只剩一个石头则返回该石头,否则返回0。

经典题目

最经典的一类题目莫过于 Top KThe Kth ,即求数组(大小为 N)中最大或最小的 K 个数或者第 K 个数。这类问题一般有两种思路(以求取最小的 K 个数或者第 K 个数为例):

1、创建一个大小为 N 的最小堆,然后对其进行 K 次弹出heappop)操作,由于每次都是弹出最小值,所以得到的结果一定就是最小的 K 个数,只要最小的第 K 个数也可以。时间复杂度是 O(Klog⁡N)O(K\log N)O(KlogN),是因为进行了 K 次弹出操作,而每次弹出后最小堆都会比较 log⁡N\log NlogN 次把下一个最小值放到根节点,因此是O(Klog⁡N)O(K\log N)O(KlogN),空间复杂度则为 O(N)O(N)O(N)

2、创建一个大小为 K 的最大堆,遍历数组(N 次遍历),首先数组顺序的前 K 个元素加入最大堆(填满),然后当最大堆的元素个数达到 K 时,后面的遍历就要将当前遍历元素与堆顶元素进行比较,如果当前元素大于堆顶元素,则放弃当前元素,继续遍历下一个元素;如果当前元素小于堆顶元素,则删除堆顶元素,将当前元素加入到最大堆中(heapreplace)。最后得到的最大堆中的 K 个元素就是最小的 K 个元素。时间复杂度是 O(Nlog⁡K)O(N\log K)O(NlogK),是因为进行了 N 次遍历,而每次遍历元素若加入最大堆,就会比较 log⁡K\log KlogK 次把下一个最小值放到根节点,因此是O(Nlog⁡K)O(N\log K)O(NlogK),空间复杂度则为 O(K)O(K)O(K)

剑指 Offer 40. 最小的k个数(面试题 17.14. 最小K个数)

class Solution:def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:heapq.heapify(arr)ans = []for _ in range(k):ans.append(heapq.heappop(arr))return ans

建立最小堆,弹出K个数即为最小的K个数。

215. 数组中的第K个最大元素(剑指 Offer II 076. 数组中的第 k 大的数字)

class Solution:def findKthLargest(self, nums: List[int], k: int) -> int:heapq.heapify(nums)while len(nums) > k:heapq.heappop(nums)return nums[0]

此题用取负实现最大堆也可以,但是更好的是实现一个长度为K的最小堆,则此时堆的最小值就是数组中的第K个最大元素。

703. 数据流中的第 K 大元素(剑指 Offer II 059. 数据流的第 K 大数值)

class KthLargest:def __init__(self, k: int, nums: List[int]):self.k = kself.heap = numsheapq.heapify(self.heap)def add(self, val: int) -> int:heapq.heappush(self.heap, val)while len(self.heap) > self.k:heapq.heappop(self.heap)return self.heap[0]

思路与上一题一样,实现一个长度为K的最小堆,即可得到数组中第K大元素。

1985. 找出数组中的第 K 大整数

class Solution:def kthLargestNumber(self, nums: List[str], k: int) -> str:heap = [int(i) for i in nums]heapq.heapify(heap)while len(heap) > k:heapq.heappop(heap)return str(heap[0])

还是第K大的数,加上了字符串到整数的转换。

347. 前 K 个高频元素(剑指 Offer II 060. 出现频率最高的 k 个数字)

class Solution:def topKFrequent(self, nums: List[int], k: int) -> List[int]:count = collections.Counter(nums)heap = []for key, val in count.items():if len(heap) < k:heapq.heappush(heap, (val, key))else:if val > heap[0][0]:heapq.heapreplace(heap, (val, key))return [i[1] for i in heap]

使用 collections.Counter()统计频率,然后建立长度为K的最小堆,若频率值比堆的最小值大,则替换掉它。此处有两个知识点要注意:

1、堆元素可以为元组,但比较值必须在前面,即 (val, key)。
2、heapq.heappushpop(heap, item)是先将 item 放入堆中,然后弹出并返回 heap 的最小元素;
heapq.heapreplace(heap, item)是先弹出并返回 heap 中最小的一项,然后推入新的 item,相当于poppush。

692. 前K个高频单词

class Solution:def topKFrequent(self, words: List[str], k: int) -> List[str]:count = collections.Counter(words)heap = []for key, value in count.items():heapq.heappush(heap, (-value, key))ans = []for _ in range(k):ans.append(heapq.heappop(heap)[1])return ans

此题若沿用上一题思路不太好做,这里改为建立最大堆,直接弹出K个元素即可,隐含的机制是堆会自动对元组 (-value, key) 进行从左到右优先级的排序。

451. 根据字符出现频率排序

class Solution:def frequencySort(self, s: str) -> str:count = collections.Counter(list(s))heap = []for key, value in count.items():heapq.heappush(heap, (-value, key))ans = ''for _ in range(len(heap)):value, key = heapq.heappop(heap)ans = ans + key * -valuereturn ans

这题也是统计词频并排序,只是输出需要改动一下而已。

373. 查找和最小的K对数字(剑指 Offer II 061. 和最小的 k 个数对)

class Solution:def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:heap = []for n1 in nums1:for n2 in nums2:if len(heap) < k:heapq.heappush(heap, (-n1-n2, [n1, n2]))elif heap and -heap[0][0] > n1 + n2:heapq.heapreplace(heap, (-n1-n2, [n1, n2]))else:breakreturn [i[1] for i in heap]

本题不能用最小堆,否则每次比较只能与最小值比较,不能替换掉其他值。所以用长度为K的最大堆,与347题基本一样。

263. 丑数

class Solution:def isUgly(self, n: int) -> bool:if n <= 0:return Falsefactors = [2, 3, 5]for factor in factors:while n % factor == 0:n //= factorreturn n == 1

数学类型的题目,基本写法记住就好。

264. 丑数 II(剑指 Offer 49. 丑数)(面试题 17.09. 第 k 个数)

class Solution:def nthUglyNumber(self, n: int) -> int:factors = [2, 3, 5]seen = {1}heap = [1]for i in range(n-1):cur = heapq.heappop(heap)for factor in factors:nxt = cur * factorif nxt not in seen:seen.add(nxt)heapq.heappush(heap, nxt)return heapq.heappop(heap)

此题不是判断丑数,而是寻找第 N 个丑数,那就使用一个最小堆,每次弹出最小的丑数,然后将其与3个因子结合可以生成3个新的丑数,并加入到最小堆中,重复 N-1 次,最后返回第 N 个即为所求。

378. 有序矩阵中第 K 小的元素

class Solution:def kthSmallest(self, matrix: List[List[int]], k: int) -> int:n = len(matrix)heap = [(matrix[i][0], i, 0) for i in range(n)]heapq.heapify(heap)for _ in range(k-1):num, x, y = heapq.heappop(heap)   # x是在哪一行,y是一行中的哪个位置(列)if y != n - 1:heapq.heappush(heap, (matrix[x][y + 1], x, y + 1))return heapq.heappop(heap)[0]

本题是堆与矩阵的结合题,用二分查找是最优解法,但此处还是使用了堆。只需要用一个最小堆记录最小值,每弹出一个最小值就把它在矩阵中右边的元素加入到堆中,若右边没有元素则跳过,重复 K 次即可。

1439. 有序矩阵中的第 k 个最小数组和

class Solution:def kthSmallest(self, mat, k: int) -> int:m = len(mat)n = len(mat[0])heap = []cur_sum = 0# 第一列的和for i in range(m):cur_sum += mat[i][0]# 各行的指针pointers = [0] * mheapq.heappush(heap, [cur_sum, tuple(pointers)])# 出现过的指针组合放入seenseen = set()seen.add(tuple(pointers))  # 必须用tuple才能hash,才能放入集合for _ in range(k-1):# 从堆中pop出cur_sum(最小数组和)和pointers(指针数组)cur_sum, pointers = heapq.heappop(heap)# 每个指针轮流后移一位,将new_sum(新的数组和)和new_pointers(新的指针数组)push入堆for idx, pointer in enumerate(pointers):if pointer < n - 1:# tuple变为list修改再变回tuplenew_pointers = list(pointers)new_pointers[idx] = pointer + 1new_pointers = tuple(new_pointers)if new_pointers not in seen:new_sum = cur_sum - mat[idx][pointer] + mat[idx][pointer + 1]heapq.heappush(heap, [new_sum, new_pointers])seen.add(new_pointers)return heapq.heappop(heap)[0]

这道困难题可以借鉴丑数的思路,用最小堆记录和值 sum 与指针组合 pointers(注意pointers必须用元组,否则不能哈希,放不进集合),然后用集合 seen 记录出现过的 pointers,如果没有出现过,则 push 进最小堆并记录到 seen 中。重复 K 次的 pop,然后让每行的指针都后移一位,直到无法移动为止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

进击吧! Blazor !第三期 信息交互

Blazor 是一个 Web UI 框架&#xff0c;可通过 WebAssembly 在任意浏览器中运行 .Net 。Blazor 旨在简化快速的单页面 .Net 浏览器应用的构建过程&#xff0c;它虽然使用了诸如 CSS 和 HTML 之类的 Web 技术&#xff0c;但它使用 C&#xff03;语言和 Razor 语法代替 JavaScrip…

leetcode718. 最长重复子数组

一:题目 二:上码 class Solution { public:/**思路:1.分析题意:1 2 3 6 7 41 2 6 7 4 3这里我们先遇到的1 2 但后来我们又遇见了6 7 4 那么我们的要的答案就是动态变化的2.动态规划五步走1>:确定dp数组以及下标的含义dp[i][j] 表示 以下标i-1结尾的A数组和以下标…

二叉树序列化与反序列化相关题目(Leetcode题解-Python语言)

297. 二叉树的序列化与反序列化&#xff08;剑指 Offer 37. 序列化二叉树&#xff09;&#xff08;剑指 Offer II 048. 序列化与反序列化二叉树&#xff09; class Codec:def serialize(self, root):"""Encodes a tree to a single string.:type root: TreeNod…

.NET 5 的 Target Framework 详解[上篇]

❝作者&#xff1a;.NET Team翻译&#xff1a;精致码农-王亮原文&#xff1a;http://dwz.win/Q4v❞我们希望极大地简化开发人员必须在项目文件和 NuGet 包中使用的「TFM」 (Target Framework Name, 目标框架名称)。这包括合并 .NET 5 和 .NET Standard 的概念&#xff0c;同时仍…

leetcode1143. 最长公共子序列

一&#xff1a;题目 二:上码 class Solution { public:/**思路:1.分析题意这个子序列就是我们是可以不连续的字符组成的2.动态规划五步走1>:确定dp数组的含义以及下标的含义dp[i][j] 表示的是text1中[0,i-1]字符范围,text2中[0,j-1]的字符范围 的最长公共子序列这里我们取i…

爬楼梯与路径类题目记忆化递归与动态规划双解法(Leetcode题解-Python语言)

70. 爬楼梯&#xff08;剑指 Offer 10- II. 青蛙跳台阶问题&#xff09; 递归&#xff08;英语&#xff1a;Recursion&#xff09;&#xff0c;是指在函数的定义中使用函数自身的方法。有意义的递归通常会把问题分解成规模缩小的同类子问题&#xff0c;当子问题缩写到寻常的时…

JAVA 15发布,越来越像C# ?9月排名,C#增幅狠甩JAVA

2016年.NET Core首个正式版本问世&#xff0c;如今已发布到了.NET Core3.1&#xff0c;再有2个月.NET5也将如约而至&#xff0c;跨平台开发已经快5年。微软 .NET 程序管理总监 Scott 表示&#xff0c;.NET 5 是 .NET Framework 和 .NET Core 的未来&#xff0c;最终将成为一个统…

买卖股票类问题动态规划解法(Leetcode题解-Python语言)

在 Leetcode 中&#xff0c;关于买卖股票的问题共有6道&#xff0c;而这些题目是可以用相同的思维进行求解的&#xff0c;强烈推荐这篇总结&#xff0c;写得非常到位。 股票类问题的动态规划分三步走&#xff0c;1、首先明确方程的含义&#xff0c; T[i][k][0]&#xff1a;表…

leetcode1035. 不相交的线

一:题目 二:上码 class Solution { public:/**思路:1.分析题意:这里的我们要求解的是最大值,那么我们的求解过程肯定是动态变化的,举个例子2 5 1 2 510 5 2 1 5 2 如果我们一开始就让nums1[1] 5何 nums2[4] 5 相连的话 那么我们肯定不会求解出最大值那么题目中的说的直线不…

几个超级实用但很少人知道的 VS 技巧[更新]

大家好&#xff0c;今天分享几个我知道的实用 VS 技巧&#xff0c;而这些技巧我发现很多人都不知道。因为我经常在工作中遇到&#xff1a;我在同事电脑上解决问题&#xff0c;或在会议上演示代码示例时&#xff0c;使用了一些 VS “骚”操作&#xff0c;他们会好奇地问&#xf…

一般动态规划问题合集(Leetcode题解-Python语言)

118. 杨辉三角 class Solution:def generate(self, numRows: int) -> List[List[int]]:dp [[0] * i for i in range(1, numRows1)]for i in range(numRows):for j in range(len(dp[i])):# 左右两边是1&#xff0c;中间部分就是其上方两个数之和if j 0 or j i:dp[i][j] …

leetcode53. 最大子数组和(动态规划)

一:题目 二:上码 class Solution { public:int maxSubArray(vector<int>& nums) {/**动态规划:1>:确定dp数组的含义以及下标的含义dp[j]表示的是下标j之前的最大子数组和 这个就是还没有包括nums[j] 2>:确定dp数组的状态转移公式dp[j] max (dp[j-1]nums[j],n…

矩阵模拟问题合集(Leetcode题解-Python语言)

54. 螺旋矩阵&#xff08;剑指 Offer 29. 顺时针打印矩阵&#xff09; class Solution:def spiralOrder(self, matrix: List[List[int]]) -> List[int]:ans []count 0m, n len(matrix), len(matrix[0])length m * ndirections [(0, 1), (1, 0), (0, -1), (-1, 0)]x y…

基于REACT和.NET CORE集成WINDOWS身份验证

有很多方法可以向您的应用程序添加身份验证。虽然OAuth是最常见的一种&#xff0c;但这并不是您唯一的选择。今天&#xff0c;我将向您展示如何通过React和.NET Core简单地完成Windows身份验证。探索我们的选择在深入探讨之前&#xff0c;让我们简要讨论一些可用的其他选项。了…

.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书

简介加解密现状&#xff0c;编写此系列文章的背景&#xff1a;需要考虑系统环境兼容性问题&#xff08;Linux、Windows&#xff09;语言互通问题&#xff08;如C#、Java等&#xff09;&#xff08;加解密本质上没有语言之分&#xff0c;所以原则上不存在互通性问题&#xff09;…

快速幂算法相关题目(Leetcode题解-Python语言)

50. Pow(x, n) 快速幂算法的目的&#xff0c;就是快速计算 x 的 n 次方。基本思路是把 n 视作二进制数&#xff0c;则 n 可以被分解为多个 2 的幂次方之和&#xff0c;如 12 对应 1100 等于 0∗200∗211∗221∗230*{2^0} 0*{2^1} 1*{2^2} 1*{2^3}0∗200∗211∗221∗23&…

leetcode115. 不同的子序列

一&#xff1a;题目 二:代码 class Solution { public:/**思路:动规分析走一波1>:确定dp数组以及下标的含义dp[i][j] 表示的是 以下标i-1结尾的子序列s中出现以j-1结尾的子序列t的 个数2>:确定dp数组的状态递推公式这里考虑两种状况 一种就是 s[i-1] s[j-1] 一种就是字…

栈的基础概念与经典题目(Leetcode题解-Python语言)

栈是先入后出&#xff08;后入先出&#xff09;的数据结构&#xff0c;常用操作就 push 和 pop&#xff0c;Python中用列表实现即可&#xff0c;基本概念可以看Leetbook相关章节。 普通栈 232. 用栈实现队列 class MyQueue:def __init__(self):self.stack1 []self.stack2 …

ASP.NET Core 3.x启动时运行异步任务(二)

这一篇是接着前一篇在写的。如果没有看过前一篇文章&#xff0c;建议先去看一下前一篇&#xff0c;这儿是传送门一、前言前一篇文章&#xff0c;我们从应用启动时异步运行任务开始&#xff0c;说到了必要性&#xff0c;也说到了几种解决方法&#xff0c;及各自的优缺点。最后&a…

leetcode583. 两个字符串的删除操作

一:题目 二:上码 class Solution { public:/**思路:题目给的是让求最值,那么首先就会想到的是动态规划,我们想得到答案的结果其实有多个的&#xff0c;但是我们是取最小的步数动态规划 五步走:1>:确定dp数组以及下标的含义dp[i][j]表示的是 以下标i-1结尾的字符串word1,和…