LeetCode Weekly Contest 188

5404. 用棧操作構建數組

給你一個目標數組 target 和一個整數 n。每次迭代,需要從 list = {1,2,3…, n} 中依序讀取一個數字。

請使用下述操作來構建目標數組 target :

Push:從 list 中讀取一個新元素, 並將其推入數組中。
Pop:刪除數組中的最後一個元素。
如果目標數組構建完成,就停止讀取更多元素。
題目數據保證目標數組嚴格遞增,並且只包含 1 到 n 之間的數字。

請返回構建目標數組所用的操作序列。

題目數據保證答案是唯一的。

示例 1:

輸入:target = [1,3], n = 3
輸出:[“Push”,“Push”,“Pop”,“Push”]
解釋:
讀取 1 並自動推入數組 -> [1]
讀取 2 並自動推入數組,然後刪除它 -> [1]
讀取 3 並自動推入數組 -> [1,3]
示例 2:

輸入:target = [1,2,3], n = 3
輸出:[“Push”,“Push”,“Push”]
示例 3:

輸入:target = [1,2], n = 4
輸出:[“Push”,“Push”]
解釋:只需要讀取前 2 個數字就可以停止。
示例 4:

輸入:target = [2,3,4], n = 4
輸出:[“Push”,“Pop”,“Push”,“Push”,“Push”]

提示:

1 <= target.length <= 100
1 <= target[i] <= 100
1 <= n <= 100
target 是嚴格遞增的

思路

target的長度爲m, 則時間複雜度O(m)

代碼

class Solution {
    public List<String> buildArray(int[] target, int n) {
        ArrayList<String> ans = new ArrayList<>();
        int m = target.length, end = target[m-1], i = 1, j = 0;
        for (i=1; i<=end; ++i) {
            if (target[j] == i) {
                ans.add("Push");
                ++j;
            } else {
                ans.add("Push");
                ans.add("Pop");
            }
        }
        return ans;
    }
}

5405. 形成兩個異或相等數組的三元組數目

給你一個整數數組 arr 。

現需要從數組中取三個下標 i、j 和 k ,其中 (0 <= i < j <= k < arr.length) 。

a 和 b 定義如下:

a = arr[i] ^ arr[i + 1] ^ … ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ … ^ arr[k]
注意:^ 表示 按位異或 操作。

請返回能夠令 a == b 成立的三元組 (i, j , k) 的數目。

示例 1:

輸入:arr = [2,3,1,6,7]
輸出:4
解釋:滿足題意的三元組分別是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)
示例 2:

輸入:arr = [1,1,1,1,1]
輸出:10
示例 3:

輸入:arr = [2,3]
輸出:0
示例 4:

輸入:arr = [1,3,5,7,9]
輸出:3
示例 5:

輸入:arr = [7,11,12,9,5,2,7,17,22]
輸出:8

提示:

1 <= arr.length <= 300
1 <= arr[i] <= 10^8

思路

注意到若a = b,則a ^ b = 0,因此只要找到數組中連續若干個數,這些數的從左到右異或值爲0即可
arr長度爲n,則時間複雜度O(n^2).

代碼

class Solution {
    public int countTriplets(int[] arr) {
        int n = arr.length, i = 0, j = 0, xors = 0, ans = 0;
        for (i=0; i<n; ++i) {
            xors = 0;
            for (j=i; j>=0; --j) {
                xors = arr[j] ^ xors;
                // System.out.println(j + " " + i + ": " + xors);
                if (xors == 0) {
                    ans += i - j;
                }
            }
        }
        return ans;
    }
}

5406. 收集樹上所有蘋果的最少時間

給你一棵有 n 個節點的無向樹,節點編號爲 0 到 n-1 ,它們中有一些節點有蘋果。通過樹上的一條邊,需要花費 1 秒鐘。你從 節點 0 出發,請你返回最少需要多少秒,可以收集到所有蘋果,並回到節點 0 。

無向樹的邊由 edges 給出,其中 edges[i] = [fromi, toi] ,表示有一條邊連接 from 和 toi 。除此以外,還有一個布爾數組 hasApple ,其中 hasApple[i] = true 代表節點 i 有一個蘋果,否則,節點 i 沒有蘋果。

示例 1:
在這裏插入圖片描述

輸入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,true,true,false]
輸出:8
解釋:上圖展示了給定的樹,其中紅色節點表示有蘋果。一個能收集到所有蘋果的最優方案由綠色箭頭表示。
示例 2:
在這裏插入圖片描述

輸入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,false,true,false]
輸出:6
解釋:上圖展示了給定的樹,其中紅色節點表示有蘋果。一個能收集到所有蘋果的最優方案由綠色箭頭表示。
示例 3:

輸入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,false,false,false,false,false]
輸出:0

思路

遞歸。爲每個節點維護一個值,如果左孩子/右孩子的值大於0,則當前節點的值加上左孩子/右孩子的值+1,否則如果左孩子/右孩子有蘋果,則當前節點值加上1。遞歸之前先將邊列表edges轉化爲鄰接表adj,爲了防止重複訪問再使用一個數組vis記錄樹節點是否訪問過。
樹的節點個數爲n,時間複雜度爲O(n).

