【周赛】第146场-2019-7-21

目录

 

1-等价多米诺骨牌对的数量-easy。数组

2-颜色交替的最短路径-medium。BFS、位运算

3-叶值的最小代价生成树-medium。树

4-绝对值表达式的最大值-medium。数学


1-等价多米诺骨牌对的数量-easy。数组

给你一个由一些多米诺骨牌组成的列表 dominoes

如果其中某一张多米诺骨牌可以通过旋转 0 度或 180 度得到另一张多米诺骨牌,我们就认为这两张牌是等价的。

形式上,dominoes[i] = [a, b] 和 dominoes[j] = [c, d] 等价的前提是 a==c 且 b==d,或是 a==d 且 b==c

在 0 <= i < j < dominoes.length 的前提下,找出满足 dominoes[i] 和 dominoes[j] 等价的骨牌对 (i, j) 的数量。

示例:

输入:dominoes = [[1,2],[2,1],[3,4],[5,6]]
输出:1
  • 一开始错误理解了题意,以为求的是最大等价骨牌数,其实求的是所有的等价骨牌对数量。做法就是用字典求所有同质的骨牌数量,然后对数量求组合,因为必有一前一后虽然包含了排列的思想,但前后固定,相当于只求组合,所以对所有骨牌对的数量求组合即可。
  • 大神的解法。思路更加简单,就是每多一个同质骨牌,相当于和其他所有先出现的同质骨牌构成骨牌对,数量就等于dic[do],然后再更新dic[do]

 

# DIY
class Solution:
    def numEquivDominoPairs(self, dominoes: List[List[int]]) -> int:
        if not dominoes:
            return 0
        dic = {}
        m = len(dominoes)
        for i in range(m):
            if dominoes[i][0] > dominoes[i][1]:
                dominoes[i][0], dominoes[i][1] = dominoes[i][1], dominoes[i][0]
            tu_do = tuple(dominoes[i])
            dic[tu_do] = dic.get(tu_do, 0) + 1
        res = 0
        for val in dic.values():
            res += val * (val - 1)//2
        return res
    
    def equal(self, a, b):
        return (a[0] == b[0] and a[1] == b[1]) or (a[0] == b[1] and a[1] == b[0])

# 大神的解法
class Solution:
    def numEquivDominoPairs(self, dominoes: List[List[int]]) -> int:
        if not dominoes:
            return 0
        dic = {}
        res = 0
        for do in dominoes:
            do.sort()
            tu_do = tuple(do)
            res += dic.get(tu_do, 0)
            dic[tu_do] = dic.get(tu_do, 0) + 1
        return res

2-颜色交替的最短路径-medium。BFS、位运算

在一个有向图中,节点分别标记为 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

示例 1:

输入:n = 3, red_edges = [[0,1],[1,2]], blue_edges = []
输出:[0,1,-1]

示例 2:

输入:n = 3, red_edges = [[0,1]], blue_edges = [[2,1]]
输出:[0,1,-1]

示例 3:

输入:n = 3, red_edges = [[1,0]], blue_edges = [[2,1]]
输出:[0,-1,-1]

示例 4:

输入:n = 3, red_edges = [[0,1]], blue_edges = [[1,2]]
输出:[0,1,2]

示例 5:

输入:n = 3, red_edges = [[0,1],[0,2]], blue_edges = [[1,0]]
输出:[0,1,1]

利用下一跳节点的编号来处理红蓝交替的逻辑,剩下就是BFS更新最短路径的做法

  •  关键点1,图的表示,用两个列表存储红蓝两组路径,下标表示起点,下标对应元素表示下一跳的集合,dis存储最短距离,-1表示不可达,一开始起点的编号对应是0和n
class Solution:
    def shortestAlternatingPaths(self, n: int, red_edges: List[List[int]], blue_edges: List[List[int]]) -> List[int]:
        # 前n个表示
        dis = [-1] * (n*2)
        dis[0] = 0
        dis[n] = 0
        que = [0, n]
        blues = [[] for _ in range(n)]
        reds = [[] for _ in range(n)]
        for red in red_edges:
            reds[red[0]].append(red[1] + n)
        for blue in blue_edges:
            blues[blue[0]].append(blue[1])
        while que:
            cur = que.pop(0)
            edge = reds[cur] if cur < n else blues[cur-n]
            for d in edge:
                if dis[d] == -1:
                    dis[d] = dis[cur] + 1
                    que.append(d)
        res = [-1]*n
        for i in range(n):
            if dis[i] > -1:
                res[i] = dis[i]
            if dis[i+n] > -1:
                res[i] = dis[i+n] if res[i] == -1 else min(res[i], dis[i+n])
        return res

