LeetCode 334周赛


6369. 左右元素和的差值

给你一个下标从 0 开始的整数数组 nums ,请你找出一个下标从 0 开始的整数数组 answer ,其中:

answer.length == nums.length
answer[i] = |leftSum[i] - rightSum[i]|
其中:

leftSum[i] 是数组 nums 中下标 i 左侧元素之和。如果不存在对应的元素,leftSum[i] = 0 。
rightSum[i] 是数组 nums 中下标 i 右侧元素之和。如果不存在对应的元素,rightSum[i] = 0 。
返回数组 answer 。

示例 1:

输入:nums = [10,4,8,3]
输出:[15,1,11,22]
解释:数组 leftSum 为 [0,10,14,22] 且数组 rightSum 为 [15,11,3,0] 。
数组 answer 为 [|0 - 15|,|10 - 11|,|14 - 3|,|22 - 0|] = [15,1,11,22] 。
示例 2:

输入:nums = [1]
输出:[0]
解释:数组 leftSum 为 [0] 且数组 rightSum 为 [0] 。
数组 answer 为 [|0 - 0|] = [0] 。
 
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 10^5

解答:分别统计左右两边的前缀和

class Solution {
    public int[] leftRigthDifference(int[] nums) {
        int n=nums.length;
        int[] left=new int[n];
        int[] right=new int[n];
        for(int i=1;i<n;i++){
            left[i]+=left[i-1]+nums[i-1];
        }
        for (int i = n-2; i >=0 ; i--) {
            right[i]+=right[i+1]+nums[i+1];
        }
        int[] res=new int[n];
        for (int i = 0; i < n; i++) {
            res[i]=Math.abs(left[i]-right[i]);
        }
        return res;
    }
}

6368. 找出字符串的可整除数组

给你一个下标从 0 开始的字符串 word ,长度为 n ,由从 09 的数字组成。另给你一个正整数 m 。

word 的 可整除数组 div  是一个长度为 n 的整数数组,并满足:

如果 word[0,...,i] 所表示的 数值 能被 m 整除,div[i] = 1
否则,div[i] = 0
返回 word 的可整除数组。

示例 1:

输入:word = "998244353", m = 3
输出:[1,1,0,0,0,1,1,0,0]
解释:仅有 4 个前缀可以被 3 整除:"9""99""998244""9982443" 。
示例 2:

输入:word = "1010", m = 10
输出:[0,1,0,1]
解释:仅有 2 个前缀可以被 10 整除:"10""1010" 。
 

提示:

1 <= n <= 10^5
word.length == n
word 由数字 09 组成
1 <= m <= 10^9

解答:每次都对m取模

class Solution {
    public int[] divisibilityArray(String word, int m) {
        int n=word.length();
        int[] res=new int[n];
        long sum=0;
        for(int i=0;i<n;i++){
            int num=word.charAt(i)-'0';
            sum=num+sum*10;
            //能整除,直接置sum为0
            if(sum%m==0){
                res[i]++;
                sum=0;
            }
            //不能整除,直接对m取模运算
            else{
                sum=sum%m;
            }
        }
        return res;
    }
}

6367. 求出最多标记下标

给你一个下标从 0 开始的整数数组 nums 。
一开始,所有下标都没有被标记。你可以执行以下操作任意次:
选择两个 互不相同且未标记 的下标 i 和 j ,满足 2 * nums[i] <= nums[j] ,标记下标 i 和 j 。
请你执行上述操作任意次,返回 nums 中最多可以标记的下标数目。

示例 1:

输入:nums = [3,5,2,4]
输出:2
解释:第一次操作中,选择 i = 2 和 j = 1 ,操作可以执行的原因是 2 * nums[2] <= nums[1] ,标记下标 21 。
没有其他更多可执行的操作,所以答案为 2 。
示例 2:

输入:nums = [9,2,5,4]
输出:4
解释:第一次操作中,选择 i = 3 和 j = 0 ,操作可以执行的原因是 2 * nums[3] <= nums[0] ,标记下标 30 。
第二次操作中,选择 i = 1 和 j = 2 ,操作可以执行的原因是 2 * nums[1] <= nums[2] ,标记下标 12 。
没有其他更多可执行的操作,所以答案为 4 。
示例 3:

输入:nums = [7,6,8]
输出:0
解释:没有任何可以执行的操作,所以答案为 0 。
 

