最大单词长度乘积
题目
给你一个字符串数组 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)