代碼

class Solution:
    def dfs(self, root, adj, hasApple, vis):
        vis[root] = True
        ans = 0
        for child in adj[root]:
            if not vis[child]:
                childVal = self.dfs(child, adj, hasApple, vis)
                if childVal > 0:
                    ans += childVal + 1
                elif hasApple[child]:
                    ans += 1
        # print('{}: {}'.format(root, ans))
        return ans
        
    
    def minTime(self, n: int, edges: List[List[int]], hasApple: List[bool]) -> int:
        adj = [list() for _ in range(n)]
        for edge in edges:
            adj[edge[0]].append(edge[1])
            adj[edge[1]].append(edge[0])
        vis = [False] * n
        return 2 * self.dfs(0, adj, hasApple, vis)

5407. 切披薩的方案數

給你一個 rows x cols 大小的矩形披薩和一個整數 k ,矩形包含兩種字符: ‘A’ (表示蘋果)和 ‘.’ (表示空白格子)。你需要切披薩 k-1 次,得到 k 塊披薩並送給別人。

切披薩的每一刀,先要選擇是向垂直還是水平方向切,再在矩形的邊界上選一個切的位置,將披薩一分爲二。如果垂直地切披薩,那麼需要把左邊的部分送給一個人,如果水平地切,那麼需要把上面的部分送給一個人。在切完最後一刀後,需要把剩下來的一塊送給最後一個人。

請你返回確保每一塊披薩包含 至少 一個蘋果的切披薩方案數。由於答案可能是個很大的數字,請你返回它對 10^9 + 7 取餘的結果。

示例 1:
在這裏插入圖片描述

輸入:pizza = [“A…”,“AAA”,"…"], k = 3
輸出:3
解釋:上圖展示了三種切披薩的方案。注意每一塊披薩都至少包含一個蘋果。
示例 2:

輸入:pizza = [“A…”,“AA.”,"…"], k = 3
輸出:1
示例 3:

輸入:pizza = [“A…”,“A…”,"…"], k = 1
輸出:1

提示:

1 <= rows, cols <= 50
rows == pizza.length
cols == pizza[i].length
1 <= k <= 10
pizza 只包含字符 ‘A’ 和 ‘.’ 。

思路

動態規劃。dp[row-1][col-1][cut-1]表示pizza右下角的row * col範圍分成cut份的方案數。
除了動態規劃以外,一個核心點是判斷左上頂點爲(lx, ly),右下頂點爲(rx, ry)的區域內是否有蘋果,方法是計算從左上角開始的前綴和preSum[row][col]表示pizza的左上角的row * col範圍內的蘋果數量,如此可以將"區域存在蘋果判斷"的時間複雜度降至O(mn)(假設行數爲m,列數爲n,份數爲k).
總的時間複雜度是動態規劃的時間複雜度,爲O(mnk(m+n)).

代碼

class Solution {
    private static final int mod = 1000000007;
    
    private boolean containsApple(int lx, int ly, int rx, int ry, int[][] preSum) {
        return preSum[rx+1][ry+1] + preSum[lx][ly] - preSum[lx][ry+1] - preSum[rx+1][ly] > 0? true: false;
    }
    
    public int ways(String[] pizza, int k) {
        int m = pizza.length, n = pizza[0].length(), i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, cut = 0;
        boolean[][][][] containsApple = new boolean[m][n][m][n];
        int[][] preSum = new int[m+1][n+1];         // prefix sum from left-top
        int[][][] dp = new int[m][n][k];            // dp from right-button
        for (i1=1; i1<=m; ++i1) {
            for (i2=1; i2<=n; ++i2) {
                preSum[i1][i2] = preSum[i1-1][i2] + preSum[i1][i2-1] - preSum[i1-1][i2-1] + (pizza[i1-1].charAt(i2-1) == 'A'? 1: 0);
            }
        }
        for (i1=0; i1<m; ++i1) {
            for (i2=0; i2<n; ++i2) {
                dp[i1][i2][0] = containsApple(m-1-i1, n-1-i2, m-1, n-1, preSum)? 1: 0;
                for (i3=1; i3<k; ++i3) {
                    for (cut=0; cut<i1; ++cut) {
                        if (containsApple(m-1-i1, n-1-i2, m-1-i1+cut, n-1, preSum)) {
                            dp[i1][i2][i3] = (dp[i1][i2][i3] + dp[i1-cut-1][i2][i3-1]) % mod;
                        }
                    }
                    for (cut=0; cut<i2; ++cut) {
                        if (containsApple(m-1-i1, n-1-i2, m-1, n-1-i2+cut, preSum)) {
                            dp[i1][i2][i3] = (dp[i1][i2][i3] + dp[i1][i2-cut-1][i3-1]) % mod;
                        }
                    }
                }
            }
        }
        return dp[m-1][n-1][k-1];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章