• [Leetcode Weekly Contest]303


    链接:LeetCode

    [Leetcode]2351. 第一个出现两次的字母

    给你一个由小写英文字母组成的字符串 s ,请你找出并返回第一个出现 两次 的字母。
    注意:

    • 如果 a 的 第二次 出现比 b 的 第二次 出现在字符串中的位置更靠前,则认为字母 a 在字母 b 之前出现两次。
    • s 包含至少一个出现两次的字母。

    模拟。

    class Solution {
        public char repeatedCharacter(String s) {
            HashSet<Character> set = new HashSet<>();
            for(var ch:s.toCharArray()) {
                if(set.contains(ch)) return ch;
                else set.add(ch);
            }
            return ' ';
        }
    }
    

    [Leetcode]2352. 相等行列对

    给你一个下标从 0 开始、大小为 n x n 的整数矩阵 grid ,返回满足 Ri 行和 Cj 列相等的行列对 (Ri, Cj) 的数目。
    如果行和列以相同的顺序包含相同的元素(即相等的数组),则认为二者是相等的。

    用哈希表统计每行出现的次数,然后遍历列,累加哈希表中列出现的次数。

    class Solution {
        public int equalPairs(int[][] grid) {
            int res = 0;
            int n = grid.length, m = grid[0].length;
            HashMap<String, Integer> hash = new HashMap<>();
            for(int i = 0;i<n;++i) {
                StringBuilder sb = new StringBuilder();
                for(int j = 0;j<m;++j) {
                    sb.append("#");
                    sb.append(grid[i][j]);
                }
                hash.put(sb.toString(), hash.getOrDefault(sb.toString(), 0)+1);
            }
    
            for(int j=0;j<n;++j) {
                StringBuilder sb = new StringBuilder();
                for(int i=0;i<n;++i) {
                    sb.append("#");
                    sb.append(grid[i][j]);
                }
                if(hash.containsKey(sb.toString())) res += hash.getOrDefault(sb.toString(), 0);
            }
            return res;
        }
    }
    
    

    [Leetcode]2353. 设计食物评分系统

    设计一个支持下述操作的食物评分系统:

    • 修改 系统中列出的某种食物的评分。
    • 返回系统中某一类烹饪方式下评分最高的食物。

    实现 FoodRatings 类:

    • FoodRatings(String[] foods, String[] cuisines, int[] ratings) 初始化系统。食物由 foods、cuisines 和 ratings 描述,长度均为 n 。
      • foods[i] 是第 i 种食物的名字。
      • cuisines[i] 是第 i 种食物的烹饪方式。
      • ratings[i] 是第 i 种食物的最初评分。
    • void changeRating(String food, int newRating) 修改名字为 food 的食物的评分。
    • String highestRated(String cuisine) 返回指定烹饪方式 cuisine 下评分最高的食物的名字。如果存在并列,返回 字典序较小 的名字。

    注意,字符串 x 的字典序比字符串 y 更小的前提是:x 在字典中出现的位置在 y 之前,也就是说,要么 x 是 y 的前缀,或者在满足 x[i] != y[i] 的第一个位置 i 处,x[i] 在字母表中出现的位置在 y[i] 之前。

    方法一:平衡树(有序集合)
    我们可以用一个哈希表 \(\textit{fs}\) 记录每个食物名称对应的食物评分和烹饪方式,另一个哈希表套平衡树 \(\textit{cs}\) 记录每个烹饪方式对应的食物评分和食物名字集合。对于 changeRating 操作,先从 \(\textit{cs}[\textit{fs}[\textit{food}].\textit{cuisine}]\) 中删掉旧数据,然后将 \(\textit{newRating}\)\(\textit{food}\) 记录到 \(\textit{cs}\)\(\textit{fs}\) 中。
    方法二:懒删除堆
    另一种做法是用堆:

    • 对于 changeRating 操作,直接往 \(\textit{cs}\) 中记录,不做任何删除操作;
    • 对于 highestRated 操作,查看堆顶的食物评分是否等于其实际值,若不相同则意味着对应的元素已被替换成了其他值,堆顶存的是个垃圾数据,直接弹出堆顶;否则堆顶就是答案。
    // TreeSet
    class FoodRatings1 {
        HashMap<String, Pair<String, Integer>> foodDict = new HashMap<>();
        HashMap<String, TreeSet<Pair<String, Integer>>> cuisineDict = new HashMap<>();
    
        public FoodRatings(String[] foods, String[] cuisines, int[] ratings) {
            for(int i=0;i<foods.length;++i) {
                String food = foods[i], cuisine = cuisines[i];
                int rating = ratings[i];
                foodDict.put(food, new Pair<>(cuisine, rating));
                cuisineDict.computeIfAbsent(cuisine, k -> new TreeSet<>((a, b) -> !Objects.equals(a.getValue(), b.getValue()) ? b.getValue()-a.getValue() : a.getKey().compareTo(b.getKey()))).add(new Pair<>(food, rating));
            }
        }
    
        public void changeRating(String food, int newRating) {
            var pair = foodDict.get(food);
            String cuisine = pair.getKey();
            int oldRating = pair.getValue();
            //foodDict.remove(pair);
            foodDict.put(food, new Pair<>(cuisine, newRating));
    
            var rawMap = cuisineDict.get(cuisine);
            rawMap.remove(new Pair<>(food, pair.getValue()));
            rawMap.add(new Pair<>(food, newRating));
        }
    
        public String highestRated(String cuisine) {
            return cuisineDict.get(cuisine).first().getKey();
        }
    }
    
    // PriorityQueue
    class FoodRatings2 {
        HashMap<String, Pair<String, Integer>> foodDict = new HashMap<>();
        HashMap<String, PriorityQueue<Pair<String, Integer>>> cuisineDict = new HashMap<>();
    
        public FoodRatings(String[] foods, String[] cuisines, int[] ratings) {
            for(int i=0;i<foods.length;++i) {
                String food = foods[i], cuisine = cuisines[i];
                int rating = ratings[i];
                foodDict.put(food, new Pair<>(cuisine, rating));
                cuisineDict.computeIfAbsent(cuisine, k -> new PriorityQueue<>((a, b) -> !Objects.equals(a.getValue(), b.getValue()) ? b.getValue()-a.getValue() : a.getKey().compareTo(b.getKey()))).add(new Pair<>(food, rating));
            }
        }
    
        public void changeRating(String food, int newRating) {
            var pair = foodDict.get(food);
            String cuisine = pair.getKey();
            int oldRating = pair.getValue();
            //foodDict.remove(pair);
            foodDict.put(food, new Pair<>(cuisine, newRating));
    
            var rawMap = cuisineDict.get(cuisine);
            rawMap.offer(new Pair<>(food, newRating));
        }
    
        // lazy delete
        public String highestRated(String cuisine) {
            var rawMap = cuisineDict.get(cuisine);
            while(!Objects.equals(rawMap.peek().getValue(), foodDict.get(rawMap.peek().getKey()).getValue())) {
                rawMap.poll();
            }
            return rawMap.peek().getKey();
        }
    }
    

    [Leetcode]2354. 优质数对的数目

    给你一个下标从 0 开始的正整数数组 nums 和一个正整数 k 。
    如果满足下述条件,则数对 (num1, num2) 是 优质数对 :

    • num1 和 num2 都 在数组 nums 中存在。
    • num1 OR num2 和 num1 AND num2 的二进制表示中值为 1 的位数之和大于等于 k ,其中 OR 是按位 或 操作,而 AND 是按位 与 操作。

    返回 不同 优质数对的数目。
    如果 a != c 或者 b != d ,则认为 (a, b) 和 (c, d) 是不同的两个数对。例如,(1, 2) 和 (2, 1) 不同。
    注意:如果 num1 在数组中至少出现 一次 ,则满足 num1 == num2 的数对 (num1, num2) 也可以是优质数对。

    数学。
    讨论二进制第 i 位在 num1 和 num2 中是否为 1 的情况:
    若第 i 位的 1 只在 num1 和 num2 中出现一次,则它只会在 num1 OR num2 的结果中出现,对位数之和的贡献是 1;
    若第 i 位的 1 在 num1 和 num2 中出现两次,则它会在 num1 OR num2 和 num1 AND num2 的结果中出现,对位数之和的贡献是 2。
    也就是说,第 i 位在两个数里出现几次,它的贡献就是几。因此我们维护 f(x) 表示数 x 中有几个 1,题目变为:

    求不同数对 (x,y) 的数量,使得 \(f(x) + f(y) \ge k\)

    统计答案时,我们枚举 \(f(x)\)\(f(y)\)。记 \(g(t)\) 表示 \(f(x) = t\) 的不同 x 有几个。根据数学知识,满足 \(f(x) + f(y) \ge k\) 的数对有 \(g(f(x)) \times g(f(y))\) 对。把枚举过程中的所有答案加起来即可。复杂度 \(\mathcal{O}(n\log A + \log^2 A)\),其中 A 是数组中的最大元素。

    class Solution {
        int[] bitcnt = new int[32];
        HashSet<Integer> set = new HashSet<>();
        public long countExcellentPairs(int[] nums, int k) {
            for(var num:nums) {
                int n = Integer.bitCount(num);
                if(!set.contains(num)) {
                    bitcnt[n] += 1;
                    set.add(num);
                }
            }
            long res = 0;
            for(int i=0;i<32;++i) {
                for(int j=0;j<32;++j) {
                    if(i+j >= k && bitcnt[i]!=0 &&bitcnt[j]!=0)
                        res += bitcnt[i] * bitcnt[j];
                }
            }
            return res;
        }
    }
    

    参考:LeetCode
    LeetCode

  • 相关阅读:
    js实现选择切换
    Jquery操作select
    Mybatis 高级结果映射 ResultMap Association Collection
    jQuery的一些特性和用法
    利用JSONP解决AJAX跨域问题的原理与jQuery解决方案
    List转成Array 连个Array比较
    3.15
    Get 和 Post 方法的选择和URL的设计
    fd
    如何维护一个1000 IP的免费代理池
  • 原文地址:https://www.cnblogs.com/hellojamest/p/16522666.html
Copyright © 2020-2023  润新知