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. 网络延迟时间(最短路径迪杰斯特拉,弗洛伊德)

leetcode:1337. 方阵中战斗力最弱的 K 行

1337. 矩阵中战斗力最弱的 K 行