[leetCode]212場周賽
csdn:https://blog.csdn.net/renweiyi1487/article/details/109276885
題目一: 5546. 按鍵持續時間最長的鍵
LeetCode 設計了一款新式鍵盤,正在測試其可用性。測試人員將會點選一系列鍵(總計 n
個),每次一個。
給你一個長度為 n 的字串 keysPressed
,其中 keysPressed[i]
表示測試序列中第 i 個被按下的鍵。releaseTimes
是一個升序排列的列表,其中 releaseTimes[i]
表示鬆開第 i 個鍵的時間。字串和陣列的 下標都從 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); } }
題目二:
如果一個數列由至少兩個元素組成,且每兩個連續元素之間的差值都相同,那麼這個序列就是 等差數列 。更正式地,數列 s
是等差數列,只需要滿足:對於每個有效的 i
, s[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
個整陣列成的陣列 l
和 r
,後兩個陣列表示 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/
待補坑。。。