目錄
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|
其中下標 i
,j
滿足 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