3-叶值的最小代价生成树-medium。树

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

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

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

示例:

输入:arr = [6,2,4]
输出:32
解释:
有两种可能的树,第一种的非叶节点的总和为 36,第二种非叶节点的总和为 32。

    24            24
   /  \          /  \
  12   4        6    8
 /  \               / \
6    2             2   4

暂时不懂,把第一名的代码先贴这 

const int N_MAX = 105;
const long long LL_INF = (long long) 2e18 + 5;

class Solution {
public:
    int n;
    vector leaves;
    long long dp[N_MAX][N_MAX];

    long long solve(int start, int end) {
        if (end - start <= 1)
            return 0;

        long long &answer = dp[start][end];

        if (answer >= 0)
            return answer;

        answer = LL_INF;

        for (int i = start + 1; i < end; i++) {
            int left = 0, right = 0;

            for (int j = start; j < i; j++)
                left = max(left, leaves[j]);

            for (int j = i; j < end; j++)
                right = max(right, leaves[j]);

            answer = min(answer, left * right + solve(start, i) + solve(i, end));
        }

        return answer;
    }

    int mctFromLeafValues(vector& arr) {
        leaves = arr;
        n = leaves.size();
        memset(dp, -1, sizeof(dp));
        return solve(0, n);
    }
};

 

4-绝对值表达式的最大值-medium。数学

给你两个长度相等的整数数组,返回下面表达式的最大值:|arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|

其中下标 ij 满足 0 <= i, j < arr1.length

示例 1:

输入:arr1 = [1,2,3,4], arr2 = [-1,4,5,6]
输出:13

示例 2:

输入:arr1 = [1,-2,-5,0,10], arr2 = [0,-2,-1,-7,-4]
输出:20

这道题的关键点在于把要优化的求最大值的表达式拆解开来,拆解开就是对应4种情况,i>j。然后把i和j分别写一起,就可以看出,求的是i和j两部分的最大和

  • arr1[i] - arr1[j] + arr2[i] - arr2[j] + i - j
  • arr1[i] - arr1[j] - arr2[i] + arr2[j] + i - j
  • -arr1[i] + arr1[j] + arr2[i] - arr2[j] + i - j
  • -arr1[i] + arr1[j] - arr2[i] + arr2[j] + i - j
# 大神的解法1
class Solution:
    def maxAbsValExpr(self, arr1: List[int], arr2: List[int]) -> int:
        if not arr1 or not arr2:
            return 0
        m = len(arr1)
        n = len(arr2)
        assert m == n
        res = float('-inf')
        for sign1 in [-1, 1]:
            for sign2 in [-1, 1]:
                tmp = []
                for i in range(m):
                    tmp.append(arr1[i]*sign1 + arr2[i]*sign2 + i)
                res = max(res, max(tmp) - min(tmp))
        return res

# 大神的解法2
class Solution:
    def maxAbsValExpr(self, arr1: List[int], arr2: List[int]) -> int:
        if not arr1 or not arr2:
            return 0
        m = len(arr1)
        n = len(arr2)
        assert m == n
        res = float('-inf')
        best1 = best2 = best3 = best4 = float('-inf')
        for i in range(m):
            res = max(res, best1 + arr1[i] + arr2[i] + i)
            res = max(res, best2 + arr1[i] - arr2[i] + i)
            res = max(res, best3 - arr1[i] + arr2[i] + i)
            res = max(res, best4 - arr1[i] - arr2[i] + i)
            
            best1 = max(best1, -arr1[i] - arr2[i] - i)
            best2 = max(best2, -arr1[i] + arr2[i] - i)
            best3 = max(best3, arr1[i] - arr2[i] - i)
            best4 = max(best4, arr1[i] + arr2[i] - i)
        return res

 

你可能感兴趣的:(LeetCode周赛)