• [Leetcode Weekly Contest]312


    链接:LeetCode

    [Leetcode]2418. 按身高排序

    给你一个字符串数组 names ,和一个由 互不相同 的正整数组成的数组 heights 。两个数组的长度均为 n 。
    对于每个下标 i,names[i] 和 heights[i] 表示第 i 个人的名字和身高。
    请按身高 降序 顺序返回对应的名字数组 names 。

    由于height各不相同,通过哈希存储即可。

    class Solution {
        public String[] sortPeople(String[] names, int[] heights) {
            HashMap<Integer, String> height2Name = new HashMap<>();
            int n = names.length;
            for(int i=0;i<n;++i) {
                height2Name.put(heights[i], names[i]);
            }
            Arrays.sort(heights);
            var res = new String[n];
            for(int i=n-1;i>=0;--i) {
                res[n-1-i] = height2Name.get(heights[i]);
            }
            return res;
        }
    }
    

    [Leetcode]2419. 按位与最大的最长子数组

    给你一个长度为 n 的整数数组 nums 。
    考虑 nums 中进行 按位与(bitwise AND)运算得到的值 最大 的 非空 子数组。

    • 换句话说,令 k 是 nums 任意 子数组执行按位与运算所能得到的最大值。那么,只需要考虑那些执行一次按位与运算后等于 k 的子数组。
      返回满足要求的 最长 子数组的长度。

    数组的按位与就是对数组中的所有数字进行按位与运算。
    子数组 是数组中的一个连续元素序列。

    由于 AND 不会让数字变大,那么最大值就是数组的最大值。因此题目实际上求的是数组中的最大值最多连续出现了几次。复杂度\(\mathcal{O}(n)\)

    class Solution {
        public int longestSubarray(int[] nums) {
            int cur = 0, res = 0;
            int mx = Arrays.stream(nums).max().getAsInt();
            for(var num:nums) {
                if(num == mx) {
                    cur ++;
                    res = Math.max(res, cur);
                }
                else {
                    cur = 0;
                }
            }
            return res;
        }
    }
    

    [Leetcode]2420. 找到所有好下标

    给你一个大小为 n 下标从 0 开始的整数数组 nums 和一个正整数 k 。
    对于 k <= i < n - k 之间的一个下标 i ,如果它满足以下条件,我们就称它为一个 好 下标:

    • 下标 i 之前 的 k 个元素是 非递增的 。
    • 下标 i 之后 的 k 个元素是 非递减的 。

    按 升序 返回所有好下标。

    先倒着遍历,得到从每个位置向后的最长连续非降序列的长度,然后正着遍历,得到每个位置向前的最长连续非增序列的长度,同时统计答案。

    class Solution:
        def goodIndices(self, nums: List[int], k: int) -> List[int]:
            n = len(nums)
            ans = []
            dec = [1] * n
            for i in range(n - 2, k, -1):
                if nums[i] <= nums[i + 1]:
                    dec[i] = dec[i + 1] + 1  # 递推
            inc = 1
            for i in range(1, n - k):
                if inc >= k and dec[i + 1] >= k:
                    ans.append(i)
                if nums[i - 1] >= nums[i]:
                    inc += 1  # 递推
                else:
                    inc = 1
            return ans
    

    [Leetcode] 2421. 好路径的数目

    给你一棵 n 个节点的树(连通无向无环的图),节点编号从 0 到 n - 1 且恰好有 n - 1 条边。
    给你一个长度为 n 下标从 0 开始的整数数组 vals ,分别表示每个节点的值。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。
    一条 好路径 需要满足以下条件:

    • 开始节点和结束节点的值 相同 。
    • 开始节点和结束节点中间的所有节点值都 小于等于 开始节点的值(也就是说开始节点的值应该是路径上所有节点的最大值)。

    请你返回不同好路径的数目。
    注意,一条路径和它反向的路径算作 同一 路径。比方说, 0 -> 1 与 1 -> 0 视为同一条路径。单个节点也视为一条合法路径。

    并查集。按节点值从小到大考虑,同时用并查集合并时,总是从节点值小的点往节点值大的点合并,这样可以保证连通块的代表元的节点值是最大的。
    对于节点 x 及其邻居 y,如果 y 所处的连通分量的最大节点值不超过 \(\textit{vals}[x]\),那么可以把 y 所处的连通块合并到 x 所处的连通块中。
    如果此时这两个连通块的最大节点值相同,那么可以根据乘法原理,把这两个连通块内的等于最大节点值的节点个数相乘,加到答案中。

    class Solution {
        int[] fa;
    
        public int numberOfGoodPaths(int[] vals, int[][] edges) {
            var n = vals.length;
            List<Integer>[] g = new ArrayList[n];
            Arrays.setAll(g, e -> new ArrayList<>());
            for (var e : edges) {
                int x = e[0], y = e[1];
                g[x].add(y);
                g[y].add(x); // 建图
            }
    
            fa = new int[n];
            for (var i = 0; i < n; i++) fa[i] = i;
            // size[x] 表示节点值等于 vals[x] 的节点个数,如果按照节点值从小到大合并,size[x] 也是连通块内的等于最大节点值的节点个数
            var size = new int[n];
            Arrays.fill(size, 1);
            var id = IntStream.range(0, n).boxed().toArray(Integer[]::new);
            Arrays.sort(id, (i, j) -> vals[i] - vals[j]);
    
            var ans = n;
            for (var x : id) {
                int vx = vals[x], fx = find(x);
                for (var y : g[x]) {
                    y = find(y);
                    if (y == fx || vals[y] > vx) continue; // 只考虑最大节点值比 vx 小的连通块
                    if (vals[y] == vx) { // 可以构成好路径
                        ans += size[fx] * size[y]; // 乘法原理
                        size[fx] += size[y]; // 统计连通块内节点值等于 vx 的节点个数
                    }
                    fa[y] = fx; // 把小的节点值合并到大的节点值上
                }
            }
            return ans;
        }
    
        int find(int x) {
            if (fa[x] != x) fa[x] = find(fa[x]);
            return fa[x];
        }
    }
    

    参考:
    LeetCode

  • 相关阅读:
    第12月第30天 love2d
    第12月第29天 cocos quick manual
    cpu test
    learning armbian steps(10) ----- armbian 源码分析(五)
    Linux command nmon
    learning ddr Electrical Characteristics and AC Timing
    learning ddr tRP and tRP tRTP CL tRAS
    进入Windows之前发出警告
    向系统日志 写入自定义数据
    创建并写入自定义日志信息
  • 原文地址:https://www.cnblogs.com/hellojamest/p/16732257.html
Copyright © 2020-2023  润新知