双周赛119(哈希表、贪心、双指针+哈希表、二进制枚举子集+Floyd算法)

文章目录

  • 双周赛119
    • [2956. 找到两个数组中的公共元素](https://leetcode.cn/problems/find-common-elements-between-two-arrays/)
      • 哈希表
    • [2957. 消除相邻近似相等字符](https://leetcode.cn/problems/remove-adjacent-almost-equal-characters/)
      • 贪心
    • [2958. 最多 K 个重复元素的最长子数组](https://leetcode.cn/problems/length-of-longest-subarray-with-at-most-k-frequency/)
      • 双指针 + 哈希表
    • [2959. 关闭分部的可行集合数目](https://leetcode.cn/problems/number-of-possible-sets-of-closing-branches/)
      • 二进制枚举子集 + Floyd算法
        • Floyd
        • 二进制枚举

双周赛119

2956. 找到两个数组中的公共元素

简单

给你两个下标从 0 开始的整数数组 nums1nums2 ,它们分别含有 nm 个元素。

请你计算以下两个数值:

  • 统计 0 <= i < n 中的下标 i ,满足 nums1[i]nums2至少 出现了一次。
  • 统计 0 <= i < m 中的下标 i ,满足 nums2[i]nums1至少 出现了一次。

请你返回一个长度为 2 的整数数组 answer按顺序 分别为以上两个数值。

示例 1:

输入:nums1 = [4,3,2,3,1], nums2 = [2,2,5,2,3,6]
输出:[3,4]
解释:分别计算两个数值:
- nums1 中下标为 1 ,2 和 3 的元素在 nums2 中至少出现了一次,所以第一个值为 3 。
- nums2 中下标为 0 ,1 ,3 和 4 的元素在 nums1 中至少出现了一次,所以第二个值为 4 。

示例 2:

输入:nums1 = [3,4,2,3], nums2 = [1,5]
输出:[0,0]
解释:两个数组中没有公共元素,所以两个值都为 0 。

提示:

  • n == nums1.length
  • m == nums2.length
  • 1 <= n, m <= 100
  • 1 <= nums1[i], nums2[i] <= 100

哈希表

class Solution {
    public int[] findIntersectionValues(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new HashSet<>();
        for(int n : nums1) set1.add(n);
        Set<Integer> set2 = new HashSet<>();
        for(int n : nums2) set2.add(n);
        int cnt1 = 0, cnt2 = 0;
        for(int i = 0; i < nums1.length; i++){
            if(set2.contains(nums1[i]))
                cnt1++;
        }
        for(int i = 0; i < nums2.length; i++){
            if(set1.contains(nums2[i]))
                cnt2++;
        }
        return new int[]{cnt1, cnt2};
    }
}

2957. 消除相邻近似相等字符

中等

给你一个下标从 0 开始的字符串 word

一次操作中,你可以选择 word 中任意一个下标 i ,将 word[i] 修改成任意一个小写英文字母。

请你返回消除 word 中所有相邻 近似相等 字符的 最少 操作次数。

两个字符 ab 如果满足 a == b 或者 ab 在字母表中是相邻的,那么我们称它们是 近似相等 字符。

示例 1:

输入:word = "aaaaa"
输出:2
解释:我们将 word 变为 "acaca" ,该字符串没有相邻近似相等字符。
消除 word 中所有相邻近似相等字符最少需要 2 次操作。

示例 2:

输入:word = "abddez"
输出:2
解释:我们将 word 变为 "ybdoez" ,该字符串没有相邻近似相等字符。
消除 word 中所有相邻近似相等字符最少需要 2 次操作。

示例 3:

输入:word = "zyxyxyz"
输出:3
解释:我们将 word 变为 "zaxaxaz" ,该字符串没有相邻近似相等字符。
消除 word 中所有相邻近似相等字符最少需要 3 次操作

提示:

  • 1 <= word.length <= 100
  • word 只包含小写英文字母。

贪心

class Solution {
    /**
    什么时候需要消除?  该字符和上一个字符相邻时一定要消除
    */
    public int removeAlmostEqualCharacters(String word) {
        int res = 0;
        char pre = word.charAt(0);
        for(int i = 1; i < word.length(); i++){
            char c = word.charAt(i);
            if(Math.abs(c - pre) <= 1){
                res++;
                pre = '0';
            }else
                pre = c;
        }
        return res;
    }
}

2958. 最多 K 个重复元素的最长子数组

中等

给你一个整数数组 nums 和一个整数 k

一个元素 x 在数组中的 频率 指的是它在数组中的出现次数。

如果一个数组中所有元素的频率都 小于等于 k ,那么我们称这个数组是 数组。

请你返回 nums最长好 子数组的长度。

子数组 指的是一个数组中一段连续非空的元素序列。

示例 1:

输入:nums = [1,2,3,1,2,3,1,2], k = 2
输出:6
解释:最长好子数组是 [1,2,3,1,2,3] ,值 1 ,2 和 3 在子数组中的频率都没有超过 k = 2 。[2,3,1,2,3,1] 和 [3,1,2,3,1,2] 也是好子数组。
最长好子数组的长度为 6 。

示例 2:

输入:nums = [1,2,1,2,1,2,1,2], k = 1
输出:2
解释:最长好子数组是 [1,2] ,值 1 和 2 在子数组中的频率都没有超过 k = 1 。[2,1] 也是好子数组。
最长好子数组的长度为 2 。

示例 3:

输入:nums = [5,5,5,5,5,5,5], k = 4
输出:4
解释:最长好子数组是 [5,5,5,5] ,值 5 在子数组中的频率没有超过 k = 4 。
最长好子数组的长度为 4 。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 1 <= k <= nums.length

双指针 + 哈希表

class Solution {
    public int maxSubarrayLength(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        int left = 0, res = 0;
        for(int right = 0; right < nums.length; right++){
            map.merge(nums[right], 1, Integer::sum);
            while(map.get(nums[right]) > k){
                map.merge(nums[left], -1, Integer::sum);
                left++;
            }
            res = Math.max(res, right - left + 1);
        }
        return res;
    }
}

2959. 关闭分部的可行集合数目

困难

一个公司在全国有 n 个分部,它们之间有的有道路连接。一开始,所有分部通过这些道路两两之间互相可以到达。

公司意识到在分部之间旅行花费了太多时间,所以它们决定关闭一些分部(也可能不关闭任何分部),同时保证剩下的分部之间两两互相可以到达且最远距离不超过 maxDistance

两个分部之间的 距离 是通过道路长度之和的 最小值

给你整数 nmaxDistance 和下标从 0 开始的二维整数数组 roads ,其中 roads[i] = [ui, vi, wi] 表示一条从 uivi 长度为 wi无向 道路。

请你返回关闭分部的可行方案数目,满足每个方案里剩余分部之间的最远距离不超过 maxDistance

注意,关闭一个分部后,与之相连的所有道路不可通行。

注意,两个分部之间可能会有多条道路。

示例 1:

双周赛119(哈希表、贪心、双指针+哈希表、二进制枚举子集+Floyd算法)_第1张图片

输入:n = 3, maxDistance = 5, roads = [[0,1,2],[1,2,10],[0,2,10]]
输出:5
解释:可行的关闭分部方案有:
- 关闭分部集合 [2] ,剩余分部为 [0,1] ,它们之间的距离为 2 。
- 关闭分部集合 [0,1] ,剩余分部为 [2] 。
- 关闭分部集合 [1,2] ,剩余分部为 [0] 。
- 关闭分部集合 [0,2] ,剩余分部为 [1] 。
- 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
总共有 5 种可行的关闭方案。

示例 2:

双周赛119(哈希表、贪心、双指针+哈希表、二进制枚举子集+Floyd算法)_第2张图片

输入:n = 3, maxDistance = 5, roads = [[0,1,20],[0,1,10],[1,2,2],[0,2,2]]
输出:7
解释:可行的关闭分部方案有:
- 关闭分部集合 [] ,剩余分部为 [0,1,2] ,它们之间的最远距离为 4 。
- 关闭分部集合 [0] ,剩余分部为 [1,2] ,它们之间的距离为 2 。
- 关闭分部集合 [1] ,剩余分部为 [0,2] ,它们之间的距离为 2 。
- 关闭分部集合 [0,1] ,剩余分部为 [2] 。
- 关闭分部集合 [1,2] ,剩余分部为 [0] 。
- 关闭分部集合 [0,2] ,剩余分部为 [1] 。
- 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
总共有 7 种可行的关闭方案。

示例 3:

输入:n = 1, maxDistance = 10, roads = []
输出:2
解释:可行的关闭分部方案有:
- 关闭分部集合 [] ,剩余分部为 [0] 。
- 关闭分部集合 [0] ,关闭后没有剩余分部。
总共有 2 种可行的关闭方案。

提示:

  • 1 <= n <= 10
  • 1 <= maxDistance <= 105
  • 0 <= roads.length <= 1000
  • roads[i].length == 3
  • 0 <= ui, vi <= n - 1
  • ui != vi
  • 1 <= wi <= 1000
  • 一开始所有分部之间通过道路互相可以到达。

二进制枚举子集 + Floyd算法

class Solution {
    /**
    0 <= roads.length <= 1000
    枚举保留哪些节点,在这些节点之间连边
    然后用Floyd算法求出任意两点之间的最短路,
        若保留节点之间的最短路均不超过maxDistance,记录答案
     */
    public int numberOfSets(int n, int maxDistance, int[][] roads) {
        // 预处理原图的邻接矩阵g
        int[][] g = new int[n][n];
        for(int i = 0; i < n; i++){
            Arrays.fill(g[i], Integer.MAX_VALUE / 2); // 加法防溢出
            g[i][i] = 0;
        }
        for(int[] e : roads){
            int x = e[0], y = e[1], wt = e[2];
            g[x][y] = Math.min(g[x][y], wt);
            g[y][x] = Math.min(g[y][x], wt);
        }
        int res = 0;
        int[][] f = new int[n][n];
        next:
        //遍历所有方案数,当前方案i的二进制中为1的位置则表示该节点没有被删除,为0则表示被删除
        for(int s = 0; s < (1 << n); s++){
            for(int i = 0; i < n; i++){
                if(((s >> i) & 1) == 1){
                    System.arraycopy(g[i], 0, f[i], 0, n);
                }
            }
            // Floyd
            for (int k = 0; k < n; k++) {
                if ((s >> k & 1) == 0) continue;
                for (int i = 0; i < n; i++) {
                    if ((s >> i & 1) == 0) continue;
                    for (int j = 0; j < n; j++) {
                        f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j]);
                    }
                }
            }
            for (int i = 0; i < n; i++) {
                if ((s >> i & 1) == 0) continue;
                for (int j = 0; j < n; j++) {
                    if ((s >> j & 1) == 1 && f[i][j] > maxDistance) {
                        continue next;
                    }
                }
            }
            res++;
        }
        return res;
    }
}

题单:

Floyd
  • 2642. 设计可以求最短路径的图类 1811
  • 1334. 阈值距离内邻居最少的城市 1855
  • 2101. 引爆最多的炸弹 1880
二进制枚举
  • 78. 子集

  • 77. 组合

  • 1286. 字母组合迭代器 1591

  • 2397. 被列覆盖的最多行数 1719

  • 2212. 射箭比赛中的最大得分 1869

  • 77. 组合

  • 1286. 字母组合迭代器 1591

  • 2397. 被列覆盖的最多行数 1719

  • 2212. 射箭比赛中的最大得分 1869

  • 1601. 最多可达成的换楼请求数目 2119

你可能感兴趣的:(算法刷题记录,#,LC周赛,散列表,算法,数据结构)