日渐头秃的代码日记 -- 第319场周赛 勉强四题了

155 阅读4分钟

一、温度转换

给你一个四舍五入到两位小数的非负浮点数 celsius 来表示温度,以 摄氏度Celsius)为单位。

你需要将摄氏度转换为 开氏度Kelvin)和 华氏度Fahrenheit),并以数组 ans = [kelvin, fahrenheit] 的形式返回结果。

返回数组 ans 。与实际答案误差不超过 10-5 的会视为正确答案

注意:

  • 开氏度 = 摄氏度 + 273.15
  • 华氏度 = 摄氏度 * 1.80 + 32.00

 

示例 1 :

输入: celsius = 36.50
输出: [309.65000,97.70000]
解释: 36.50 摄氏度:转换为开氏度是 309.65 ,转换为华氏度是 97.70 。

示例 2 :

输入: celsius = 122.11
输出: [395.26000,251.79800]
解释: 122.11 摄氏度:转换为开氏度是 395.26 ,转换为华氏度是 251.798 。

 

提示:

  • 0 <= celsius <= 1000

解析

直接做

代码

class Solution:
    def convertTemperature(self, celsius: float) -> List[float]:
        k = round(celsius + 273.15, 5)
        f = round(celsius * 1.80 +  32.00, 5)
        return [k, f]
        

二、最小公倍数为 K 的子数组数目

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的 子数组 中满足 元素最小公倍数为 k 的子数组数目。

子数组 是数组中一个连续非空的元素序列。

数组的最小公倍数 是可被所有数组元素整除的最小正整数。

 

示例 1 :

输入: nums = [3,6,2,7,1], k = 6
输出: 4
解释: 以 6 为最小公倍数的子数组是:
- [3,6]
- [3,6,2]
- [6]
- [6,2]

示例 2 :

输入: nums = [3], k = 2
输出: 0
解释: 不存在以 2 为最小公倍数的子数组。

 

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i], k <= 1000

解析

暴力求解就行了,但是要注意剪枝,降低循环次数,最小公倍数就是相乘除以最大公约数

代码

from math import gcd

@cache
def mgcd(a, b):
    return gcd(a, b)

class Solution:
    
    def lcm(self, s):
        if len(set(s)) == 1:
            return s[0]
        if len(s)==1:
            return s[0]
        a, b = s[0], s[1]
        g = mgcd(a, b)
        a = (a*b)//g
        if len(s) > 2:
            for i in range(2, len(s)):
                b = s[i]
                g = mgcd(a, b)
                a = (a*b)//g
        # print(s, a)
        return a
    
    def subarrayLCM(self, nums: List[int], k: int) -> int:
        cnt = 0
        if len(set(nums)) == 1:
            if nums[0] == k:
                return (1 + len(nums)) * len(nums) // 2
        for i in range(len(nums)):
            if nums[i] > k:
                continue
            if k % nums[i] != 0:
                continue
            for j in range(i+1, len(nums)+1):
                if nums[j-1] > k:
                    break
                if k % nums[j-1] != 0:
                    break
                l = self.lcm(nums[i:j])
                if l == k:
                    cnt +=1 
        return cnt
                

三、逐层排序二叉树所需的最少操作数目

给你一个 值互不相同 的二叉树的根节点 root 。

在一步操作中,你可以选择 同一层 上任意两个节点,交换这两个节点的值。

返回每一层按 严格递增顺序 排序所需的最少操作数目。

节点的 层数 是该节点和根节点之间的路径的边数。

 

示例 1 :

输入: root = [1,4,3,7,6,8,5,null,null,null,null,9,null,10]
输出: 3
解释:
- 交换 43 。第 2 层变为 [3,4] 。
- 交换 75 。第 3 层变为 [5,6,8,7] 。
- 交换 87 。第 3 层变为 [5,6,7,8] 。
共计用了 3 步操作,所以返回 3 。
可以证明 3 是需要的最少操作数目。

示例 2 :

输入: root = [1,3,2,7,6,5,4]
输出: 3
解释: - 交换 3 和 2 。第 2 层变为 [2,3] 。 
- 交换 7 和 4 。第 3 层变为 [4,6,5,7] 。 
- 交换 6 和 5 。第 3 层变为 [4,5,6,7] 。
共计用了 3 步操作,所以返回 3 。 
可以证明 3 是需要的最少操作数目。

示例 3 :

输入: root = [1,2,3,4,5,6]
输出: 0
解释: 每一层已经按递增顺序排序,所以返回 0 。

 

提示:

  • 树中节点的数目在范围 [1, 10^5] 。
  • 1 <= Node.val <= 10^5
  • 树中的所有值 互不相同 。

解析

好在只是交换值,不需要交换节点,只要按照题目要求进行模拟就行,首先层序遍历,然后将每一层的值进行排序,进行交换,主要是一些空间换时间的优化手段

代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def change_position(self, src):
        target = sorted(src)
        op = copy.copy(src)
        search_map = dict()
        cnt = 0
        for index, value in enumerate(target):
            search_map[value] = index
        op_map = dict()
        for index, value in enumerate(op):
            op_map[value] = index
        for num in src:
            i = op_map[num]
            if i == search_map[num]:
                continue
            p = search_map[num]
            # print(op[i], op[p])
            op[i], op[p] = op[p], op[i]
            op_map[op[i]] = op_map[op[p]]
            op_map[op[p]] = i
            cnt += 1
        return cnt


    def minimumOperations(self, root: Optional[TreeNode]) -> int:
        res = []
        cnt = 0
        if not root:
            return cnt
        p = []
        p.append(root)
        
        while len(p) != 0:
            tmp = []
            for i in range(len(p)):
                r = p.pop(0)
                if r.left:
                    p.append(r.left)
                if r.right:
                    p.append(r.right)
                tmp.append(r.val)
            res.append(tmp)
            cnt += self.change_position(tmp)
        return cnt

四、不重叠回文子字符串的最大数目

给你一个字符串 s 和一个  整数 k 。

从字符串 s 中选出一组满足下述条件且 不重叠 的子字符串:

  • 每个子字符串的长度 至少 为 k 。
  • 每个子字符串是一个 回文串 。

返回最优方案中能选择的子字符串的 最大 数目。

子字符串 是字符串中一个连续的字符序列。

 

示例 1 :

输入: s = "abaccdbbd", k = 3
输出: 2
解释: 可以选择 s = "abaccdbbd" 中斜体加粗的子字符串。"aba""dbbd" 都是回文,且长度至少为 k = 3 。
可以证明,无法选出两个以上的有效子字符串。

示例 2 :

输入: s = "adbcda", k = 2
输出: 0
解释: 字符串中不存在长度至少为 2 的回文子字符串。

 

提示:

  • 1 <= k <= s.length <= 2000
  • s 仅由小写英文字母组成

解析

不需要使用DP

要求至少为k,只需要看长度是k 以及 k+1 这两种情况即可

代码

class Solution:
    @cache
    def isPalindrome(self, x):
        return x == x[::-1]
        
    def maxPalindromes(self, s: str, k: int) -> int:
        if k == 1:
            return len(s)
        i = 0
        cnt = 0
        while i <= len(s) - k:
            j = i + k
            x = s[i:j]
            if self.isPalindrome(x):
                cnt += 1
                print(x)
                i = j
            else:
                j = i + k + 1
                x = s[i:j]
                if self.isPalindrome(x):
                    cnt += 1
                    print(x)
                    i = j
                else:
                    i = i + 1
        
        return cnt

image.png 上图里36ms的解法是上述代码,1492ms的代码是DP的结果。