力扣周赛330题解

108 阅读3分钟

最大单词长度乘积

题目

给你一个字符串数组 words ,找出 words[i] 和 words[j] 乘积的最大值,其中两个字符串中没有公共字母。如果不存在这样的两个字符串,返回 0 。

示例 1:

输入:words = ["abcw","baz","foo","bar","xtfn","abcdef"] 输出:16 解释:这两个单词为 "abcw" 和 "xtfn" ,它们的乘积为 4 * 4 = 16 。 示例 2:

输入:words = ["a","ab","abc","d","cd","bcd","abcd"] 输出:4 解释:这两个单词为 "ab" 和 "cd" ,它们的乘积为 2 * 2 = 4 。 示例 3:

输入:words = ["a","aa","aaa","aaaa"] 输出:0 解释:不存在这样的两个字符串。

提示:

  • 2 <= words.length <= 1000
  • 1 <= words[i].length <= 1000
  • words[i] 仅包含小写字母
  • words[i] 中的所有字符都是唯一的

解析

  • 遍历每个单词,用一个整数表示它包含的字母,比如"a"对应1,"b"对应2,"ab"对应3,以此类推。这样可以用位运算来判断两个单词是否有公共字母,即如果两个整数的按位与结果为0,就说明没有公共字母。
  • 然后用一个双重循环遍历所有单词的组合,计算它们的长度乘积,并更新最大值。
  • 最后返回最大值。

我的代码如下:

class Solution:
    def maxProduct(self, words: List[str]) -> int:
        # 将每个单词转换为一个整数表示它包含的字母
        nums = []
        for word in words:
            num = 0
            for c in word:
                num |= (1 << (ord(c) - ord('a')))
            nums.append(num)
        
        # 遍历所有单词的组合,计算长度乘积,并更新最大值
        ans = 0
        n = len(words)
        for i in range(n):
            for j in range(i + 1, n):
                # 如果两个单词没有公共字母,就更新答案
                if nums[i] & nums[j] == 0:
                    ans = max(ans, len(words[i]) * len(words[j]))
        
        return ans

最大子序列交替和

题目描述

给你一个整数数组 nums ,请你找出 nums 中一个 交替和 最大的子序列,并返回该子序列的 交替和 。

交替和 的定义为:一个子序列的偶数索引处的元素之和 减去 该子序列奇数索引处的元素之和。

示例 1:

输入:nums = [4,2,5,3] 输出:7 解释:最优子序列为 [4,2,5] ,交替和为 (4 + 5) - 2 = 7 。 示例 2:

输入:nums = [5,6,7,8] 输出:8 解释:最优子序列为 [8] ,交替和为 8 。 示例 3:

输入:nums = [6,2,1,2,4,5] 输出:10 解释:最优子序列为 [6,1,5] ,交替和为 (6 + 5) - 1 = 10 。

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

解析

  • 使用动态规划的方法,维护两个状态变量,odd 和 even,分别表示以奇数索引或偶数索引结尾的最大交替和。
  • 遍历数组中的每个元素,根据它的奇偶性更新 odd 和 even 的值,具体如下:
    • 如果当前元素是奇数,那么它可以加到以偶数索引结尾的最大交替和上,得到一个新的以奇数索引结尾的最大交替和,即 odd = max(odd, even + nums[i])。同时,它也可以作为一个新的子序列的起点,即 odd = max(odd, nums[i])。
    • 如果当前元素是偶数,那么它可以加到以奇数索引结尾的最大交替和上,得到一个新的以偶数索引结尾的最大交替和,即 even = max(even, odd + nums[i])。同时,它也可以作为一个新的子序列的起点,即 even = max(even, nums[i])。
  • 最后返回 odd 和 even 中的较大值作为答案。

我的代码如下:

class Solution:
    def maxAlternatingSum(self, nums: List[int]) -> int:
        # 初始化两个状态变量
        odd = 0 # 表示以奇数索引结尾的最大交替和
        even = 0 # 表示以偶数索引结尾的最大交替和
        
        # 遍历数组中的每个元素
        for num in nums:
            # 如果当前元素是奇数
            if num % 2 == 1:
                # 更新 odd 的值
                odd = max(odd, even + num) # 加到以偶数索引结尾的最大交替和上
                odd = max(odd, num) # 或者作为一个新的子序列的起点
            # 如果当前元素是偶数
            else:
                # 更新 even 的值
                even = max(even, odd + num) # 加到以奇数索引结尾的最大交替和上
                even = max(even, num) # 或者作为一个新的子序列的起点
        
        # 返回 odd 和 even 中的较大值作为答案
        return max(odd, even)

最大平均通过率。

题目

一所高中有 n 个班级,编号为 0 到 n - 1 。每个班级有一些学生,编号为 0 到 29 。每个班级的学生数量可能不同。每个班级的考试成绩存储在一个二维整数数组 classes 中,其中 classes[i][j] 是第 i 个班级中第 j 个学生的成绩。每个班级的通过率等于该班级中及格(成绩至少为 50 分)的学生数量除以该班级的学生数量。

你可以在任意次数的考试中给任意一个学生加分(一次一分),使他们的成绩变高。请你返回在 k 次加分操作后,所有班级的 最大 平均通过率。

与标准答案误差范围在 10^-5 以内的结果都会被视为正确结果。

示例 1:

输入:classes = [[1,2,3],[3,2,1]], k = 2 输出:0.78333 解释:可以将第一个班级的第一个学生和第二个学生各加一分,这样该班级的通过率为 (3/3) ,第二个班级的通过率仍为 (2/3) ,平均通过率为 (3/3 + 2/3) / 2 = 0.78333 。 示例 2:

输入:classes = [[2,4],[3,9],[4,5],[2,10]], k = 4 输出:0.53485

提示:

  • 1 <= classes.length <= 10^5
  • classes[i].length == 2
  • 1 <= classes[i][j] <= 10^6
  • 1 <= k <= 10^9

解析

  • 使用优先队列(堆)的方法,维护一个最大堆,其中每个元素表示一个班级的信息,包括该班级当前的通过率、及格人数、总人数和增加一分后的通过率提升。
  • 遍历所有班级,计算它们的初始信息,并将它们加入到最大堆中,按照通过率提升排序。
  • 然后进行 k 次循环,每次从最大堆中取出当前提升最大的班级,给它加一分,并更新它的信息,再将它放回到最大堆中。
  • 最后遍历最大堆中的所有元素,计算它们的平均通过率,并返回结果。

代码

import heapq

class Solution:
    def maxAverageRatio(self, classes: List[List[int]], k: int) -> float:
        # 定义一个函数,计算给一个班级加一分后的通过率提升
        def get_delta(passed, total):
            return (passed + 1) / (total + 1) - passed / total
        
        # 初始化一个最大堆,其中每个元素表示一个班级的信息
        heap = []
        for passed, total in classes:
            # 计算该班级当前的通过率、及格人数、总人数和增加一分后的通过率提升
            ratio = passed / total
            delta = get_delta(passed, total)
            # 将这些信息作为一个元组加入到最大堆中,按照通过率提升排序
            heapq.heappush(heap, (-delta, passed, total))
        
        # 进行 k 次循环,每次从最大堆中取出当前提升最大的班级,给它加一分,并更新它的信息,再将它放回到最大堆中
        for _ in range(k):
            # 取出当前提升最大的班级
            delta, passed, total = heapq.heappop(heap)
            # 给它加一分
            passed += 1
            total += 1
            # 更新它的通过率和通过率提升
            ratio = passed / total
            delta = get_delta(passed, total)
            # 将它放回到最大堆中
            heapq.heappush(heap, (-delta, passed, total))
        
        # 初始化平均通过率为 0
        ans = 0
        # 遍历最大堆中的所有元素,计算它们的平均通过率
        for delta, passed, total in heap:
            ans += passed / total
        
        # 返回平均通过率除以班级数量
        return ans / len(classes)