LeetCode 1337. 矩阵中战斗力最弱的 K 行/215. 数组中的第K个最大元素(topk快排堆排)/743. 网络延迟时间(最短路径迪杰斯特拉,弗洛伊德)
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 1337. 矩阵中战斗力最弱的 K 行/215. 数组中的第K个最大元素(topk快排堆排)/743. 网络延迟时间(最短路径迪杰斯特拉,弗洛伊德)相关的知识,希望对你有一定的参考价值。
1337. 矩阵中战斗力最弱的 K 行
2021.8.1 每日一题,眨眼八月了
题目描述
给你一个大小为 m * n 的矩阵 mat,矩阵由若干军人和平民组成,分别用 1 和 0 表示。
请你返回矩阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。
如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。
军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。
示例 1:
输入:mat =
[[1,1,0,0,0],
[1,1,1,1,0],
[1,0,0,0,0],
[1,1,0,0,0],
[1,1,1,1,1]],
k = 3
输出:[2,0,3]
解释:
每行中的军人数目:
行 0 -> 2
行 1 -> 4
行 2 -> 1
行 3 -> 2
行 4 -> 5
从最弱到最强对这些行排序后得到 [2,0,3,1,4]
示例 2:
输入:mat =
[[1,0,0,0],
[1,1,1,1],
[1,0,0,0],
[1,0,0,0]],
k = 2
输出:[0,2]
解释:
每行中的军人数目:
行 0 -> 1
行 1 -> 4
行 2 -> 1
行 3 -> 1
从最弱到最强对这些行排序后得到 [0,2,3,1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/the-k-weakest-rows-in-a-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
暴力
class Solution {
public int[] kWeakestRows(int[][] mat, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
int m = mat.length;
int n = mat[0].length;
for(int i = 0; i < m; i++){
int sum = 0;
for(int j = 0; j < n; j++){
sum += mat[i][j];
}
pq.offer(new int[]{sum, i});
}
int[] res = new int[k];
for(int i = 0; i < k; i++){
res[i] = pq.poll()[1];
}
return res;
}
}
然后看到每一行军人出现在平民前面,可以用二分
class Solution {
public int[] kWeakestRows(int[][] mat, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
int m = mat.length;
int n = mat[0].length;
for(int i = 0; i < m; i++){
int left = 0;
int right = n - 1;
while(left < right){
int mid = (right - left + 1) / 2 + left;
if(mat[i][mid] == 1){
left = mid;
}else{
right = mid - 1;
}
}
if(mat[i][left] == 1){
pq.offer(new int[]{left + 1, i});
}else{
pq.offer(new int[]{0, i});
}
}
int[] res = new int[k];
for(int i = 0; i < k; i++){
res[i] = pq.poll()[1];
}
return res;
}
}
215. 数组中的第K个最大元素
topK的写法,复习一下
题目描述
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
快排思想,这里加了个随机,不加也行
class Solution {
Random random = new Random();
public int findKthLargest(int[] nums, int k) {
//就背一个快排模板
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
public int quickSelect(int[] nums, int l, int r, int index){
int q = randomPartition(nums, l, r);
if(q == index)
return nums[q];
if(q > index)
return quickSelect(nums, l, q - 1, index);
else
return quickSelect(nums, q + 1, r, index);
}
public int randomPartition(int[] nums, int l, int r){
//交换到左边位置
int t = random.nextInt(r - l + 1) + l;
swap(nums, t, l);
return quickSort(nums, l, r);
}
public int quickSort(int[] nums, int l, int r){
int v = nums[l];
int i = l;
int j = r;
while(i < j){
while(i < j && nums[j] >= v)
j--;
while(i < j && nums[i] <= v)
i++;
swap(nums, i, j);
}
swap(nums, l, i);
return i;
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
堆排序,注意,建堆的过程, 自底向上,是O(n)的复杂度
class Solution {
public int findKthLargest(int[] nums, int k) {
//堆排序的思想
int heapsize = nums.length;
buildMaxHeap(nums, heapsize);
for(int i = 0; i < k - 1; i++){
//堆顶和堆底交换
swap(nums, 0, heapsize - i - 1);
//调整堆
adjust(nums, 0, heapsize - i - 1);
}
return nums[0];
}
//自底向上建堆,将数组看成一个完全二叉树
public void buildMaxHeap(int[] nums, int heapsize){
for(int i = heapsize / 2; i >= 0; i--){
adjust(nums, i, heapsize);
}
}
public void adjust(int[] nums, int i, int heapsize){
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i;
if(left < heapsize && nums[left] > nums[max]){
max = left;
}
if(right < heapsize && nums[right] > nums[max]){
max = right;
}
if(max != i){
swap(nums, max, i);
adjust(nums, max, heapsize);
}
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
743. 网络延迟时间
2021.8.2 每日一题
题目描述
有 n 个网络节点,标记为 1 到 n。
给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。
现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。
示例 1:
输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2
示例 2:
输入:times = [[1,2,1]], n = 2, k = 1
输出:1
示例 3:
输入:times = [[1,2,1]], n = 2, k = 2
输出:-1
提示:
1 <= k <= n <= 100
1 <= times.length <= 6000
times[i].length == 3
1 <= ui, vi <= n
ui != vi
0 <= wi <= 100
所有 (ui, vi) 对都 互不相同(即,不含重复边)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/network-delay-time
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
刚开始没想到是迪杰斯特拉,然后就写bfs了,结果做着做着,发现要求最短路径
只能硬着头皮改了一下,还是写出来了,虽然麻烦了点,还是写出来了
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
//bfs
int l = times.length;
Map<Integer, List<int[]>> map = new HashMap<>();
for(int i = 0; i < l; i++){
int s = times[i][0];
int t = times[i][1];
int d = times[i][2];
List<int[]> list = map.getOrDefault(s, new ArrayList<>());
list.add(new int[]{t, d});
map.put(s, list);
}
Map<Integer, Integer> used = new HashMap<>();
Queue<int[]> queue = new LinkedList<>();
int res = -1;
queue.offer(new int[]{k, 0});
used.put(k, 0);
while(!queue.isEmpty()){
int[] temp = queue.poll();
int s = temp[0];
int d = temp[1];
if(!map.containsKey(s))
continue;
List<int[]> list = map.get(s);
for(int i = 0; i < list.size(); i++){
int t = list.get(i)[0];
int dd = list.get(i)[1];
if(used.containsKey(t) && d + dd >= used.get(t))
continue;
queue.offer(new int[]{t, d + dd});
used.put(t, d + dd);
}
}
for(Map.Entry<Integer, Integer> entry : used.entrySet()){
res = Math.max(res, entry.getValue());
}
return used.size() == n ? res : -1;
}
}
再次回顾迪杰斯特拉:每次扩展最小的边,直到所有点都扩展到
自己写一下,看看能不能回想起来
自己写的,应该差不多是迪杰斯特拉的意思,比刚刚快了一点点
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
//bfs
int l = times.length;
Map<Integer, List<int[]>> map = new HashMap<>();
for(int i = 0; i < l; i++){
int s = times[i][0];
int t = times[i][1];
int d = times[i][2];
List<int[]> list = map.getOrDefault(s, new ArrayList<>());
list.add(new int[]{t, d});
map.put(s, list);
}
//存储扩展过的点
Set<Integer> set = new HashSet<>();
//存储扩展到的点和它的距离
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b) -> (a[1] == b[1] ? a[0] - b[0] : a[1] - b[1]));
pq.offer(new int[]{k, 0});
int res = 0;
while(!pq.isEmpty()){
//当前扩展的点就是优先队列的头部节点,即距离最短的点
int[] temp = pq.poll();
int s = temp[0];
int d = temp[1];
set.add(s);
res = d;
//如果所有点已经被扩展过了,就直接输出
if(set.size() == n)
return res;
//根据这个点s更新距离
if(!map.containsKey(s))
continue;
List<int[]> list = map.get(s);
for<以上是关于LeetCode 1337. 矩阵中战斗力最弱的 K 行/215. 数组中的第K个最大元素(topk快排堆排)/743. 网络延迟时间(最短路径迪杰斯特拉,弗洛伊德)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode Algorithm 1337. 矩阵中战斗力最弱的 K 行
Python描述 LeetCode 1337. 矩阵中战斗力最弱的 K 行
LeetCode 1337矩阵中战斗力最弱的K行[自定义排序] HERODING的LeetCode之路
LeetCode 1337. 矩阵中战斗力最弱的 K 行/215. 数组中的第K个最大元素(topk快排堆排)/743. 网络延迟时间(最短路径迪杰斯特拉,弗洛伊德)