LeetCode第 34 场双周赛

5491. 矩阵对角线元素的和

给你一个正方形矩阵 mat,请你返回矩阵对角线元素的和。

请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。

示例 1:
LeetCode第 34 场双周赛_第1张图片

输入:mat = [[1,2,3],
[4,5,6],
[7,8,9]]
输出:25
解释:对角线的和为:1 + 5 + 9 + 3 + 7 = 25
请注意,元素 mat[1][1] = 5 只会被计算一次。
示例 2:

输入:mat = [[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]]
输出:8
示例 3:

输入:mat = [[5]]
输出:5

提示:

n == mat.length == mat[i].length
1 <= n <= 100
1 <= mat[i][j] <= 100

代码

class Solution {
     
    public int diagonalSum(int[][] mat) {
     
        int n = mat.length, ret = 0;
        for (int i=0; i<n; ++i) {
     
            int j = n - 1 - i;
            ret += mat[i][i];
            if (i != j) {
     
                ret += mat[i][j];
            }
        }
        return ret;
    }
}

5492. 分割字符串的方案数

给你一个二进制串 s (一个只包含 0 和 1 的字符串),我们可以将 s 分割成 3 个 非空 字符串 s1, s2, s3 (s1 + s2 + s3 = s)。

请你返回分割 s 的方案数,满足 s1,s2 和 s3 中字符 ‘1’ 的数目相同。

由于答案可能很大,请将它对 10^9 + 7 取余后返回。

示例 1:

输入:s = “10101”
输出:4
解释:总共有 4 种方法将 s 分割成含有 ‘1’ 数目相同的三个子字符串。
“1|010|1”
“1|01|01”
“10|10|1”
“10|1|01”
示例 2:

输入:s = “1001”
输出:0
示例 3:

输入:s = “0000”
输出:3
解释:总共有 3 种分割 s 的方法。
“0|0|00”
“0|00|0”
“00|0|0”
示例 4:

输入:s = “100100010100110”
输出:12

提示:

s[i] == ‘0’ 或者 s[i] == ‘1’
3 <= s.length <= 10^5

思路

统计两个分割之间的0的个数。注意所有字符均为’0’的特殊情况。

代码

class Solution {
     
    private static final long mod = 1000000007;
    
    public int numWays(String s) {
     
        int cnt = 0;
        for (char ch: s.toCharArray()) {
     
            if (ch == '1') {
     
                ++cnt;
            }
        }
        if (cnt % 3 != 0) {
     
            return 0;
        }
        if (cnt == 0) {
     
            long sn = (long)s.length();
            long ret = (sn - 1) * (sn - 2) / 2;
            return (int) (ret % mod);
        }
        int unit = cnt / 3, cnt1 = 0, cnt2 = 0, cur1 = 0;
        for (char ch: s.toCharArray()) {
     
            if (ch == '1') {
     
                ++cur1;
            } else if (cur1 == unit) {
     
                ++cnt1;
            } else if (cur1 == 2*unit) {
     
                ++cnt2;
            }
        }
        long ret = ((long)(cnt1 + 1)) * ((long)(cnt2 + 1));
        return (int) (ret % mod);
    }
}

5493. 删除最短的子数组使剩余数组有序

给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。

一个子数组指的是原数组中连续的一个子序列。

请你返回满足题目要求的最短子数组的长度。

示例 1:

输入:arr = [1,2,3,10,4,2,3,5]
输出:3
解释:我们需要删除的最短子数组是 [10,4,2] ,长度为 3 。剩余元素形成非递减数组 [1,2,3,3,5] 。
另一个正确的解为删除子数组 [3,10,4] 。
示例 2:

输入:arr = [5,4,3,2,1]
输出:4
解释:由于数组是严格递减的,我们只能保留一个元素。所以我们需要删除长度为 4 的子数组,要么删除 [5,4,3,2],要么删除 [4,3,2,1]。
示例 3:

输入:arr = [1,2,3]
输出:0
解释:数组已经是非递减的了,我们不需要删除任何元素。
示例 4:

输入:arr = [1]
输出:0

提示:

1 <= arr.length <= 10^5
0 <= arr[i] <= 10^9

思路

第一遍遍历,找到第一个不满足非递减的起始位置start和最后一个不满足非递减的终止位置end.
第二遍遍历,从start往前找找到第一个小于等于end位置的值的位置left.
第三遍遍历,从end往后找找到第一个大于等于start位置的值的位置right.
可以选择删去leftend之间,或者删去startright之间,取删去较少者。
注意数组原本已经非递减的特判。

代码

