天天看點

LeetCode Weekly Contest 1915424. 數組中兩元素的最大乘積5425. 切割後面積最大的蛋糕5426. 重新規劃路線5427. 兩個盒子中球的顔色數相同的機率

5424. 數組中兩元素的最大乘積

給你一個整數數組 nums,請你選擇數組的兩個不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值。

請你計算并傳回該式的最大值。

示例 1:

輸入:nums = [3,4,5,2]

輸出:12

解釋:如果選擇下标 i=1 和 j=2(下标從 0 開始),則可以獲得最大值,(nums[1]-1)(nums[2]-1) = (4-1)(5-1) = 3*4 = 12 。

示例 2:

輸入:nums = [1,5,4,5]

輸出:16

解釋:選擇下标 i=1 和 j=3(下标從 0 開始),則可以獲得最大值 (5-1)*(5-1) = 16 。

示例 3:

輸入:nums = [3,7]

輸出:12

提示:

2 <= nums.length <= 500

1 <= nums[i] <= 10^3

代碼

class Solution {
    public int maxProduct(int[] nums) {
        int i = 0, topidx = 0, secidx = 0, n = nums.length, topmax = 0, secmax = 0;
        for (i=0; i<n; ++i) {
            if (nums[i] > topmax) {
                topidx = i;
                topmax = nums[i];
            }
        }
        for (i=0; i<n; ++i) {
            if (i == topidx) {
                continue;
            }
            if (nums[i] > secmax) {
                secidx = i;
                secmax = nums[i];
            }
        }
        return (topmax - 1) * (secmax - 1);
    }
}
           

5425. 切割後面積最大的蛋糕

矩形蛋糕的高度為 h 且寬度為 w,給你兩個整數數組 horizontalCuts 和 verticalCuts,其中 horizontalCuts[i] 是從矩形蛋糕頂部到第 i 個水準切口的距離,類似地, verticalCuts[j] 是從矩形蛋糕的左側到第 j 個豎直切口的距離。

請你按數組 horizontalCuts 和 verticalCuts 中提供的水準和豎直位置切割後,請你找出 面積最大 的那份蛋糕,并傳回其 面積 。由于答案可能是一個很大的數字,是以需要将結果對 10^9 + 7 取餘後傳回。

示例 1:

LeetCode Weekly Contest 1915424. 數組中兩元素的最大乘積5425. 切割後面積最大的蛋糕5426. 重新規劃路線5427. 兩個盒子中球的顔色數相同的機率

輸入:h = 5, w = 4, horizontalCuts = [1,2,4], verticalCuts = [1,3]

輸出:4

解釋:上圖所示的矩陣蛋糕中,紅色線表示水準和豎直方向上的切口。切割蛋糕後,綠色的那份蛋糕面積最大。

示例 2:

LeetCode Weekly Contest 1915424. 數組中兩元素的最大乘積5425. 切割後面積最大的蛋糕5426. 重新規劃路線5427. 兩個盒子中球的顔色數相同的機率

輸入:h = 5, w = 4, horizontalCuts = [3,1], verticalCuts = [1]

輸出:6

解釋:上圖所示的矩陣蛋糕中,紅色線表示水準和豎直方向上的切口。切割蛋糕後,綠色和黃色的兩份蛋糕面積最大。

示例 3:

輸入:h = 5, w = 4, horizontalCuts = [3], verticalCuts = [3]

輸出:9

提示:

2 <= h, w <= 10^9

1 <= horizontalCuts.length < min(h, 10^5)

1 <= verticalCuts.length < min(w, 10^5)

1 <= horizontalCuts[i] < h

1 <= verticalCuts[i] < w

題目資料保證 horizontalCuts 中的所有元素各不相同

題目資料保證 verticalCuts 中的所有元素各不相同

代碼

class Solution {
    private static final long mod = 1000000007L;
    
