LeetCode Weekly Contest 196

5452. 判斷能否形成等差數列

給你一個數字數組 arr 。

如果一個數列中,任意相鄰兩項的差總等於同一個常數,那麼這個數列就稱爲 等差數列 。

如果可以重新排列數組形成等差數列,請返回 true ;否則,返回 false 。

示例 1:

輸入:arr = [3,5,1]
輸出:true
解釋:對數組重新排序得到 [1,3,5] 或者 [5,3,1] ,任意相鄰兩項的差分別爲 2 或 -2 ,可以形成等差數列。
示例 2:

輸入:arr = [1,2,4]
輸出:false
解釋:無法通過重新排序得到等差數列。

提示:

2 <= arr.length <= 1000
-10^6 <= arr[i] <= 10^6

思路

先排序,再計算兩兩元素之差。時間複雜度O(n)

代碼

class Solution {
    public boolean canMakeArithmeticProgression(int[] arr) {
        Arrays.sort(arr);
        int n = arr.length, i = 0, diff = arr[1] - arr[0];
        for (i=2; i<n; ++i) {
            if (arr[i] - arr[i-1] != diff) {
                return false;
            }
        }
        return true;
    }
}

5453. 所有螞蟻掉下來前的最後一刻

題目難度Medium
有一塊木板,長度爲 n 個 單位 。一些螞蟻在木板上移動,每隻螞蟻都以 每秒一個單位 的速度移動。其中,一部分螞蟻向 左 移動,其他螞蟻向 右 移動。

當兩隻向 不同 方向移動的螞蟻在某個點相遇時,它們會同時改變移動方向並繼續移動。假設更改方向不會花費任何額外時間。

而當螞蟻在某一時刻 t 到達木板的一端時,它立即從木板上掉下來。

給你一個整數 n 和兩個整數數組 left 以及 right 。兩個數組分別標識向左或者向右移動的螞蟻在 t = 0 時的位置。請你返回最後一隻螞蟻從木板上掉下來的時刻。

示例 1:
在這裏插入圖片描述
輸入:n = 4, left = [4,3], right = [0,1]
輸出:4
解釋:如上圖所示:
-下標 0 處的螞蟻命名爲 A 並向右移動。
-下標 1 處的螞蟻命名爲 B 並向右移動。
-下標 3 處的螞蟻命名爲 C 並向左移動。
-下標 4 處的螞蟻命名爲 D 並向左移動。
請注意,螞蟻在木板上的最後時刻是 t = 4 秒,之後螞蟻立即從木板上掉下來。(也就是說在 t = 4.0000000001 時,木板上沒有螞蟻)。
示例 2:
在這裏插入圖片描述輸入:n = 7, left = [], right = [0,1,2,3,4,5,6,7]
輸出:7
解釋:所有螞蟻都向右移動,下標爲 0 的螞蟻需要 7 秒才能從木板上掉落。
示例 3:
在這裏插入圖片描述
輸入:n = 7, left = [0,1,2,3,4,5,6,7], right = []
輸出:7
解釋:所有螞蟻都向左移動,下標爲 7 的螞蟻需要 7 秒才能從木板上掉落。
示例 4:

輸入:n = 9, left = [5], right = [4]
輸出:5
解釋:t = 1 秒時,兩隻螞蟻將回到初始位置,但移動方向與之前相反。
示例 5:

輸入:n = 6, left = [6], right = [0]
輸出:6

提示:

1 <= n <= 10^4
0 <= left.length <= n + 1
0 <= left[i] <= n
0 <= right.length <= n + 1
0 <= right[i] <= n
1 <= left.length + right.length <= n + 1
left 和 right 中的所有值都是唯一的,並且每個值 只能出現在二者之一 中。

思路

可以證明,無論中間有多少螞蟻,最左邊的向右走的螞蟻和最右邊的向左走的螞蟻走的路是恆定的。時間複雜度O(n)

代碼

class Solution {
    public int getLastMoment(int n, int[] left, int[] right) {
        int rightMostInLeft = -1, leftMostInRight = n + 1;
        for (int l: left) {
            rightMostInLeft = Math.max(l, rightMostInLeft);
        }
        for (int r: right) {
            leftMostInRight = Math.min(r, leftMostInRight);
        }
        if (rightMostInLeft == -1) {
            return n - leftMostInRight;
        }
        if (leftMostInRight == n + 1) {
            return rightMostInLeft;
        }
        return Math.max(n - leftMostInRight, rightMostInLeft);
    }
}

5454. 統計全 1 子矩形

題目難度Medium
給你一個只包含 0 和 1 的 rows * columns 矩陣 mat ,請你返回有多少個 子矩形 的元素全部都是 1 。

示例 1:

