[leetCode]212场周赛

csdn:https://blog.csdn.net/renweiyi1487/article/details/109276885

题目一: 5546. 按键持续时间最长的键

链接:https://leetcode-cn.com/problems/slowest-key

LeetCode 设计了一款新式键盘,正在测试其可用性。测试人员将会点击一系列键(总计 n 个),每次一个。

给你一个长度为 n 的字符串 keysPressed ,其中 keysPressed[i] 表示测试序列中第 i 个被按下的键。releaseTimes 是一个升序排列的列表,其中 releaseTimes[i] 表示松开第 i 个键的时间。字符串和数组的 下标都从 0 开始 。第 0 个键在时间为 0 时被按下,接下来每个键都 恰好 在前一个键松开时被按下。

测试人员想要找出按键 持续时间最长 的键。第 i 次按键的持续时间为 releaseTimes[i] - releaseTimes[i - 1] ,第 0 次按键的持续时间为 releaseTimes[0]

注意,测试期间,同一个键可以在不同时刻被多次按下,而每次的持续时间都可能不同。

请返回按键 持续时间最长 的键,如果有多个这样的键,则返回 按字母顺序排列最大 的那个键。

一次遍历使用额外空间

class Solution {
    public char slowestKey(int[] releaseTimes, String keysPressed) {
        int n = releaseTimes.length;
        // 存储keysPressed[i]的持续时间
        int[] div = new int[n];
        div[0] = releaseTimes[0];
        for (int i = 1; i < n; i++) {
            div[i] = releaseTimes[i] - releaseTimes[i-1];
        }
        // 计算持续时间的最大值
        int max = div[0];
        // 记录最大值对应的下标
        int index = 0;
        for (int i = 1; i < n; i++) {
            if (div[i] > max) {
                max = div[i];
                index = i;
            } else if (div[i] == max) {
                if (keysPressed.charAt(i) > keysPressed.charAt(index)) 
                    index = i;
            }
        }
        return keysPressed.charAt(index);
    }
}

一次遍历不使用额外空间

class Solution {
    public char slowestKey(int[] releaseTimes, String keysPressed) {
        int n = releaseTimes.length;
        int max = releaseTimes[0];
        int index  = 0;
        for (int i = 1; i < n; i++) {
            int time = releaseTimes[i] - releaseTimes[i - 1];
            if (time > max) {
                max = time;
                index = i;
            } else if (time == max){
                if (keysPressed.charAt(i) > keysPressed.charAt(index))
                    index = i;
            }
        }
        return keysPressed.charAt(index);
    }
}

题目二:

链接: https://leetcode-cn.com/problems/arithmetic-subarrays/

如果一个数列由至少两个元素组成,且每两个连续元素之间的差值都相同,那么这个序列就是 等差数列 。更正式地,数列 s 是等差数列,只需要满足:对于每个有效的 is[i+1] - s[i] == s[1] - s[0] 都成立。

例如,下面这些都是 等差数列 :

1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9

下面的数列 不是等差数列 :

1, 1, 2, 5, 7

给你一个由 n 个整数组成的数组 nums,和两个由 m 个整数组成的数组 lr,后两个数组表示 m 组范围查询,其中第 i 个查询对应范围 [l[i], r[i]] 。所有数组的下标都是 从 0 开始 的。

返回 boolean 元素构成的答案列表 answer 。如果子数组 nums[l[i]], nums[l[i]+1], ... , nums[r[i]] 可以 重新排列 形成 等差数列 ,answer[i] 的值就是 true;否则answer[i] 的值就是 false

示例:
示例 1:

输入:nums = [4,6,5,9,3,7], l = [0,0,2], r = [2,3,5]
输出:[true,false,true]
解释:
第 0 个查询,对应子数组 [4,6,5] 。可以重新排列为等差数列 [6,5,4] 。
第 1 个查询,对应子数组 [4,6,5,9] 。无法重新排列形成等差数列。
第 2 个查询,对应子数组 [5,9,3,7] 。可以重新排列为等差数列 [3,5,7,9]。

示例 2:

输入:nums = [-12,-9,-3,-12,-6,15,20,-25,-20,-15,-10], l = [0,1,6,4,8,7], r = [4,4,9,7,9,10]
输出:[false,true,false,false,true,true]

暴力法

class Solution {
    public List<Boolean> checkArithmeticSubarrays(int[] nums, int[] l, int[] r) {
        int m = l.length;
        List<Boolean> ans = new ArrayList<>(); 
        for (int i = 0; i < m; i++) {
            int[] arr = copy(nums, l[i], r[i]);
            Arrays.sort(arr);
            ans.add(isEquArr(arr));
        }
        return ans;
    }
    