    public int maxArea(int h, int w, int[] horizontalCuts, int[] verticalCuts) {
        Arrays.sort(horizontalCuts);
        Arrays.sort(verticalCuts);
        int hmax = 0, vmax = 0, i = 0, hn = horizontalCuts.length, vn = verticalCuts.length;
        for (i=0; i<hn; ++i) {
            if (i == 0) {
                hmax = Math.max(hmax, horizontalCuts[0]);
            } else {
                hmax = Math.max(hmax, horizontalCuts[i] - horizontalCuts[i-1]);
            }
        }
        hmax = Math.max(hmax, h - horizontalCuts[hn-1]);
        for (i=0; i<vn; ++i) {
            if (i == 0) {
                vmax = Math.max(vmax, verticalCuts[0]);
            } else {
                vmax = Math.max(vmax, verticalCuts[i] - verticalCuts[i-1]);
            }
        }
        vmax = Math.max(vmax, w - verticalCuts[vn-1]);
        // System.out.println(hmax);
        // System.out.println(vmax);
        return (int) (((long)hmax) * ((long)vmax) % mod);
    }
}
           

5426. 重新規劃路線

n 座城市,從 0 到 n-1 編号,其間共有 n-1 條路線。是以,要想在兩座不同城市之間旅行隻有唯一一條路線可供選擇(路線網形成一顆樹)。去年,交通運輸部決定重新規劃路線,以改變交通擁堵的狀況。

路線用 connections 表示,其中 connections[i] = [a, b] 表示從城市 a 到 b 的一條有向路線。

今年,城市 0 将會舉辦一場大型比賽,很多遊客都想前往城市 0 。

請你幫助重新規劃路線方向,使每個城市都可以通路城市 0 。傳回需要變更方向的最小路線數。

題目資料 保證 每個城市在重新規劃路線方向後都能到達城市 0 。

示例 1:

LeetCode Weekly Contest 1915424. 數組中兩元素的最大乘積5425. 切割後面積最大的蛋糕5426. 重新規劃路線5427. 兩個盒子中球的顔色數相同的機率

輸入:n = 6, connections = [[0,1],[1,3],[2,3],[4,0],[4,5]]

輸出:3

解釋:更改以紅色顯示的路線的方向,使每個城市都可以到達城市 0 。

示例 2:

LeetCode Weekly Contest 1915424. 數組中兩元素的最大乘積5425. 切割後面積最大的蛋糕5426. 重新規劃路線5427. 兩個盒子中球的顔色數相同的機率

輸入:n = 5, connections = [[1,0],[1,2],[3,2],[3,4]]

輸出:2

解釋:更改以紅色顯示的路線的方向,使每個城市都可以到達城市 0 。

示例 3:

輸入:n = 3, connections = [[1,0],[2,0]]

輸出:0

提示:

2 <= n <= 5 * 10^4

connections.length == n-1

connections[i].length == 2

0 <= connections[i][0], connections[i][1] <= n-1

connections[i][0] != connections[i][1]

思路

遞歸。從0開始周遊,周遊到反向的路徑就更改方向。注意不要重複通路節點

代碼

class Solution:
    def dfs(self, adj, vis, root):
        vis[root] = True
        for tup in adj[root]:
            if vis[tup[0]]:
                continue
            if not tup[1]:
                self.ans += 1
            self.dfs(adj, vis, tup[0])
    
    def minReorder(self, n: int, connections: List[List[int]]) -> int:
        adj = [list() for _ in range(n)]
        for edge in connections:
            adj[edge[0]].append((edge[1], False))
            adj[edge[1]].append((edge[0], True))
        self.ans = 0
        vis = [False] * n
        self.dfs(adj, vis, 0)
        return self.ans
           

5427. 兩個盒子中球的顔色數相同的機率

桌面上有 2n 個顔色不完全相同的球,球上的顔色共有 k 種。給你一個大小為 k 的整數數組 balls ,其中 balls[i] 是顔色為 i 的球的數量。

所有的球都已經 随機打亂順序 ,前 n 個球放入第一個盒子,後 n 個球放入另一個盒子(請認真閱讀示例 2 的解釋部分)。