提示:

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

解答:贪心,直接排序取中心下标,然后双指针遍历数据统计

class Solution {
    public int maxNumOfMarkedIndices(int[] nums) {
        int n=nums.length;
        Arrays.sort(nums);
        int res=0;
        int index=(n-1)/2,r=n-1;
        Set<Integer> set=new HashSet<>();
        while(index>=0&&r>=0){
            while(set.contains(r)){
                r--;
            }
            if(nums[index]*2<=nums[r]){
                set.add(index);
                r--;
                index--;
                res+=2;
            }
            else if(nums[index]*2>nums[r]){
                index--;
            }
        }
        return res;
    }
}

6366. 在网格图中访问一个格子的最少时间

给你一个 m x n 的矩阵 grid ,每个元素都为 非负 整数,其中 grid[row][col] 表示可以访问格子 (row, col) 的 最早 时间。也就是说当你访问格子 (row, col) 时,最少已经经过的时间为 grid[row][col] 。

你从 最左上角 出发,出发时刻为 0 ,你必须一直移动到上下左右相邻四个格子中的 任意 一个格子(即不能停留在格子上)。每次移动都需要花费 1 单位时间。

请你返回 最早 到达右下角格子的时间,如果你无法到达右下角的格子,请你返回 -1 。

示例 1:
输入:grid = [[0,1,3,2],[5,1,2,5],[4,3,8,6]]
输出:7
解释:一条可行的路径为:
- 时刻 t = 0 ,我们在格子 (0,0) 。
- 时刻 t = 1 ,我们移动到格子 (0,1) ,可以移动的原因是 grid[0][1] <= 1 。
- 时刻 t = 2 ,我们移动到格子 (1,1) ,可以移动的原因是 grid[1][1] <= 2 。
- 时刻 t = 3 ,我们移动到格子 (1,2) ,可以移动的原因是 grid[1][2] <= 3 。
- 时刻 t = 4 ,我们移动到格子 (1,1) ,可以移动的原因是 grid[1][1] <= 4 。
- 时刻 t = 5 ,我们移动到格子 (1,2) ,可以移动的原因是 grid[1][2] <= 5 。
- 时刻 t = 6 ,我们移动到格子 (1,3) ,可以移动的原因是 grid[1][3] <= 6 。
- 时刻 t = 7 ,我们移动到格子 (2,3) ,可以移动的原因是 grid[2][3] <= 7 。
最终到达时刻为 7 。这是最早可以到达的时间。

示例 2:
输入:grid = [[0,2,4],[3,2,1],[1,0,4]]
输出:-1
解释:没法从左上角按题目规定走到右下角。
 

提示:
m == grid.length
n == grid[i].length
2 <= m, n <= 1000
4 <= m * n <= 10^5
0 <= grid[i][j] <= 10^5
grid[0][0] == 0

解答:BFS+优先队列+最短路,因为能来回走所有到达一个位置的时间应该与该坐标同奇偶

class Solution {
    int m,n;
    int[] dx={0,1,0,-1};
    int[] dy={1,0,-1,0};
    public int minimumTime(int[][] grid) {
        m=grid.length;n=grid[0].length;
        //刚开始两个位置都无法到达直接返回-1
        if(grid[0][1]>1&&grid[1][0]>1)return -1; 
        Queue<int[]> q=new PriorityQueue<>((a,b)->a[2]-b[2]);
        int[][] d=new int[m][n];
        for(int[] a:d)Arrays.fill(a,Integer.MAX_VALUE);        
        q.offer(new int[]{0,0,0});
        int res=Integer.MAX_VALUE;
        while(true){
                int[] tmp=q.poll();
                int i=tmp[0],j=tmp[1],c=tmp[2];
                if(tmp[0]==m-1&&tmp[1]==n-1)return c;
                //枚举上下左右四个方向
                for(int k=0;k<4;k++){
                    int x=i+dx[k],y=j+dy[k];
                    if(x<0||x>=m||y<0||y>=n)continue;
                    int curd=Math.max(c+1,grid[x][y]);
                    curd+=(curd-x-y)%2;//curd和x+y同奇偶
                    if(curd<d[x][y]){
                        d[x][y]=curd;//更新最短路
                        q.offer(new int[]{x,y,curd});   
                    }
            }   
        }
    }
}

  目录