作者: admin2025

  • Sliding Window Median,LeetCode,480

    LeetCode 480题 “Sliding Window Median” 是一个中等难度的题目,要求我们在一个滑动窗口中找到中位数。中位数是指在一个有序数组中位于中间位置的数,如果数组长度是奇数,则中位数是中间那个数;如果数组长度是偶数,则中位数是中间两个数的平均值。

    题目描述

    给定一个数组 nums 和一个整数 k,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

    返回滑动窗口的中位数数组。

    示例

    输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 输出: [1,-1,-1,3,5,6] 解释:

    滑动窗口的位置 中位数


    [1 3 -1] -3 5 3 6 7 1 1 [3 -1 -3] 5 3 6 7 -1 1 3 [-1 -3 5] 3 6 7 -1 1 3 -1 [-3 5 3] 6 7 3 1 3 -1 -3 [5 3 6] 7 5 1 3 -1 -3 5 [3 6 7] 6

    解题思路

    要解决这个问题,我们可以使用两个数据结构:一个大顶堆(max heap)和一个小顶堆(min heap)。大顶堆用来存储窗口中较小的那一半元素,小顶堆用来存储较大的那一半元素。这样,我们可以保证:

    • 大顶堆中的所有元素都小于等于小顶堆中的所有元素。
    • 两个堆的大小之差不超过1。

    通过这种方式,我们可以快速找到中位数:

    • 如果两个堆的大小相等,中位数是两个堆顶元素的平均值。
    • 如果两个堆的大小不相等,中位数是较大的那个堆的堆顶元素。

    具体步骤

    1. 初始化:创建一个大顶堆 left 和一个小顶堆 right
    2. 填充初始窗口:将前 k 个元素加入堆中,调整堆使其满足上述条件。
    3. 滑动窗口:从第 k 个元素开始,每次移动窗口时:
      • 移除窗口最左边的元素。
      • 添加窗口最右边的元素。
      • 调整堆使其满足上述条件。
      • 计算当前窗口的中位数并记录。

    代码实现

    以下是使用Python实现的代码:

    import heapq

    def medianSlidingWindow(nums, k): def add_num(num): if not left or num <= -left[0]: heapq.heappush(left, -num) else: heapq.heappush(right, num) balance()

    def remove_num(num):
        if num <= -left[0]:
            left.remove(-num)
            heapq.heapify(left)
        else:
            right.remove(num)
            heapq.heapify(right)
        balance()
    
    def balance():
        if len(left) > len(right) + 1:
            heapq.heappush(right, -heapq.heappop(left))
        if len(right) > len(left):
            heapq.heappush(left, -heapq.heappop(right))
    
    def get_median():
        if len(left) == len(right):
            return (-left[0] + right[0]) / 2
        else:
            return -left[0]
    
    left, right = [], []
    result = []
    
    for i in range(len(nums)):
        add_num(nums[i])
        if i >= k:
            remove_num(nums[i - k])
        if i >= k - 1:
            result.append(get_median())
    
    return result

    示例

    nums = [1,3,-1,-3,5,3,6,7] k = 3 print(medianSlidingWindow(nums, k)) # 输出: [1, -1, -1, 3, 5, 6]

    解释

    1. add_num(num):将一个数加入堆中,并根据需要调整堆。
    2. remove_num(num):从堆中移除一个数,并重新调整堆。
    3. balance():确保两个堆的大小之差不超过1。
    4. get_median():根据两个堆的顶元素计算中位数。

    通过这种方式,我们可以在每个窗口移动时高效地计算中位数,从而解决这道题目。

  • Largest Palindrome Product,LeetCode,479

    LeetCode 479题是关于寻找最大的回文数乘积的问题。题目要求我们找到两个n位数相乘得到的最大的回文数。下面我将详细解释题目的要求、解题思路以及具体的代码实现。

    题目描述

    给定一个整数n,返回两个n位数的乘积中的最大回文数。如果没有找到,则返回0。

    解题思路

    1. 定义回文数:回文数是指从左到右和从右到左读都相同的数,例如121、12321等。
    2. 生成n位数:首先需要生成所有可能的n位数。
    3. 寻找最大回文数乘积:通过双重循环遍历所有可能的n位数对,计算它们的乘积,并检查是否为回文数。记录最大的回文数乘积。

    具体步骤

    1. 生成n位数:可以通过计算10^(n-1)到10^n-1之间的所有数来生成n位数。
    2. 检查回文数:编写一个函数来判断一个数是否为回文数。
    3. 遍历并记录最大回文数乘积:使用双重循环遍历所有n位数对,计算乘积并检查是否为回文数,记录最大的回文数乘积。

    代码实现

    以下是Python代码实现:

    class Solution: def largestPalindrome(self, n: int) -> int: if n == 1: return 9

        # 生成n位数的范围
        start = 10**(n-1)
        end = 10**n - 1
    
        # 检查是否为回文数的函数
        def is_palindrome(num):
            return str(num) == str(num)[::-1]
    
        max_palindrome = 0
    
        # 遍历所有可能的n位数对
        for i in range(end, start - 1, -1):
            for j in range(i, start - 1, -1):
                product = i * j
                if is_palindrome(product):
                    max_palindrome = max(max_palindrome, product)
    
        return max_palindrome

    示例使用

    sol = Solution() print(sol.largestPalindrome(2)) # 输出: 9009 (91 * 99)

    优化思路

    上述代码虽然能够解决问题,但时间复杂度较高,为O(n^2 * 10^(2n))。可以通过以下方法进行优化:

    1. 数学性质:利用回文数的数学性质,例如回文数可以表示为a * 10^n + b,其中ba的逆序数。
    2. 减少遍历范围:由于乘积是对称的,可以减少遍历的范围。

    优化后的代码

    class Solution: def largestPalindrome(self, n: int) -> int: if n == 1: return 9

        upper_limit = 10**n - 1
        lower_limit = 10**(n-1)
    
        for i in range(upper_limit, lower_limit - 1, -1):
            # 构造回文数
            palindrome = int(str(i) + str(i)[::-1])
            # 从大到小尝试除以n位数
            for j in range(upper_limit, lower_limit - 1, -1):
                if palindrome // j > upper_limit:
                    break
                if palindrome % j == 0:
                    return palindrome
    
        return 0

    示例使用

    sol = Solution() print(sol.largestPalindrome(2)) # 输出: 9009 (91 * 99)

    总结

    通过上述方法,我们可以有效地找到两个n位数相乘得到的最大回文数。优化后的代码利用了回文数的数学性质,减少了遍历的范围,提高了效率。希望这个详细的解答对你有所帮助!如果有更多问题,欢迎继续提问。

  • Generate Random Point in a Circle,LeetCode,478

    LeetCode 478题是“生成随机点在圆内”(Generate Random Point in a Circle),这是一个中等难度的题目,主要考察的是数学和随机数生成的知识。

    题目描述

    给定圆的半径和圆心位置,要求随机生成圆内的一个点。

    示例:

    输入: ["Solution", "randPoint", "randPoint", "randPoint"] [[1.0, 0.0, 0.0], [], [], []] 输出: [null, [-0.02493, -0.38077], [0.82314, 0.38945], [0.36572, 0.17248]] 解释: Solution solution = new Solution(1.0, 0.0, 0.0); solution.randPoint(); // 返回[-0.02493, -0.38077] solution.randPoint(); // 返回[0.82314, 0.38945] solution.randPoint(); // 返回[0.36572, 0.17248]

    解题思路

    要随机生成圆内的一个点,可以使用极坐标的方法。具体步骤如下:

    1. 生成随机半径:由于圆的面积与半径的平方成正比,直接均匀生成半径会导致点集中在圆心附近。因此,我们需要生成一个与半径平方成正比的随机数。具体来说,可以生成一个[0, 1]之间的随机数,然后取其平方根,再乘以圆的半径。
    2. 生成随机角度:在[0, 2π]之间均匀生成一个随机角度。
    3. 转换为直角坐标:使用极坐标到直角坐标的转换公式:
      • x = r * cos(θ)
      • y = r * sin(θ)
    4. 平移到圆心:将生成的点平移到给定的圆心位置。

    代码实现

    以下是Python的实现代码:

    import random import math

    class Solution: def init(self, radius: float, x_center: float, y_center: float): self.radius = radius self.x_center = x_center self.y_center = y_center

    def randPoint(self):
        # 生成随机半径
        r = self.radius * math.sqrt(random.random())
        # 生成随机角度
        theta = random.uniform(0, 2 * math.pi)
        # 转换为直角坐标
        x = r * math.cos(theta)
        y = r * math.sin(theta)
        # 平移到圆心
        return [self.x_center + x, self.y_center + y]

    示例使用

    solution = Solution(1.0, 0.0, 0.0) print(solution.randPoint()) # 返回一个随机点 print(solution.randPoint()) # 返回一个随机点 print(solution.randPoint()) # 返回一个随机点

    解释

    1. 初始化:在构造函数中,我们存储了圆的半径和圆心的坐标。
    2. 生成随机点
      • math.sqrt(random.random())生成一个[0, 1]之间的随机数的平方根,确保生成的半径符合圆的面积分布。
      • random.uniform(0, 2 * math.pi)生成一个[0, 2π]之间的随机角度。
      • 使用极坐标到直角坐标的转换公式计算出点的坐标。
      • 最后将生成的点平移到圆心位置。

    这种方法能够均匀地在圆内生成随机点,符合题目要求。

    希望这个详细的解答对你有帮助!如果有其他问题,欢迎继续提问。

  • Total Hamming Distance,LeetCode,477

    LeetCode 477题 “Total Hamming Distance” 是一个中等难度的位操作问题。题目要求计算一个数组中所有数对之间的汉明距离的总和。汉明距离是指两个整数对应二进制位不同的位置的数目。

    题目描述

    给定一个非空整数数组 nums,返回数组中所有数对之间的汉明距离的总和。

    示例

    输入: nums = [4, 14, 2] 输出: 6 解释: 在二进制表示中,4表示为 0100,14表示为 1110,2表示为 0010。 所以它们之间的汉明距离分别为: HammingDistance(4, 14) = 2 HammingDistance(4, 2) = 2 HammingDistance(14, 2) = 2 所以总汉明距离为 6。

    解法思路

    直接计算每两个数之间的汉明距离会导致时间复杂度为 O(n^2),我们可以通过位操作优化到 O(n)。

    核心思想

    1. 对于每一个二进制位,统计数组中在该位上为 1 的数的个数。
    2. 对于每一位,汉明距离的贡献为该位上为 1 的数的个数乘以该位上为 0 的数的个数。

    具体步骤

    1. 初始化 total_distance 为 0。
    2. 遍历每一位(从 0 到 31,假设数组中的数不超过 2^31 – 1)。
    3. 对于每一位,统计数组中在该位上为 1 的数的个数 count_1
    4. 该位的汉明距离贡献为 count_1 * (n - count_1),其中 n 是数组的长度。
    5. 将该位的贡献加到 total_distance 中。
    6. 返回 total_distance

    代码实现

    class Solution: def totalHammingDistance(self, nums): total_distance = 0 n = len(nums)

        for i in range(32):  # 遍历每一位
            count_1 = 0
            for num in nums:
                count_1 += (num >> i) & 1  # 统计在第 i 位上为 1 的数的个数
            count_0 = n - count_1
            total_distance += count_1 * count_0  # 计算该位的汉明距离贡献
    
        return total_distance

    解释

    • (num >> i) & 1:将 num 右移 i 位后与 1 进行按位与操作,得到第 i 位的值。
    • count_1 * count_0:在第 i 位上,为 1 的数和为 0 的数之间的汉明距离贡献。

    复杂度分析

    • 时间复杂度:O(n * 32) = O(n),因为我们需要遍历每一位,共 32 位,每次遍历数组。
    • 空间复杂度:O(1),只使用了常数额外空间。

    通过这种方法,我们能够高效地计算出数组中所有数对之间的汉明距离的总和。希望这个解释对你理解这道题有所帮助!如果有更多问题,欢迎继续提问。

  • Number Complement,LeetCode,476

    LeetCode 476题是关于求数的补数的问题。题目描述如下:

    题目描述: 给定一个正整数,输出它的补数。补数的定义是:该数和它的补数进行按位异或(XOR)运算的结果为所有位都为1的二进制数。

    示例:

    输入:5 输出:2 解释:5的二进制表示为101,其补数为010。101和010进行按位异或运算的结果为111。

    解题思路:

    1. 确定二进制长度:首先需要确定输入数字的二进制长度,这样才能构造出所有位都为1的二进制数。
    2. 构造全1二进制数:根据确定的长度,构造一个所有位都为1的二进制数。
    3. 计算补数:使用按位异或运算,将输入数字与全1二进制数进行异或,得到的结果即为补数。

    具体步骤:

    1. 计算输入数字的二进制长度。
    2. 构造一个与该长度相同的全1二进制数。
    3. 使用按位异或运算得到补数。

    代码实现(Python):

    class Solution: def findComplement(self, num: int) -> int:

    Step 1: Determine the length of the binary representation of num

        length = len(bin(num)) - 2
    
        # Step 2: Create a bitmask with all bits set to 1 of the same length
        bitmask = (1 << length) - 1
    
        # Step 3: Compute the complement by XORing num with the bitmask
        complement = num ^ bitmask
    
        return complement

    解释:

    1. len(bin(num)) - 2bin(num)返回num的二进制字符串,len(bin(num))获取该字符串的长度,减去2是因为bin()函数返回的字符串包含前缀'0b'
    2. 1 << length:将1左移length位,得到一个所有位都为0,只有最高位为1的数。
    3. (1 << length) - 1:将上一步得到的数减去1,得到一个所有位都为1的数。
    4. num ^ bitmask:使用按位异或运算得到补数。

    复杂度分析:

    • 时间复杂度:O(1),因为二进制长度和操作都是常数时间。
    • 空间复杂度:O(1),只使用了常数额外空间。

    这个解法简洁高效,充分利用了位运算的特性来解决问题。希望这个详细的解释对你理解这道题有所帮助!如果有任何进一步的问题,欢迎继续提问。

  • Heaters,LeetCode,475

    题目描述: 你有一个带有加热器的房间,现在你想找出加热器的最小加热半径,使得房间内的每个位置都能被至少一个加热器覆盖。

    输入

    • houses:一个整数数组,表示房间内每个位置的距离(可以是任意顺序)。
    • heaters:一个整数数组,表示每个加热器的位置(可以是任意顺序)。

    输出

    • 一个整数,表示所需的最小加热半径。

    示例

    输入: houses = [1,2,3], heaters = [2] 输出: 1 解释: 仅在位置2放置一个加热器,其加热半径为1即可覆盖所有房屋。

    解题思路

    1. 排序:首先对 housesheaters 进行排序,以便后续处理。
    2. 二分查找:对于每个房屋,使用二分查找找到离它最近的加热器。
    3. 计算半径:计算每个房屋到最近加热器的距离,这些距离中的最大值即为所需的最小加热半径。

    详细步骤

    1. 排序houses.sort() heaters.sort()
    2. 二分查找
      • 对于每个房屋 house,使用二分查找在 heaters 中找到离它最近的加热器。
      • 二分查找的目的是找到一个位置 i,使得 heaters[i] 是离 house 最近的加热器。
    3. 计算半径
      • 对于每个房屋,计算它到最近加热器的距离。
      • 更新最小加热半径为这些距离中的最大值。

    Python代码实现

    def findRadius(houses, heaters): import bisect

    houses.sort()
    heaters.sort()
    
    def findClosestHeater(house):
        # 使用二分查找找到最近的加热器
        idx = bisect.bisect_left(heaters, house)
        if idx == 0:
            return heaters[0]
        if idx == len(heaters):
            return heaters[-1]
        # 比较左右两个加热器,返回最近的
        if abs(heaters[idx] - house) < abs(heaters[idx - 1] - house):
            return heaters[idx]
        else:
            return heaters[idx - 1]
    
    min_radius = 0
    for house in houses:
        closest_heater = findClosestHeater(house)
        min_radius = max(min_radius, abs(closest_heater - house))
    
    return min_radius

    示例

    houses = [1, 2, 3] heaters = [2] print(findRadius(houses, heaters)) # 输出: 1

    复杂度分析

    • 时间复杂度:O(N log M),其中 N 是房屋的数量,M 是加热器的数量。排序的时间复杂度为 O(N log N + M log M),二分查找的时间复杂度为 O(N log M)。
    • 空间复杂度:O(1),除了输入数组外,使用的额外空间为常数。

    总结: 通过排序和二分查找,我们可以高效地找到每个房屋到最近加热器的距离,从而确定所需的最小加热半径。这种方法在处理大量数据时表现良好,具有较高的效率。

  • Ones and Zeroes,LeetCode,474

    LeetCode 474题 “Ones and Zeroes” 是一个经典的动态规划问题。题目要求我们在给定的字符串数组中,选择尽可能多的字符串,同时满足这些字符串中 ‘0’ 和 ‘1’ 的数量分别不超过给定的两个限制值。

    题目描述

    给你一个二进制字符串数组 strs 和两个整数 mn

    请你找出并返回 strs 的最大子集的大小,该子集中最多包含 m 个 ‘0’ 和 n 个 ‘1’。

    示例

    输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3 输出:4 解释:最多有 4 个字符串可以选择。 可以选择 "10"、"0001"、"1" 和 "0"。

    解题思路

    我们可以使用动态规划来解决这个问题。定义一个二维数组 dp,其中 dp[i][j] 表示最多包含 i 个 ‘0’ 和 j 个 ‘1’ 的最大子集大小。

    1. 初始化dp[0][0] = 0,因为不包含任何字符串时,’0′ 和 ‘1’ 的数量都是 0。
    2. 遍历字符串数组:对于每个字符串,统计其中的 ‘0’ 和 ‘1’ 的数量。
    3. 更新 dp 数组:从后向前更新 dp 数组,以避免重复使用同一个字符串。

    代码实现

    def findMaxForm(strs, m, n):

    初始化 dp 数组

    dp = [[0] * (n + 1) for _ in range(m + 1)]
    
    # 遍历每个字符串
    for s in strs:
        zeros = s.count('0')
        ones = s.count('1')
    
        # 从后向前更新 dp 数组
        for i in range(m, zeros - 1, -1):
            for j in range(n, ones - 1, -1):
                dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1)
    
    return dp[m][n]

    示例输入

    strs = ["10", "0001", "111001", "1", "0"] m = 5 n = 3

    输出结果

    print(findMaxForm(strs, m, n)) # 输出:4

    解释

    1. 初始化 dp 数组:创建一个 (m+1) x (n+1) 的二维数组,初始值都为 0。
    2. 统计每个字符串的 ‘0’ 和 ‘1’ 数量:使用 s.count('0')s.count('1')
    3. 更新 dp 数组:从后向前更新是为了确保每个字符串只被使用一次。dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) 表示在当前条件下,选择或不选择当前字符串的最大子集大小。

    复杂度分析

    • 时间复杂度:O(len(strs) m n),其中 len(strs) 是字符串数组的长度。
    • 空间复杂度:O(m * n),用于存储 dp 数组。

    通过这种方法,我们可以有效地解决 “Ones and Zeroes” 问题,找到满足条件的最大子集大小。

  • Matchsticks to Square,LeetCode,473

    LeetCode 473题 “Matchsticks to Square” 是一个中等难度的题目,主要考察的是回溯算法和深度优先搜索(DFS)。题目要求我们判断是否可以用一组火柴棍组成一个正方形。每根火柴棍的长度都是给定的,并且我们可以使用每根火柴棍一次。

    题目描述

    给定一个整数数组 nums,其中每个元素代表一根火柴棍的长度。你需要判断是否可以将这些火柴棍排列成一个正方形。

    示例

    示例 1:

    输入: [1,1,2,2,2] 输出: true

    解释: 可以组成一个边长为2的正方形,正方形的四条边分别是 {1,1}, {2}, {2}, {2}。

    示例 2:

    输入: [3,3,3,3,4] 输出: false

    解释: 无法将这些火柴棍组成一个正方形。

    解题思路

    1. 计算总和和边长
      • 首先计算所有火柴棍的总长度 sum
      • 如果 sum 不是4的倍数,直接返回 false,因为无法分成四条相等的边。
      • 计算每条边的长度 side = sum / 4
    2. 排序
      • 将火柴棍按长度从大到小排序,这样可以更快地发现不满足条件的情况。
    3. 回溯算法
      • 使用深度优先搜索(DFS)尝试将火柴棍分配到四条边上。
      • 维护一个数组 sides,表示当前四条边的长度。
      • 逐个尝试将火柴棍放入某一条边,如果某条边的长度超过了 side,则回溯。
    4. 剪枝优化
      • 如果某根火柴棍的长度超过了 side,直接返回 false
      • 如果当前边的长度为0,则优先放入当前边,这样可以减少不必要的搜索。

    代码实现

    class Solution: def makesquare(self, nums: List[int]) -> bool: if not nums: return False

        total_length = sum(nums)
        if total_length % 4 != 0:
            return False
    
        side_length = total_length // 4
        nums.sort(reverse=True)
    
        if nums[0] > side_length:
            return False
    
        sides = [0] * 4
    
        def dfs(index):
            if index == len(nums):
                return sides[0] == sides[1] == sides[2] == side_length
    
            for i in range(4):
                if sides[i] + nums[index] <= side_length:
                    sides[i] += nums[index]
                    if dfs(index + 1):
                        return True
                    sides[i] -= nums[index]
    
                # 如果当前边的长度为0,则不需要继续尝试其他边,因为结果会相同
                if sides[i] == 0:
                    break
    
            return False
    
        return dfs(0)

    解释

    1. 初始化和预处理
      • 计算总长度并判断是否可以分成四条相等的边。
      • 将火柴棍按长度从大到小排序。
    2. DFS函数
      • 递归尝试将每根火柴棍放入四条边中的一条。
      • 如果某条边的长度超过了 side_length,则回溯。
      • 如果所有火柴棍都分配完毕且四条边的长度都等于 side_length,则返回 True
    3. 剪枝优化
      • 如果当前边的长度为0,则不需要继续尝试其他边,因为结果会相同。

    通过上述步骤,我们可以有效地判断是否可以用给定的火柴棍组成一个正方形。这个问题的核心在于合理地使用回溯算法和剪枝优化,以减少不必要的搜索空间。

  • Implement Rand10() Using Rand7(),LeetCode,470

    LeetCode 470题的要求是使用一个已有的rand7()函数来实现一个rand10()函数。rand7()函数可以等概率地生成1到7之间的整数,而我们需要设计一个rand10()函数来等概率地生成1到10之间的整数。

    思路分析

    直接使用rand7()生成1到10之间的数是有挑战的,因为7和10不是倍数关系。我们可以通过以下步骤来实现:

    1. 扩展范围:首先,我们可以通过调用两次rand7()来生成一个更大的范围。具体来说,我们可以生成一个1到49的均匀分布。
      • x = rand7()y = rand7(),则可以构造一个数z = (x - 1) * 7 + y,这样z的范围是1到49。
    2. 拒绝采样:由于我们需要的是1到10的数,我们可以利用1到49的范围,但需要排除掉一些数。具体来说,如果生成的数在1到40之间,我们可以利用这个数来生成1到10的数;如果生成的数在41到49之间,则重新生成。
    3. 映射到1到10:对于在1到40之间的数,我们可以通过取模操作将其映射到1到10。具体来说,z % 10 + 1就可以得到一个1到10之间的数。

    代码实现

    以下是具体的代码实现:

    def rand7():

    这是一个假设的函数,实际实现依赖于具体环境

    pass

    def rand10(): while True:

    生成1到49之间的数

        x = rand7()
        y = rand7()
        z = (x - 1) * 7 + y
    
        # 如果z在1到40之间,则接受这个数
        if z <= 40:
            return z % 10 + 1
    
        # 如果z在41到49之间,重新生成
        # 这里可以进一步优化,利用41到49之间的数来减少重新生成的概率
        # 但为了简单起见,我们直接重新生成

    详细解释

    1. 生成1到49的数
      • x = rand7()生成1到7之间的数。
      • y = rand7()生成1到7之间的数。
      • z = (x - 1) * 7 + yxy组合成一个1到49之间的数。这里(x - 1) * 7x映射到0, 7, 14, 21, 28, 35, 42,再加上y(1到7),得到1到49。
    2. 拒绝采样
      • 如果z在1到40之间,我们接受这个数。
      • 如果z在41到49之间,我们重新生成,因为这部分数不能均匀映射到1到10。
    3. 映射到1到10
      • 对于接受的数z,通过z % 10 + 1将其映射到1到10。

    时间复杂度

    虽然这个方法在最坏情况下可能需要多次调用rand7(),但其期望时间复杂度是常数时间,因为每次重新生成的概率是逐渐减小的。

    空间复杂度

    这个方法的空间复杂度是O(1),因为只需要常数级别的额外空间。

    通过这种方法,我们成功地将rand7()转换为rand10(),确保了生成的数的均匀性和随机性。

  • Convex Polygon,LeetCode,469

    LeetCode 469题是关于判断一个多边形是否为凸多边形的问题。凸多边形是指所有内角都小于180度的多边形,或者等价地说,多边形上任意两点的连线都在多边形内部。

    题目描述

    给定一个多边形的所有顶点坐标,你需要判断这个多边形是否为凸多边形。

    输入

    一个二维数组 points,其中每个元素是一个长度为2的数组,表示多边形的一个顶点的坐标。

    输出

    返回一个布尔值,表示这个多边形是否为凸多边形。

    示例

    输入: points = [[0,0],[0,1],[1,1],[1,0]] 输出: true

    输入: points = [[0,0],[0,1],[1,0]] 输出: false

    解题思路

    判断一个多边形是否为凸多边形可以通过计算相邻边之间的叉积(cross product)来实现。具体步骤如下:

    1. 计算叉积: 对于多边形的每三个连续顶点 (A, B, C),计算向量 (AB) 和 (BC) 的叉积。叉积的符号可以告诉我们 (B) 点处的转向是左转还是右转。
    2. 判断转向
      • 如果所有相邻边的叉积符号相同(全为正或全为负),则多边形为凸多边形。
      • 如果叉积符号不一致,则多边形不是凸多边形。
    3. 处理边界情况
      • 多边形至少需要3个顶点才能构成一个多边形。
      • 需要考虑顶点顺序的影响,可以统一按照顺时针或逆时针顺序处理。

    代码实现

    以下是使用Python实现的代码示例:

    def isConvex(points): def cross_product(o, a, b):

    计算向量 OA 和 OB 的叉积

        return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
    
    n = len(points)
    if n < 3:
        return False
    
    # 初始化前两个边的叉积符号
    pre = 0
    for i in range(n):
        # 当前点、下一个点和下下个点
        cur = cross_product(points[i], points[(i + 1) % n], points[(i + 2) % n])
        if cur != 0:
            if pre * cur < 0:
                return False
            pre = cur
    
    return True

    示例

    points1 = [[0,0],[0,1],[1,1],[1,0]] points2 = [[0,0],[0,1],[1,0]]

    print(isConvex(points1)) # 输出: True print(isConvex(points2)) # 输出: False

    解释

    1. cross_product函数:计算两个向量的叉积。
    2. 主函数isConvex
      • 首先检查顶点数量是否小于3,如果是则直接返回False。
      • 使用一个循环遍历所有顶点,计算每三个连续顶点形成的两个向量的叉积。
      • 如果叉积不为0,检查当前叉积与前一个叉积的符号是否相反,如果是则返回False。
      • 如果所有叉积符号一致,则返回True。

    通过这种方法,可以有效地判断一个多边形是否为凸多边形。希望这个解释对你理解并解决LeetCode 469题有所帮助!