[Python3] 力扣第205场周赛 题解

P1. 替换所有的问号 显示英文描述

给你一个仅包含小写英文字母和 ‘?’ 字符的字符串 s ,请你将所有的 ‘?’ 转换为若干小写字母,使最终的字符串不包含任何 连续重复 的字符。

注意:你 不能 修改非 ‘?’ 字符。

题目测试用例保证 除 ‘?’ 字符 之外,不存在连续重复的字符。

在完成所有转换(可能无需转换)后返回最终的字符串。如果有多个解决方案,请返回其中任何一个。可以证明,在给定的约束条件下,答案总是存在的。

解:

  1. “ x ? y " = > " x z y " “x?y" => "xzy" x?y"=>"xzy"
  2. " x 0 ? ? ? y " = > " x 1 ? ? y " = > . . . "x_0???y"=>"x_1??y" => ... "x0???y"=>"x1??y"=>...
  3. 遍历+枚举, 因为解一定存在。
class Solution:
    def modifyString(self, s: str) -> str:
        ret = ['^']
        n = len(s)
        s = ['^'] + list(s) + ['$']
        f = lambda x: chr(ord('a') + x)
        A = [f(x) for x in range(26)]
        for i in range(1, n+1):    
            if s[i] != '?': 
                ret.append(s[i])
            else:    
                for ch in A:
                    if ch != ret[-1] and ch != s[i+1]:
                        ret.append(ch)
                        break
            
        return "".join(ret[1:])

P2. 数的平方等于两数乘积的方法数

给你两个整数数组 nums1 和 nums2 ,请你返回根据以下规则形成的三元组的数目(类型 1 和类型 2 ):

类型 1:三元组 (i, j, k) ,如果 nums1[i]2 == nums2[j] * nums2[k] 其中 0 <= i < nums1.length 且 0 <= j < k < nums2.length
类型 2:三元组 (i, j, k) ,如果 nums2[i]2 == nums1[j] * nums1[k] 其中 0 <= i < nums2.length 且 0 <= j < k < nums1.length

解:

  1. Hash
class Solution:
    def numTriplets(self, nums1: List[int], nums2: List[int]) -> int:
        return self.solve(nums1, nums2) + self.solve(nums2, nums1)
    def solve(self, nums1: List[int], nums2: List[int]) -> int:
        d = collections.defaultdict(int)
        n1, n2 = len(nums1), len(nums2)
        for j in range(n1):
            for k in range(j+1, n1):
                d[nums1[j] * nums1[k]] += 1
        return sum(d[x * x] for x in nums2)  

P3. 避免重复字母的最小删除成本

给你一个字符串 s 和一个整数数组 cost ,其中 cost[i] 是从 s 中删除字符 i 的代价。

返回使字符串任意相邻两个字母不相同的最小删除成本。

请注意,删除一个字符后,删除其他字符的成本不会改变。

解:

  1. 不用华丽的操作, 只要扫一遍。
  2. 我为什么要贴个st表, wa了4发。
class Solution:
    def minCost(self, s: str, cost: List[int]) -> int:
        c, m, n, ret = cost[0], cost[0], len(s), 0
        for i in range(1, n):
            if s[i] == s[i-1]:
                c += cost[i]
                m = max(m, cost[i])
            else:    
                ret += c - m
                c, m = cost[i], cost[i]
        ret += c - m        
        return ret

code 2 (比赛时,萌萌的自己,居然还被我搞过去了):

from math import log
class ST:
    def __init__(self, arr):
        n = len(arr)
        K = int(log(n, 2))
        self.Ma = [[0]*(K+1) for _ in range(n)]
        for k in range(K+1):
            for i in range(n):
                if k == 0:
                    self.Ma[i][k] = arr[i]
                else:
                    if i + (1 << (k - 1)) >= n:
                        continue
                    self.Ma[i][k] = max(self.Ma[i][k-1], self.Ma[i+(1 << (k-1))][k-1])

    def query_max(self, L, R):
        k = int(log(R - L + 1, 2))
        return max(self.Ma[L][k], self.Ma[R - (1 << k) + 1][k])

class Solution:
    def minCost(self, s: str, cost: List[int]) -> int:
        st = ST(cost)
        n = len(cost)
        prefix = [0] * n
        for i in range(n):
            prefix[i] = prefix[i-1] + cost[i]
        def get(L, R):    
            return prefix[R] if L == 0 else prefix[R] - prefix[L-1]
        f = lambda L, R: get(L, R) - st.query_max(L, R)
        L, R, ret = 0, -1, 0
        for i in range(1, n):
            if s[i] != s[L]:
                if R != -1:
                    ret += f(L, R)
                L, R = i, -1
            else:    
                R = i
                    
        if R != -1:  ret += f(L, R)
        return ret

P4 保证图可完全遍历

Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3 种类型的边:

类型 1:只能由 Alice 遍历。
类型 2:只能由 Bob 遍历。
类型 3:Alice 和 Bob 都可以遍历。
给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。

返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。

解:

  1. 倒着思考, 用并查集 带个 路径压缩。 一开始没加,T了。
class DSU:
    def __init__(self, N):
        self.parent = [i for i in range(N)]
    def find(self, x):   
        if self.parent[x] == x: return x
        ret = self.find(self.parent[x])
        self.parent[x] = ret
        return ret
    def union(self, x, y):   
        self.parent[self.find(x)] = self.parent[self.find(y)]
class Solution:
    def maxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -> int:
        dsu = DSU(n)
        def valid(dsu):
            A = [dsu.find(i) for i in range(n)]
            return len(set(A)) == 1
        t3 = [[x - 1, y - 1] for t, x, y in edges if t == 3]
        t2 = [[x - 1, y - 1] for t, x, y in edges if t == 2]
        t1 = [[x - 1, y - 1] for t, x, y in edges if t == 1]
        use, m = 0, len(edges)
        def add_graph(dsu, t):
            nonlocal use
            for x, y in t:
                if dsu.find(x) != dsu.find(y):
                    dsu.union(x, y)
                    use += 1
        add_graph(dsu, t3)            
        dsu2 = DSU(n)       
        dsu2.parent = [x for x in dsu.parent]
        add_graph(dsu2, t2)
        add_graph(dsu, t1)
        return m - use if valid(dsu) and valid(dsu2) else -1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值