class Solution {
     
    public int findLengthOfShortestSubarray(int[] arr) {
     
        int n = arr.length, left = 0, right = n-1, start = n-1, end = 0;
        if (n == 1) {
     
            return 0;
        }
        while (left < n-1) {
     
            if (arr[left] <= arr[left + 1]) {
     
                ++left;
            } else {
     
                start = left;
                break;
            }
        }
        if (start == n-1) {
     
            return 0;
        }
        while (right > 0) {
     
            if (arr[right] >= arr[right - 1]) {
     
                --right;
            } else {
     
                end = right;
                break;
            }
        }
        left = start;
        end = right;
        while (left >= 0 && arr[left] > arr[end]) {
     
            --left;
        }
        while (right < n && arr[start] > arr[right]) {
     
            ++right;
        }
        return Math.min(end - left - 1, right - start - 1);
    }
}

5494. 统计所有可行路径

给你一个 互不相同 的整数数组,其中 locations[i] 表示第 i 个城市的位置。同时给你 start,finish 和 fuel 分别表示出发城市、目的地城市和你初始拥有的汽油总量

每一步中,如果你在城市 i ,你可以选择任意一个城市 j ,满足 j != i 且 0 <= j < locations.length ,并移动到城市 j 。从城市 i 移动到 j 消耗的汽油量为 |locations[i] - locations[j]|,|x| 表示 x 的绝对值。

请注意, fuel 任何时刻都 不能 为负,且你 可以 经过任意城市超过一次(包括 start 和 finish )。

请你返回从 start 到 finish 所有可能路径的数目。

由于答案可能很大, 请将它对 10^9 + 7 取余后返回。

示例 1:

输入:locations = [2,3,6,8,4], start = 1, finish = 3, fuel = 5
输出:4
解释:以下为所有可能路径,每一条都用了 5 单位的汽油:
1 -> 3
1 -> 2 -> 3
1 -> 4 -> 3
1 -> 4 -> 2 -> 3
示例 2:

输入:locations = [4,3,1], start = 1, finish = 0, fuel = 6
输出:5
解释:以下为所有可能的路径:
1 -> 0,使用汽油量为 fuel = 1
1 -> 2 -> 0,使用汽油量为 fuel = 5
1 -> 2 -> 1 -> 0,使用汽油量为 fuel = 5
1 -> 0 -> 1 -> 0,使用汽油量为 fuel = 3
1 -> 0 -> 1 -> 0 -> 1 -> 0,使用汽油量为 fuel = 5
示例 3:

输入:locations = [5,2,1], start = 0, finish = 2, fuel = 3
输出:0
解释:没有办法只用 3 单位的汽油从 0 到达 2 。因为最短路径需要 4 单位的汽油。
示例 4 :

输入:locations = [2,1,5], start = 0, finish = 0, fuel = 3
输出:2
解释:总共有两条可行路径,0 和 0 -> 1 -> 0 。
示例 5:

输入:locations = [1,2,3], start = 0, finish = 2, fuel = 40
输出:615088286
解释:路径总数为 2615088300 。将结果对 10^9 + 7 取余,得到 615088286 。

提示:

2 <= locations.length <= 100
1 <= locations[i] <= 10^9
所有 locations 中的整数 互不相同 。
0 <= start, finish < locations.length
1 <= fuel <= 200

思路

记忆化搜索,dp[i][j]表示从i位置出发时汽油量为j可以达到finish位置的路径的数量

代码

class Solution {
     
    private static final int mod = 1000000007;
    
    private int dfs(int[] locations, int n, int finish, int loc, int fuel, int[][] dp) {
     
        if (dp[loc][fuel] != -1) {
     
            return dp[loc][fuel];
        }
        dp[loc][fuel] = loc == finish? 1: 0;
        for (int i=0; i<n; ++i) {
     
            int remain = fuel - Math.abs(locations[loc] - locations[i]);
            if (i != loc && remain >= 0) {
     
                dp[loc][fuel] = (dp[loc][fuel] + dfs(locations, n, finish, i, remain, dp)) % mod;
            }
        }
        return dp[loc][fuel];
    }
    
    public int countRoutes(int[] locations, int start, int finish, int fuel) {
     
        int n = locations.length;
        int[][] dp = new int[n][fuel + 1];
        for (int i=0; i<n; ++i) {
     
            Arrays.fill(dp[i], -1);
        }
        dp[finish][0] = 1;
        dfs(locations, n, finish, start, fuel, dp);
        return dp[start][fuel];
    }
}

你可能感兴趣的:(LeetCode,LeetCode,双周赛)