leetcode第146场周赛

本文分享了算法竞赛的经验总结,并详细解析了四道经典题目,包括等价多米诺骨牌对数量、颜色交替最短路径、叶值最小代价生成树及绝对值表达式最大值等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛感想

        做出了三题,掉分应该不会掉,最后一题没做出来,这次难度还行。第一题又把题目理解错了,挂了一次。。还得加油呀=,=

 

第一题 等价多米诺骨牌对的数量

题目大意

       给你一个由一些多米诺骨牌组成的列表 dominoes,dominoes[i] = [a, b] 和 dominoes[j] = [c, d] 等价的前提是 a==c 且 b==d,或是 a==d 且 b==c。现求等价的骨牌对 (i, j) 的数量。

解题思路

       每个多米诺骨牌的a,b,若a>b,将其换位,按第一列排序,在第一列相等的情况下排序第二列。相等的多米诺骨牌x块,则骨牌对数为x*(x - 1) / 2。

代码如下

class Solution:
    def numEquivDominoPairs(self, dominoes: List[List[int]]) -> int:
        for i in range(0, len(dominoes)):
            if dominoes[i][1] < dominoes[i][0]:
                (dominoes[i][0], dominoes[i][1]) = (dominoes[i][1], dominoes[i][0])
        dominoes = sorted(dominoes, key = lambda a:a[1])
        dominoes = sorted(dominoes, key= lambda a:a[0])
        i = 0
        sum = 0
        while i + 1 < len(dominoes):
            ls_sum = 1
            while i + 1 < len(dominoes) and dominoes[i] == dominoes[i + 1]:
                ls_sum += 1
                i += 1
        
            sum += ls_sum * (ls_sum - 1) // 2
            i += 1
        return sum

第二题 颜色交替的最短路径

题目大意

        在一个有向图中,节点分别标记为 0, 1, ..., n-1。这个图中的每条边不是红色就是蓝色,且存在自环或平行边。

   red_edges 中的每一个 [i, j] 对表示从节点 i 到节点 j 的红色有向边。类似地,blue_edges 中的每一个 [i, j] 对表示从节点 i到节点 j 的蓝色有向边。

        返回长度为 n 的数组 answer,其中 answer[X] 是从节点 0 到节点 X 的最短路径的长度,且路径上红色边和蓝色边交替出现。如果不存在这样的路径,那么 answer[x] = -1

解题思路

       我们可以用f[i][0]表示通过red道路到 i 这个点的最短路径,f[i][1]表示通过blue道路到 i 这个点的最短路径,用广度优先搜索即可。

代码如下

class Solution:
    def shortestAlternatingPaths(self, n: int, red_edges: List[List[int]], blue_edges: List[List[int]]) -> List[int]:
        red_edge = [set() for i in range(n)]
        blue_edge = [set() for i in range(n)]
        f = [[None, None] for i in range(n)]
        f[0] = [0, 0]
        for each in red_edges:
            red_edge[each[0]].add(each[1])
        for each in blue_edges:
            blue_edge[each[0]].add(each[1])
        #从0开始
        now_arrived_red = [0]
        now_arrived_blue = [0]
        step = 0
        #广搜
        while len(now_arrived_red) > 0 or len(now_arrived_blue) > 0:
            new_arrived_blue = []
            new_arrived_red = []
            step += 1
            for point in now_arrived_red:
                for path in blue_edge[point]:
                    if f[path][1] == None:
                        f[path][1] = step
                        new_arrived_blue.append(path)

            for point in now_arrived_blue:
                for path in red_edge[point]:
                    if f[path][0] == None:
                        f[path][0] = step
                        new_arrived_red.append(path)
            now_arrived_blue = new_arrived_blue
            now_arrived_red = new_arrived_red
        #获得答案
        ans = []
        for i in range(n):
            point_ans = -1
            if f[i][0] != None:
                point_ans = f[i][0]
            if f[i][1] != None:
                if point_ans == -1:
                    point_ans = f[i][1]
                else:
                    point_ans = min(point_ans, f[i][1])
            ans.append(point_ans)
        return ans

第三题 叶值的最小代价生成树

题目大意

       给你一个正整数数组 arr,考虑所有满足以下条件的二叉树:

  • 每个节点都有 0 个或是 2 个子节点。
  • 数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。(知识回顾:如果一个节点有 0 个子节点,那么该节点为叶节点。)
  • 每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。

        在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。