    private boolean isEquArr(int[] arr) {
        int n = arr.length;
        if (n <= 2) return true;
        int div = (arr[1] - arr[0]);
        for (int i = 1; i < arr.length; i++) {
            if ((arr[i] - arr[i-1]) != div) {
                return false;
            }
        }
        return true;
    }
    
    private int[] copy(int[] nums, int left, int right) {
        int[] ans = new int[right - left +1];
        for (int i = left; i <= right; i++) {
            ans[i - left] = nums[i];
        }
        return ans;
    }
}

题目三: 5548. 最小体力消耗路径

链接: https://leetcode-cn.com/problems/path-with-minimum-effort

你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。

一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。

请你返回从左上角走到右下角的最小 体力消耗值 。

示例:
在这里插入图片描述
输入:heights = [[1,2,2],[3,8,2],[5,3,5]]
输出:2
解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2 。
这条路径比路径 [1,2,2,2,5] 更优,因为另一条路劲差值最大值为 3 。

提示:

  • rows == heights.length
  • columns == heights[i].length
  • 1 <= rows, columns <= 100
  • 1 <= heights[i][j] <= 10^6

bfs + 二分查找

 由提示可知高度差的范围为[0, 99999],可以通过二分查找查找到达终点的所有路径中的最小体力,每选取一次mid通过能否能到达终点来调整最小体力值所在的范围。如果能达到终点说明选取的mid大了所以应该调整右指针,如果选取的mid到达不了终点说明选取的mid小了应该调整左指针。

class Solution {
    // 定义一个方向数组控制移动的方向
    int[][] directions = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    
    public int minimumEffortPath(int[][] heights) {
        // 地图的行数
        int rows = heights.length;
        // 地图的列数
        int cols = heights[0].length;
       
        // 定义范围用于二分查找注意循环不变量,[l,r] 高度差的范围为 [0, 999999]
        int l = 0, r = 999999;
        while (l <= r) {
            int mid = l + (r - l) / 2; // 防止溢出,这题不会出现,mid表示走这条路当前能提供的最小体力值
            
             // 定义一个辅助数组记录已经走过的格子
            boolean[][] seen = new boolean[rows][cols];
             // 队列,用于广度优先搜索
            Queue<int[]> queue = new LinkedList<>();
            queue.add(new int[]{0,0});
            seen[0][0] = true;
            while (!queue.isEmpty()) {
                int[] cur = queue.poll();
                int x = cur[0];
                int y = cur[1];
                for (int[] dir : directions) {
                    int nx = x + dir[0];
                    int ny = y + dir[1];
                    if (nx < 0 || nx >= rows || ny < 0 || ny >= cols || seen[nx][ny] == true)
                        continue;
                    // 下一个位置有效,则计算到下一个位置的所需体力值
                    // 走到下一步所需要的体力值,小于等于 能提供的最小体力值说明能继续走
                    if (Math.abs(heights[nx][ny] - heights[x][y]) <= mid) {
                        queue.add(new int[]{nx,ny});
                        seen[nx][ny] = true;
                    }
                }
            }
            // 走到了终点说明当前路径需要的最小体力值范围在[l,mid -1]
            if (seen[rows-1][cols - 1]) {
                r = mid - 1;
            } else { // 没有走到终点说明当前提供的最小体力不够,所以查找值应在[mid+1, r]
                l = mid + 1;
            }
        }
        return l;// 也可以是r+1;
    }
}

dfs + 二分查找

思路和bfs差不多,代码如下

class Solution {

    int[][] dirs = new int[][]{{1,0},{0,1},{-1,0},{0,-1}};
    int rows;
    int cols;
    public int minimumEffortPath(int[][] heights) {
        rows = heights.length;
        cols = heights[0].length;
        int l = 0, r = 999999;
        while (l <= r) {
            boolean[][] seen = new boolean[rows][cols];
            int mid = l + (r - l)/2;
            if (dfs(heights, 0, 0, mid, seen)) {
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        return l;
    }

    // 检测从(x,y)是否能到达终点
    private boolean dfs(int[][] heights, int x, int y, int mid , boolean[][] seen) {
        // 到达终点
        if (x == rows - 1 && y == cols - 1) {
            return true;
        }
        seen[x][y] = true;
        for (int[] dir : dirs) {
            int nx = x + dir[0];
            int ny = y + dir[1];
            if (nx < 0 || nx >= rows || ny < 0 || ny >= cols || seen[nx][ny] 
            || Math.abs(heights[x][y] - heights[nx][ny]) > mid)
                continue;
            if (dfs(heights, nx, ny, mid, seen)) {
                return true;
            }
        }
        return false;
    }
}

题目四: 5156. 矩阵转换后的秩

链接: https://leetcode-cn.com/problems/rank-transform-of-a-matrix/

待补坑。。。

posted @ 2020-10-25 19:42  消灭猕猴桃  阅读(118)  评论(0编辑  收藏  举报