返回

编程神技,算法题轻松秒解,再也不怕难题了!

前端

攻克算法难题:秒解 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 算法是一种打乱数组的算法,它可以保证每个元素都有相同的概率被选中。算法的步骤如下:

  1. 从数组的末尾开始,对于每个元素,随机生成一个数字,范围是 [0, 当前元素的索引]。
  2. 将当前元素与随机生成的元素交换。

代码示例:

# 解法一:随机数生成器
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 的算法难题。