注意:這兩個盒子是不同的。例如,兩個球顔色分别為 a 和 b,盒子分别為 [] 和 (),那麼 [a] (b) 和 [b] (a) 這兩種配置設定方式是不同的(請認真閱讀示例 1 的解釋部分)。

請計算「兩個盒子中球的顔色數相同」的情況的機率。

示例 1:

輸入:balls = [1,1]

輸出:1.00000

解釋:球平均配置設定的方式隻有兩種:

  • 顔色為 1 的球放入第一個盒子,顔色為 2 的球放入第二個盒子
  • 顔色為 2 的球放入第一個盒子,顔色為 1 的球放入第二個盒子

    這兩種配置設定,兩個盒子中球的顔色數都相同。是以機率為 2/2 = 1 。

    示例 2:

輸入:balls = [2,1,1]

輸出:0.66667

解釋:球的清單為 [1, 1, 2, 3]

随機打亂,得到 12 種等機率的不同打亂方案,每種方案機率為 1/12 :

[1,1 / 2,3], [1,1 / 3,2], [1,2 / 1,3], [1,2 / 3,1], [1,3 / 1,2], [1,3 / 2,1], [2,1 / 1,3], [2,1 / 3,1], [2,3 / 1,1], [3,1 / 1,2], [3,1 / 2,1], [3,2 / 1,1]

然後,我們将前兩個球放入第一個盒子,後兩個球放入第二個盒子。

這 12 種可能的随機打亂方式中的 8 種滿足「兩個盒子中球的顔色數相同」。

機率 = 8/12 = 0.66667

示例 3:

輸入:balls = [1,2,1,2]

輸出:0.60000

解釋:球的清單為 [1, 2, 2, 3, 4, 4]。要想顯示所有 180 種随機打亂方案是很難的,但隻檢查「兩個盒子中球的顔色數相同」的 108 種情況是比較容易的。

機率 = 108 / 180 = 0.6 。

示例 4:

輸入:balls = [3,2,1]

輸出:0.30000

解釋:球的清單為 [1, 1, 1, 2, 2, 3]。要想顯示所有 60 種随機打亂方案是很難的,但隻檢查「兩個盒子中球的顔色數相同」的 18 種情況是比較容易的。

機率 = 18 / 60 = 0.3 。

示例 5:

輸入:balls = [6,6,6,6,6,6]

輸出:0.90327

提示:

1 <= balls.length <= 8

1 <= balls[i] <= 6

sum(balls) 是偶數

答案與真實值誤差在 10^-5 以内,則被視為正确答案

思路

排列組合求總的組合數:A(2n, 2n) / Pi(A(a[i], a[i])

dfs求符合條件的組合數(看到題解裡的大佬用動态規劃求解符合條件的組合數的,用動态規劃可以降低時間複雜度,具體可以移步LeetCode讨論區)

代碼

class Solution:
    def fact(self, n):
        ans = 1
        for i in range(2, n+1):
            ans *= i
        return ans

    def numPermutations(self, arr):
        n = sum(arr)
        parent = 1
        for num in arr:
            parent *= self.fact(num)
        return self.fact(n) / parent

    def dfs(self, arr, arr1, arr2, idx):
        half = sum(arr) / 2
        if sum(arr1) > half or sum(arr2) > half:        # pruning
            return
        if idx == len(arr):
            cnt = 0
            for num in arr1:
                cnt += num > 0
            for num in arr2:
                cnt -= num > 0
            if cnt == 0:
                self.ans += self.numPermutations(arr1) * self.numPermutations(arr2)
            return
        for num in range(arr[idx] + 1):
            arr1.append(num)
            arr2.append(arr[idx] - num)
            self.dfs(arr, arr1, arr2, idx + 1)
            arr1.pop()
            arr2.pop()

    def getProbability(self, balls: List[int]) -> float:
        self.ans = 0
        self.dfs(balls, list(), list(), 0)
        return self.ans / self.numPermutations(balls)