輸入:mat = [[1,0,1],
[1,1,0],
[1,1,0]]
輸出:13
解釋:
有 6 個 1x1 的矩形。
有 2 個 1x2 的矩形。
有 3 個 2x1 的矩形。
有 1 個 2x2 的矩形。
有 1 個 3x1 的矩形。
矩形數目總共 = 6 + 2 + 3 + 1 + 1 = 13 。
示例 2:

輸入:mat = [[0,1,1,0],
[0,1,1,1],
[1,1,1,0]]
輸出:24
解釋:
有 8 個 1x1 的子矩形。
有 5 個 1x2 的子矩形。
有 2 個 1x3 的子矩形。
有 4 個 2x1 的子矩形。
有 2 個 2x2 的子矩形。
有 2 個 3x1 的子矩形。
有 1 個 3x2 的子矩形。
矩形數目總共 = 8 + 5 + 2 + 4 + 2 + 2 + 1 = 24 。
示例 3:

輸入:mat = [[1,1,1,1,1,1]]
輸出:21
示例 4:

輸入:mat = [[1,0,1],[0,1,0],[1,0,1]]
輸出:5

提示:

1 <= rows <= 150
1 <= columns <= 150
0 <= mat[i][j] <= 1

思路

用前綴和計算(0, 0)到(i, j)之間矩形區域mat值之和。將判斷全1矩形轉化爲計算矩形區域的mat值是否等於矩形區域的面積,其中矩形區域的mat值用前綴和計算。時間複雜度O(n^2 * m^2).

代碼

class Solution {
    public int numSubmat(int[][] mat) {
        int m = mat.length, n = mat[0].length;
        int[][] corner = new int[m+1][n+1];
        int i = 0, j = 0, k = 0, l = 0, ans = 0;
        for (i=1; i<=m; ++i) {
            for (j=1; j<=n; ++j) {
                corner[i][j] = corner[i-1][j] + corner[i][j-1] - corner[i-1][j-1] + mat[i-1][j-1];
            }
        }
        for (i=0; i<m; ++i) {
            for (j=0; j<n; ++j) {
                for (k=i+1; k<=m; ++k) {
                    for (l=j+1; l<=n; ++l) {
                        if (corner[k][l] - corner[i][l] - corner[k][j] + corner[i][j] == (k-i) * (l - j)) {
                            // System.out.println(i + " " + j + " " + k + " " + l);
                            ++ans;
                        }
                    }
                }
            }
        }
        return ans;
    }
}

5455. 最多 K 次交換相鄰數位後得到的最小整數

題目難度Hard
給你一個字符串 num 和一個整數 k 。其中,num 表示一個很大的整數,字符串中的每個字符依次對應整數上的各個 數位 。

你可以交換這個整數相鄰數位的數字 最多 k 次。

請你返回你能得到的最小整數,並以字符串形式返回。

示例 1:
在這裏插入圖片描述
輸入:num = “4321”, k = 4
輸出:“1342”
解釋:4321 通過 4 次交換相鄰數位得到最小整數的步驟如上圖所示。
示例 2:

輸入:num = “100”, k = 1
輸出:“010”
解釋:輸出可以包含前導 0 ,但輸入保證不會有前導 0 。
示例 3:

輸入:num = “36789”, k = 1000
輸出:“36789”
解釋:不需要做任何交換。
示例 4:

輸入:num = “22”, k = 22
輸出:“22”
示例 5:

輸入:num = “9438957234785635408”, k = 23
輸出:“0345989723478563548”

提示:

1 <= num.length <= 30000
num 只包含 數字 且不含有 前導 0 。
1 <= k <= 10^9

思路

貪心。從首位置開始考慮每一個位置,每次找到該位置之後k個元素之內最小的元素,通個與前面的元素進行兩兩交換,把這個最小元素交換到當前位置,並維護k的值,減去已經用掉的交換次數。直到所有的交換次數用盡。

代碼

class Solution {
    private String swap(String str, int i, int j) {
        return str.substring(0, i) + str.charAt(j) + str.substring(i+1, j) + str.charAt(i) + str.substring(j+1);
    }
    
    private int findMin(String str, int left, int range) {
        char curMin = str.charAt(left);
        int minIdx = left;
        for (int i=1; i<=range; ++i) {
            if (str.charAt(left + i) < curMin) {
                curMin = str.charAt(left + i);
                minIdx = left + i;
            }
        }
        return minIdx;
    }
    
    public String minInteger(String num, int k) {
        int left = 0, n = num.length();
        while (k > 0 && left < n) {
            int range = Math.min(k, n - 1 - left);
            int minIdx = findMin(num, left, range);
            if (minIdx != left) {
                num = num.substring(0, left) + num.charAt(minIdx) + num.substring(left, minIdx) + num.substring(minIdx + 1);
            }
            k -= minIdx - left;
            ++left;
        }
        return num;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章