编程神技,算法题轻松秒解,再也不怕难题了!
2024-01-12 21:57:50
攻克算法难题:秒解 LeetCode 四大题型
在软件开发的世界中,算法能力至关重要,而 LeetCode 是一个极佳的平台,可让你磨练技能并精通算法。本文将深入探讨四道 LeetCode 算法题,提供循序渐进的解题思路,助你轻松秒解这些难题。
933. 最近的请求次数
这道题要求你计算每秒钟的请求次数,时间范围是过去 3000 毫秒。
解法一:滑动窗口
我们可以使用一个长度为 3000 毫秒的滑动窗口来解决这个问题。当遇到一个新的时间戳时,将其添加到窗口中,同时从窗口中移除超时的请求。最后,计算窗口中请求的总数除以 3000,即可得到每秒钟的请求次数。
解法二:哈希表
我们还可以使用哈希表,键为时间戳,值为请求次数。当遇到一个新的时间戳时,更新哈希表中的值,然后计算过去 3000 毫秒内的请求总数,并将其除以 3000。
代码示例:
# 解法一:滑动窗口
class RecentCounter:
def __init__(self):
self.requests = []
def ping(self, t: int) -> int:
self.requests.append(t)
while self.requests[0] < t - 3000:
self.requests.pop(0)
return len(self.requests)
# 解法二:哈希表
class RecentCounter:
def __init__(self):
self.hashtable = {}
def ping(self, t: int) -> int:
self.hashtable[t] = self.hashtable.get(t, 0) + 1
start = max(0, t - 3000)
total = 0
for i in range(start, t + 1):
total += self.hashtable.get(i, 0)
return total
859. 亲密字符串
亲密字符串的定义是,两个字符串的每个字符都出现在另一个字符串中,且出现的次数相同。
解法一:哈希表
我们可以使用两个哈希表,键为字符,值为出现次数。对于每个字符串,将字符和出现次数放入哈希表中。最后,比较两个哈希表是否相等。
解法二:数组
我们还可以使用两个长度为 26(小写字母的数量)的数组,每个元素代表一个字母的出现次数。对于每个字符串,将字母的出现次数添加到数组中。最后,比较两个数组是否相等。
代码示例:
# 解法一:哈希表
def areAlmostEqual(s1: str, s2: str) -> bool:
if s1 == s2:
return True
freq1, freq2 = {}, {}
for char in s1:
freq1[char] = freq1.get(char, 0) + 1
for char in s2:
freq2[char] = freq2.get(char, 0) + 1
return freq1 == freq2
# 解法二:数组
def areAlmostEqual(s1: str, s2: str) -> bool:
if s1 == s2:
return True
cnt1, cnt2 = [0] * 26, [0] * 26
for char in s1:
cnt1[ord(char) - ord('a')] += 1
for char in s2:
cnt2[ord(char) - ord('a')] += 1
return cnt1 == cnt2
641. 设计循环双端队列
循环双端队列是一种特殊队列,允许从两端插入和删除元素。
解法一:数组
我们可以使用一个数组来实现循环双端队列,数组的大小是队列的最大容量。队头和队尾使用指针表示,队头指针指向队头的元素,队尾指针指向队尾元素的下一个位置。当队头指针指向数组的末尾时,环回到数组的开头。
解法二:链表
我们还可以使用链表来实现循环双端队列,每个节点包含一个元素和指向下一个节点的指针。队头和队尾节点分别指向队头的元素和队尾元素的下一个节点。当队头节点指向链表的末尾时,环回到链表的开头。
代码示例:
# 解法一:数组
class MyCircularQueue:
def __init__(self, k: int):
self.queue = [None] * k
self.head, self.tail = 0, 0
self.size = k
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
self.queue[self.tail] = value
self.tail = (self.tail + 1) % self.size
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
self.queue[self.head] = None
self.head = (self.head + 1) % self.size
return True
def Front(self) -> int:
if self.isEmpty():
return -1
return self.queue[self.head]
def Rear(self) -> int:
if self.isEmpty():
return -1
return self.queue[(self.tail - 1 + self.size) % self.size]
def isEmpty(self) -> bool:
return self.head == self.tail
def isFull(self) -> bool:
return (self.tail + 1) % self.size == self.head
# 解法二:链表
class Node:
def __init__(self, val):
self.val = val
self.next = None
class MyCircularQueue:
def __init__(self, k: int):
self.head = Node(None)
self.tail = self.head
self.size = k
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
new_node = Node(value)
self.tail.next = new_node
self.tail = new_node
self.tail.next = self.head
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
self.head = self.head.next
self.tail.next = self.head
return True
def Front(self) -> int:
if self.isEmpty():
return -1
return self.head.val
def Rear(self) -> int:
if self.isEmpty():
return -1
return self.tail.val
def isEmpty(self) -> bool:
return self.head == self.tail
def isFull(self) -> bool:
return self.head.next == self.tail
384. 打乱数组
打乱数组是指将数组中的元素随机排列。
解法一:随机数生成器
我们可以使用随机数生成器来打乱数组,随机生成两个数字,然后交换这两个数字。重复这个过程,直到数组中的所有元素都被交换过。
解法二:Fisher-Yates 算法
Fisher-Yates 算法是一种打乱数组的算法,它可以保证每个元素都有相同的概率被选中。算法的步骤如下:
- 从数组的末尾开始,对于每个元素,随机生成一个数字,范围是 [0, 当前元素的索引]。
- 将当前元素与随机生成的元素交换。
代码示例:
# 解法一:随机数生成器
import random
def shuffle(nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
for i in range(len(nums)):
j = random.randint(i, len(nums) - 1)
nums[i], nums[j] = nums[j], nums[i]
# 解法二:Fisher-Yates 算法
def shuffle(nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
for i in range(n - 1, -1, -1):
j = random.randint(0, i)
nums[i], nums[j] = nums[j], nums[i]
结论
通过本文中提供的解题思路和代码示例,你可以轻松秒解 LeetCode 的算法难题。