力扣周赛334

139 阅读6分钟

第一题:三除数

题目

给你一个整数 n 。如果 n 恰好有三个正除数,返回 true ,否则返回 false 。

如果存在整数 k ,满足 n = k * m ,那么整数 m 就是 n 的一个 除数 。

思路:

如果 n 有三个正除数,那么它们一定是 1, sqrt(n) 和 n 本身。也就是说,n 一定是一个完全平方数,并且 sqrt(n) 是一个质数。所以,我们只需要判断 n 是否是完全平方数,并且 sqrt(n) 是否是质数即可。判断完全平方数可以用开方后取整再平方的方法,判断质数可以用试除法。

代码:

import math

class Solution:
    def isThree(self, n: int) -> bool:
        # 判断是否是完全平方数
        root = int(math.sqrt(n))
        if root * root != n:
            return False
        # 判断sqrt(n)是否是质数
        for i in range(2, int(math.sqrt(root)) + 1):
            if root % i == 0:
                return False
        return True

第二题:你可以工作的最大周数

题目

给你 n 个项目,编号从 0 到 n - 1 。同时给你一个整数数组 milestones ,其中每个 milestones[i] 表示第 i 个项目中的阶段任务数量。

你可以按下面两个规则参与项目中的工作:

  • 每周,你将会完成 某一个 项目中的 恰好一个 阶段任务。你每周都 必须 工作。
  • 在 连续的 两周中,你 不能 参与并完成同一个项目中的两个阶段任务。

一旦所有项目中的全部阶段任务都完成,或者仅剩余一个阶段任务都会导致你违反上面的规则,那么你将 停止工作 。注意,由于这些条件的限制,你可能无法完成所有阶段任务。

返回在不违反上面规则的情况下你 最多 能工作多少周。

思路:

我们可以发现,如果有一个项目的阶段任务数量超过了其他所有项目的阶段任务数量之和,那么我们就无法完成所有阶段任务,因为最后一定会剩下这个项目的一个阶段任务无法完成。所以,我们需要保证最大的阶段任务数量不超过其他所有阶段任务数量之和。如果满足这个条件,那么我们可以按照贪心的策略,每次选择剩余阶段任务数量最多的两个不同的项目来完成,这样可以尽可能地平衡各个项目的进度,避免出现无法完成的情况。所以,我们只需要对 milestones 数组进行排序,然后判断最大的阶段任务数量是否超过了其他所有阶段任务数量之和,如果是,那么答案就是其他所有阶段任务数量之和的两倍再加一;如果不是,那么答案就是所有阶段任务数量之和。

代码:

class Solution:
    def numberOfWeeks(self, milestones: List[int]) -> int:
        # 对milestones数组进行排序
        milestones.sort()
        # 计算最大的阶段任务数量和其他所有阶段任务数量之和
        max_milestone = milestones[-1]
        other_sum = sum(milestones[:-1])
        # 判断是否满足条件
        if max_milestone > other_sum:
            # 答案是其他所有阶段任务数量之和的两倍再加一
            return other_sum * 2 + 1
        else:
            # 答案是所有阶段任务数量之和
            return max_milestone + other_sum

第三题:构造元素不等于两相邻元素平均值的数组

题目

给你一个 下标从 0 开始 的数组 nums ,数组由若干 互不相同的 整数组成。你打算重新排列数组中的元素以满足:重排后,数组中的每个元素都 不等于 其两侧相邻元素的 平均值 。

更公式化的说法是,重新排列后,数组中的每个元素都不等于其左右相邻元素的平均值,也就是说,对于重新排列后的数组中的任意下标 i ,都满足 nums[i] != (nums[i-1] + nums[i+1]) / 2 。

返回满足题意的任一重排结果。

思路:

我们可以发现,如果数组中有三个连续的元素是升序或降序排列的,那么它们就不满足题目的条件。例如,如果有 a < b < c ,那么 b = (a + c) / 2 。所以,我们需要避免出现这样的情况。一个简单的方法是,将数组分成两部分,一部分是奇数下标的元素,另一部分是偶数下标的元素,然后将两部分分别排序,再交错合并。这样可以保证任意三个连续的元素都不是升序或降序排列的,因为奇数下标的元素都大于或等于偶数下标的元素。例如,如果有 a <= b <= c <= d ,那么合并后得到 a, c, b, d ,就满足题目的条件。

代码:

class Solution:
    def rearrangeArray(self, nums: List[int]) -> List[int]:
        # 将数组分成奇数下标和偶数下标两部分
        odd = nums[1::2]
        even = nums[0::2]
        # 将两部分分别排序
        odd.sort()
        even.sort()
        # 交错合并两部分
        ans = []
        for i in range(len(nums)):
            if i % 2 == 0:
                ans.append(even[i // 2])
            else:
                ans.append(odd[i // 2])
        return ans

第四题:统计特殊子序列的数目

题目

给你一个字符串 s ,由小写英文字母组成,且长度为 n 。一个 子序列 是由 s 中的一些字符(可能全部)组成的一个字符串,且不改变这些字符在 s 中的相对顺序。

如果一个子序列满足以下条件,那么它就是一个 特殊子序列 :

  • 子序列中的所有字符都是 a ,b 或 c 。
  • 子序列中恰好有 a 个 'a' , b 个 'b' 和 c 个 'c' 。

例如,"abcbcc" 是一个特殊子序列,因为它满足上述条件(a=1, b=2, c=3)。另外,"abc" 也是一个特殊子序列,因为它满足上述条件(a=1, b=1, c=1)。

返回 s 中 特殊子序列 的数目。由于答案可能很大,请将它对 10^9 + 7 取余后返回。

思路:

我们可以用动态规划的方法来解决这个问题。我们用 dp[i][j][k] 表示 s 的前 i 个字符中,满足 a = j, b = k 的特殊子序列的数目。那么,我们可以根据 s[i-1] 的值来更新 dp[i][j][k] 。如果 s[i-1] 是 'a' ,那么 dp[i][j][k] 等于 dp[i-1][j-1][k] (选择 s[i-1] 作为最后一个 'a' )加上 dp[i-1][j][k] (不选择 s[i-1] )。如果 s[i-1] 是 'b' ,那么 dp[i][j][k] 等于 dp[i-1][j][k-1] (选择 s[i-1] 作为最后一个 'b' )加上 dp[i-1][j][k] (不选择 s[i-1] )。如果 s[i-1] 是 'c' ,那么 dp[i][j][k] 等于 dp[i-1][j][k] (选择 s[i-1] 作为最后一个 'c' )加上 dp[i-1][j][k] (不选择 s[i-1] )。如果 s[i-1] 不是 'a' ,'b' 或 'c' ,那么 dp[i][j][k] 等于 dp[i-1][j][k] (不选择 s[i-1] )。最后,我们需要将所有的 dp[n][j][k] 相加,就得到了答案。注意,空字符串也是一个特殊子序列,所以我们需要初始化 dp[0][0][0] = 1 。另外,由于答案可能很大,我们需要对每次更新和求和都取模。

代码:

class Solution:
    def countSpecialSubsequences(self, s: str) -> int:
        # 定义动态规划数组
        n = len(s)
        dp = [[[0 for _ in range(4)] for _ in range(4)] for _ in range(n + 1)]
        # 定义模数
        mod = 10**9 + 7
        # 初始化空字符串情况
        dp[0][0][0] = 1
        # 遍历s中的每个字符
        for i in range(1, n + 1):
            # 遍历每种a,b,c的数量
            for j in range(4):
                for k in range(4):
                    # 根据s[i-1]的值更新dp[i][j][k]
                    if s[i-1] == 'a':
                        if j > 0:
                            # 可以选择或不选择s[i-1]
                            dp[i][j][k] = (dp[i-1][j-1][k] + dp[i-1][j][k]) % mod
                        else:
                            # 不可以选择s[i-1]
                            dp[i][j][k] = dp[i-1][j][k]
                    elif s[i-1] == 'b':
                        if k > 0:
                            # 可以选择或不选择s[i-1]
                            dp[i][j][k] = (dp[i-1][j][k-1] + dp[i-1][j][k]) % mod
                        else:
                            # 不可以选择s[i-1]
                            dp[i][j][k] = dp[i-1][j][k]
                    elif s[i-1] == 'c':
                        # 可以选择或不选择s[i-1]
                        dp[i][j][k] = (dp[i-1][j][k] * 2) % mod
                    else:
                        # 不可以选择s[i-1]
                        dp[i][j][k] = dp[i-1][j][k]
        # 计算答案
        ans = 0
        for j in range(4):
            for k in range(4):
                ans = (ans + dp[n][j][k]) % mod
        return ans