[LeetCode周赛复盘] 第 100 场双周赛20230401

[LeetCode周赛复盘] 第 100 场双周赛20230401

    • 一、本周周赛总结
    • 二、 [Easy] 6327. 从两个数字数组里生成最小数字
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 三、[Medium] 6328. 找到最大开销的子字符串
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 四、[Medium] 6329. 使子数组元素和相等
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 五、[Hard] 6330. 图中的最短环
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 六、参考链接

一、本周周赛总结

  • T4是模板题,现场百度的。
  • T1 贪心模拟。
  • T2 套壳最大子段和。
  • T3 贪心结论题+中位数贪心。
  • T4 最短路。
    [LeetCode周赛复盘] 第 100 场双周赛20230401_第1张图片

二、 [Easy] 6327. 从两个数字数组里生成最小数字

链接: 6327. 从两个数字数组里生成最小数字

1. 题目描述

[LeetCode周赛复盘] 第 100 场双周赛20230401_第2张图片

2. 思路分析

  • 题意表述很奇怪。目标找一个数字,这个数字要跟数组1和2都有关系。
  • 关系就是有一位数在数组里。
  • 由于数都是个位数,因此如果有交集,交集最小那个就是答案。
  • 否则取两边最小的拼起来。

3. 代码实现

class Solution:
    def minNumber(self, nums1: List[int], nums2: List[int]) -> int:        
        x = set(nums1)&set(nums2)
        if x:
            return min(x)
        a,b = min(nums1), min(nums2)        
        return min(a*10+b,b*10+a)        

三、[Medium] 6328. 找到最大开销的子字符串

链接: 6328. 找到最大开销的子字符串

1. 题目描述

[LeetCode周赛复盘] 第 100 场双周赛20230401_第3张图片

2. 思路分析

  • 由于字符串的开销是字符对应的价值之和,因此把字符直接替换成价值即可。
  • 那么题目就变成求最大字段和,注意可以是空字符串0.

3. 代码实现

class Solution:
    def maximumCostSubstring(self, s: str, chars: str, vals: List[int]) -> int:
        cost ={}
        for i in range(26):
            cost[chr(ord('a')+i)] = i+1
        for c,p in zip(chars,vals):
            cost[c] = p
        
        n = len(s)
        f = [0]*n
        f[0] = cost[s[0]]
        for i in range(1,n):
            if f[i-1]>0:
                f[i] = cost[s[i]] + f[i-1]
            else:
                f[i] = cost[s[i]]
        return max(0,max(f))                    

四、[Medium] 6329. 使子数组元素和相等

链接: 6329. 使子数组元素和相等

1. 题目描述

[LeetCode周赛复盘] 第 100 场双周赛20230401_第4张图片

2. 思路分析

  • 注意数组是循环的。
  • 用滑窗考虑,如果每个k段和都相等,那么a[i]一定等于a[i+k],因为窗口右滑的时候,i要出去i+k要进来,和还不能变,因此他俩必相等。
  • 由于数组是循环的,因此相等的下标也要首尾循环,这种取模关系一般可以gcd,于是猜了结论:最小间隔是gcd的数字集合,必须是同一组,他们要相等。
  • 问题转化成,每组内操作步数最小,然后加起来。
  • 这个问题就是,给一个数组,让他们都走到一样的数,最少多少步;这题有结论,就是都走到中位数,如果n是偶数,那中间两个数任意都可以。
  • 对数组排序,令中间的数下标为p,求左边和右边的求和跟它的差即可。
  • 特判,如果gcd=1,那么必须全部相等。

3. 代码实现

class Solution:
    def makeSubKSumEqual(self, arr: List[int], k: int) -> int:
        n = len(arr)
        g = gcd(n,k)
        
        def f(a):
            a.sort()
            x = len(a)            
            p = x//2
            return p*a[p] - sum(a[:p]) + sum(a[p:]) - (x-p)*a[p]
            
        if g == 1:
            return f(arr)
        ans = 0
        for i in range(g):
            ans += f(arr[i::g])
        return ans         

五、[Hard] 6330. 图中的最短环

链接: 6330. 图中的最短环

1. 题目描述

[LeetCode周赛复盘] 第 100 场双周赛20230401_第5张图片

2. 思路分析

  • 看完题感觉很板就去百度了。就是求最小环,而且是简化版。
  • 原题是带边权的图,求最小/短环。
    • 原题做法是遍历删除每条边u-v-w,然后dijkstra求dis[u][v]的最短路。
    • 若连通,显然uv在环上,这个环的长度就是dis[u][v]+w。复杂度是O(nmlogn)
    • 还可以用floyd做,最外层枚举到k时,设与k相邻的两个点u,v,只枚举小于k的u,v更新答案即可。但复杂度是O(n3)
  • 然而这题边权是1,因此直接bfs即可。复杂度O(mn)

3. 代码实现


class Solution:
    def findShortestCycle(self, n: int, edges: List[List[int]]) -> int:
        g = [[] for _ in range(n)]
        for u,v in edges:
            g[u].append(v)
            g[v].append(u)
        def f(d1,d2):
            q = deque([(d1,-1)])
            dis = [inf]*n
            dis[d1] = 0
            while q:
                u,fa = q.popleft()
                for v in g[u]:
                    if v == fa:
                        continue 
                    if u == d1 and v == d2 or u==d2 and v == d1:
                        continue
                    if dis[v] == inf:
                        dis[v] = dis[u]+1
                        q.append((v,u))
            # print(d1,d2,dis)
            return dis[d2]
                    
        ans = n+1 
        for u,v in edges:            
            ans = min(ans,f(u,v)+1)
        if ans == n+1:
            return -1 
        return ans                

六、参考链接

你可能感兴趣的:(力扣周赛复盘,leetcode,算法,职场和发展)