5400. 旅行終點站
給你一份旅遊線路圖,該線路圖中的旅行線路用數組 paths 表示,其中 paths[i] = [cityAi, cityBi] 表示該線路將會從 cityAi 直接前往 cityBi 。請你找出這次旅行的終點站,即沒有任何可以通往其他城市的線路的城市。
題目數據保證線路圖會形成一條不存在循環的線路,因此只會有一個旅行終點站。
示例 1:
輸入:paths = [[“London”,“New York”],[“New York”,“Lima”],[“Lima”,“Sao Paulo”]]
輸出:“Sao Paulo”
解釋:從 “London” 出發,最後抵達終點站 “Sao Paulo” 。本次旅行的路線是 “London” -> “New York” -> “Lima” -> “Sao Paulo” 。
示例 2:
輸入:paths = [[“B”,“C”],[“D”,“B”],[“C”,“A”]]
輸出:“A”
解釋:所有可能的線路是:
“D” -> “B” -> “C” -> “A”.
“B” -> “C” -> “A”.
“C” -> “A”.
“A”.
顯然,旅行終點站是 “A” 。
示例 3:
輸入:paths = [[“A”,“Z”]]
輸出:“Z”
提示:
1 <= paths.length <= 100
paths[i].length == 2
1 <= cityAi.length, cityBi.length <= 10
cityAi != cityBi
所有字符串均由大小寫英文字母和空格字符組成。
思路
找只在第二個位置出現沒有在第一個位置出現的元素
代碼
class Solution {
public String destCity(List<List<String>> paths) {
HashSet<String> froms = new HashSet<>();
for (List<String> path: paths) {
froms.add(path.get(0));
}
for (List<String> path: paths) {
String to = path.get(1);
if (!froms.contains(to)) {
return to;
}
}
return "";
}
}
5401. 是否所有 1 都至少相隔 k 個元素
給你一個由若干 0 和 1 組成的數組 nums 以及整數 k。如果所有 1 都至少相隔 k 個元素,則返回 True ;否則,返回 False 。
示例 1:
輸入:nums = [1,0,0,0,1,0,0,1], k = 2
輸出:true
解釋:每個 1 都至少相隔 2 個元素。
示例 2:
輸入:nums = [1,0,0,1,0,1], k = 2
輸出:false
解釋:第二個 1 和第三個 1 之間只隔了 1 個元素。
示例 3:
輸入:nums = [1,1,1,1,1], k = 0
輸出:true
示例 4:
輸入:nums = [0,1,0,1], k = 1
輸出:true
提示:
1 <= nums.length <= 10^5
0 <= k <= nums.length
nums[i] 的值爲 0 或 1
代碼
class Solution {
public boolean kLengthApart(int[] nums, int k) {
int pre = -1, cur = -1, i = 0, n = nums.length;
for (i=0; i<n; ++i) {
if (nums[i] == 1) {
pre = cur;
cur = i;
if (pre != -1 && cur - pre <= k) {
return false;
}
}
}
return true;
}
}
5402. 絕對差不超過限制的最長連續子數組
給你一個整數數組 nums ,和一個表示限制的整數 limit,請你返回最長連續子數組的長度,該子數組中的任意兩個元素之間的絕對差必須小於或者等於 limit 。
如果不存在滿足條件的子數組,則返回 0 。
示例 1:
輸入:nums = [8,2,4,7], limit = 4
輸出:2
解釋:所有子數組如下:
[8] 最大絕對差 |8-8| = 0 <= 4.
[8,2] 最大絕對差 |8-2| = 6 > 4.
[8,2,4] 最大絕對差 |8-2| = 6 > 4.
[8,2,4,7] 最大絕對差 |8-2| = 6 > 4.
[2] 最大絕對差 |2-2| = 0 <= 4.
[2,4] 最大絕對差 |2-4| = 2 <= 4.
[2,4,7] 最大絕對差 |2-7| = 5 > 4.
[4] 最大絕對差 |4-4| = 0 <= 4.
[4,7] 最大絕對差 |4-7| = 3 <= 4.
[7] 最大絕對差 |7-7| = 0 <= 4.
因此,滿足題意的最長子數組的長度爲 2 。
示例 2:
輸入:nums = [10,1,2,4,7,2], limit = 5
輸出:4
解釋:滿足題意的最長子數組是 [2,4,7,2],其最大絕對差 |2-7| = 5 <= 5 。
示例 3:
輸入:nums = [4,2,2,2,4,4,2,2], limit = 0
輸出:3
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
0 <= limit <= 10^9
思路
二分答案。判斷答案是否可行的函數就是在一個數組的給定長度的窗口上求最大最小值,使用滑動窗口實現。假設nums
的長度爲n
,滑動窗口的時間複雜度爲O(n)
,總的時間複雜度爲O(nlogn)
.
代碼
class Solution {
private class Value {
public int val, idx;
public Value(int _val, int _idx) {
val = _val;
idx = _idx;
}
}
private boolean slidingMaxMin(int[] nums, int w, int limit) {
if (w == 1) {
return true;
}
int i = 0, n = nums.length;
LinkedList<Value> dq_max = new LinkedList<>(), dq_min = new LinkedList<>();
dq_max.add(new Value(nums[0], 0));
dq_min.add(new Value(nums[0], 0));
for (i=1; i<n; ++i) {
// update dq_max
if (nums[i] >= dq_max.getFirst().val) {
dq_max.clear();
dq_max.add(new Value(nums[i], i));
} else {
while (!dq_max.isEmpty() && dq_max.getLast().val <= nums[i]) {
dq_max.removeLast();
}
dq_max.add(new Value(nums[i], i));
while (!dq_max.isEmpty() && dq_max.getFirst().idx <= i - w) {
dq_max.removeFirst();
}
}
// update dq_min
if (nums[i] <= dq_min.getFirst().val) {
dq_min.clear();
dq_min.add(new Value(nums[i], i));
} else {
while (!dq_min.isEmpty() && dq_min.getLast().val >= nums[i]) {
dq_min.removeLast();
}
dq_min.add(new Value(nums[i], i));
while (!dq_min.isEmpty() && dq_min.getFirst().idx <= i - w) {
dq_min.removeFirst();
}
}
// check max & min
if (i >= w-1 && dq_max.getFirst().val - dq_min.getFirst().val <= limit) {
return true;
}
}
return false;
}
public int longestSubarray(int[] nums, int limit) {
int n = nums.length, left = 1, right = n, mid = 0;
while (left <= right) {
mid = (right - left) / 2 + left;
if (mid == 1 || (mid != 0 && slidingMaxMin(nums, mid, limit))) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return right;
}
}
5403. 有序矩陣中的第 k 個最小數組和
給你一個 m * n 的矩陣 mat,以及一個整數 k ,矩陣中的每一行都以非遞減的順序排列。
你可以從每一行中選出 1 個元素形成一個數組。返回所有可能數組中的第 k 個 最小 數組和。
示例 1:
輸入:mat = [[1,3,11],[2,4,6]], k = 5
輸出:7
解釋:從每一行中選出一個元素,前 k 個和最小的數組分別是:
[1,2], [1,4], [3,2], [3,4], [1,6]。其中第 5 個的和是 7 。
示例 2:
輸入:mat = [[1,3,11],[2,4,6]], k = 9
輸出:17
示例 3:
輸入:mat = [[1,10,10],[1,4,5],[2,3,6]], k = 7
輸出:9
解釋:從每一行中選出一個元素,前 k 個和最小的數組分別是:
[1,1,2], [1,1,3], [1,4,2], [1,4,3], [1,1,6], [1,5,2], [1,5,3]。其中第 7 個的和是 9 。
示例 4:
輸入:mat = [[1,1,10],[2,2,9]], k = 7
輸出:12
提示:
m == mat.length
n == mat.length[i]
1 <= m, n <= 40
1 <= k <= min(200, n ^ m)
1 <= mat[i][j] <= 5000
mat[i] 是一個非遞減數組
思路
注意到每一行的選取是獨立的,因此問題具有子結構:整個二維數組的前k小的數組和,在二維數組的前i行中的部分,也是前k小的數組和。因此,用一個最大堆維護前i行的最小的k個數組和,每次把前i行的k個數組和與第(i+1)行的前min(n, k)個數組分別相加,最小的k個加和就是前(i+1)行的最小的k個數組和。如此遞推即可。時間複雜度O(mnklogk)
.
代碼
class Solution {
public int kthSmallest(int[][] mat, int k) {
int m = mat.length, n = Math.min(mat[0].length, k), i = 0, j = 0;
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (j=0; j<n; ++j) {
pq.add(mat[0][j]);
}
for (i=1; i<m; ++i) {
ArrayList<Integer> tmp = new ArrayList<>(pq);
pq.clear();
for (int num: tmp) {
for (j=0; j<n; ++j) {
int cur = num + mat[i][j];
if (pq.size() < k) {
pq.add(cur);
} else if (pq.size() == k && pq.peek() > cur) {
pq.poll();
pq.add(cur);
}
}
}
}
return pq.peek();
}
}