【周賽】第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<int> 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<int>& 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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章