解题思路

       这题的关键是数组arr中的值与树的中序遍历中的值一一对应,这表示数组arr的顺序不能换。我们可以用f[i][j]表示从i到j的叶子构成的树中所有非叶节点的值的和的最小值。转移方程式:f[i][j] = min(f[i][j],f[i][k] + f[i][k+1][j] + max_leaf[i][k] * max_leaf[k+1][j]),时间效率为O(n^3)。

代码如下

class Solution:
    def mctFromLeafValues(self, arr: List[int]) -> int:
        f = [[None for i in range(len(arr))] for j in range(len(arr))]
        max_leaf = [[0 for i in range(len(arr))] for j in range(len(arr))]
        for i in range(len(arr)):
            for j in range(i, len(arr)):
                max_leaf[i][j] = max(max_leaf[i][j - 1], arr[j])

        for i in range(len(arr)):
            f[i][i] = 0

        for length in range(2, len(arr) + 1):
            for i in range(0, len(arr) - length + 1):
                j = i + length - 1
                for k in range(i, j):
                    if f[i][j] == None:
                        f[i][j] = f[i][k] + f[k + 1][j] + max_leaf[i][k] * max_leaf[k + 1][j]
                    else:
                        f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + max_leaf[i][k] * max_leaf[k + 1][j])
        return f[0][len(arr) - 1]

第四题 绝对值表达式的最大值

题目大意

       给你两个长度相等的整数数组,返回下面表达式的最大值:

  |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|

解题思路

       |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
        默认i > j则 原式 = |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + i - j
        |arr1[i] - arr1[j]| = max(arr1[i] - arr1[j], arr1[j] - arr1[i])
        |arr2[i] - arr2[j]| = max(arr2[i] - arr2[j], arr2[j] - arr2[i])
        原式 = max(arr1[i] - arr1[j], arr1[j] - arr1[i]) + max(arr2[i] - arr2[j], arr2[j] - arr2[i])  + i - j
        原式 = max(arr1[i] - arr1[j] + arr2[i] - arr2[j] + i - j,
                    arr1[i] - arr1[j] + arr2[j] - arr2[i] + i - j,
                    arr1[j] - arr1[i] + arr2[i] - arr2[j] + i - j,
                    arr1[j] - arr1[i] + arr2[j] - arr2[i] + i - j)
        原式 = max((arr1[i] + arr2[i] + i) - (arr1[j] + arr2[j] + j),
                    (arr1[i] - arr2[i] + i) - (arr1[j] - arr2[j] + j),
                    (-arr1[i] + arr2[i] + i) - (-arr1[j] + arr2[j] + j),
                    (-arr1[i] - arr2[i] + i) - (-arr1[j] - arr2[j] + j))

       故用四种情况算最大值即可。

代码如下

class Solution:
    def maxAbsValExpr(self, arr1: List[int], arr2: List[int]) -> int:
        '''
        原式 = max(arr1[i] - arr1[j], arr1[j] - arr1[i]) + max(arr2[i] - arr2[j], arr2[j] - arr2[i])  + i - j
            = max(arr1[i] - arr1[j] + arr2[i] - arr2[j] + i - j,
                    arr1[i] - arr1[j] + arr2[j] - arr2[i] + i - j,
                    arr1[j] - arr1[i] + arr2[i] - arr2[j] + i - j,
                    arr1[j] - arr1[i] + arr2[j] - arr2[i] + i - j)
            = max((arr1[i] + arr2[i] + i) - (arr1[j] + arr2[j] + j),
                    (arr1[i] - arr2[i] + i) - (arr1[j] - arr2[j] + j),
                    (-arr1[i] + arr2[i] + i) - (-arr1[j] + arr2[j] + j),
                    (-arr1[i] - arr2[i] + i) - (-arr1[j] - arr2[j] + j))

        :param arr1:数组1
        :param arr2:数组2
        :return: |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j| 最大值
        '''
        ans = -99999999999
        for operator1 in [-1, 1]:
            for operator2 in [-1, 1]:
                minn = None
                for i in range(len(arr1)):
                    value = arr1[i] * operator1 + arr2[i] * operator2 + i
                    if i == 0:
                        minn = value
                    else:
                        minn = min(minn, value)
                        ans = max(ans, value - minn)

        return ans

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值