第 258 场周赛(5867. 反转单词前缀/ 5868. 可互换矩形的组数 / 5869. 两个回文子序列长度的最大乘积(状态压缩) / 5870. 每棵子树内缺失的最小基因值(小大合并))(代码片

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第 258 场周赛(5867. 反转单词前缀/ 5868. 可互换矩形的组数 / 5869. 两个回文子序列长度的最大乘积(状态压缩) / 5870. 每棵子树内缺失的最小基因值(小大合并))(代码片相关的知识,希望对你有一定的参考价值。

第 258 场周赛

从这次开始还是把题目加上名字吧,要不然想找找不到题,哈哈

字节的周赛,还想冲个200来着,最后一题按二叉树写的,用例还能过,一提交,发现多叉的。。。来不及改了。。400多名

5867. 反转单词前缀

题目描述

给你一个下标从 0 开始的字符串 word 和一个字符 ch 。找出 ch 第一次出现的下标 i ,反转 word 中从下标 0 开始、直到下标 i 结束(含下标 i )的那段字符。如果 word 中不存在字符 ch ,则无需进行任何操作。

例如,如果 word = “abcdefd” 且 ch = “d” ,那么你应该 反转 从下标 0 开始、直到下标 3 结束(含下标 3 )。结果字符串将会是 “dcbaefd” 。
返回 结果字符串 。

示例 1:

输入:word = “abcdefd”, ch = “d”
输出:“dcbaefd”
解释:“d” 第一次出现在下标 3 。
反转从下标 0 到下标 3(含下标 3)的这段字符,结果字符串是 “dcbaefd” 。

示例 2:

输入:word = “xyxzxe”, ch = “z”
输出:“zxyxxe”
解释:“z” 第一次也是唯一一次出现是在下标 3 。
反转从下标 0 到下标 3(含下标 3)的这段字符,结果字符串是 “zxyxxe” 。

示例 3:

输入:word = “abcd”, ch = “z”
输出:“abcd”
解释:“z” 不存在于 word 中。
无需执行反转操作,结果字符串是 “abcd” 。

提示:

1 <= word.length <= 250
word 由小写英文字母组成
ch 是一个小写英文字母

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-prefix-of-word
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

估计是第一题里面,写的最慢的了吧

class Solution {
    public String reversePrefix(String word, char ch) {
        int l = word.length();
        int idx = -1;
        for(int i = 0; i < l; i++){
            if(word.charAt(i) == ch){
                idx = i;
                break;
            }
        }
        if(idx == -1)
            return word;
        StringBuffer sb = new StringBuffer();
        for(int i = idx; i >= 0; i--){
            sb.append(word.charAt(i));
        }
        
        sb.append(word.substring(idx + 1, l));
        return sb.toString();
    }
}

5868. 可互换矩形的组数

题目描述

用一个下标从 0 开始的二维整数数组 rectangles 来表示 n 个矩形,其中 rectangles[i] = [widthi, heighti] 表示第 i 个矩形的宽度和高度。

如果两个矩形 i 和 j(i < j)的宽高比相同,则认为这两个矩形 可互换 。更规范的说法是,两个矩形满足 widthi/heighti == widthj/heightj(使用实数除法而非整数除法),则认为这两个矩形 可互换 。

计算并返回 rectangles 中有多少对 可互换 矩形。

示例 1:

输入:rectangles = [[4,8],[3,6],[10,20],[15,30]]
输出:6
解释:下面按下标(从 0 开始)列出可互换矩形的配对情况:
- 矩形 0 和矩形 1 :4/8 == 3/6
- 矩形 0 和矩形 2 :4/8 == 10/20
- 矩形 0 和矩形 3 :4/8 == 15/30
- 矩形 1 和矩形 2 :3/6 == 10/20
- 矩形 1 和矩形 3 :3/6 == 15/30
- 矩形 2 和矩形 3 :10/20 == 15/30

示例 2:

输入:rectangles = [[4,5],[7,8]]
输出:0
解释:不存在成对的可互换矩形。

提示:

n == rectangles.length
1 <= n <= 105
rectangles[i].length == 2
1 <= widthi, heighti <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-pairs-of-interchangeable-rectangles
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

map存相同比值的矩形个数,然后C(n,2)选2个数
注意范围,又WA了一发…

class Solution {
    public long interchangeableRectangles(int[][] rec) {
        Map<Double, Integer> map = new HashMap<>();
        int l = rec.length;
        for(int i = 0; i < l; i++){
            double val = (double)rec[i][0] / (double)rec[i][1];
            if(map.containsKey(val)){
                map.put(val, map.get(val) + 1);
            }else{
                map.put(val, 1);
            }
        }
        long res = 0;
        for(double key : map.keySet()){
            int val = map.get(key);
            res += (long)val * (long)((val - 1)) / 2;
        }
        return res;
        
    }
}

5869. 两个回文子序列长度的最大乘积

题目描述

给你一个字符串 s ,请你找到 s 中两个 不相交回文子序列 ,使得它们长度的 乘积最大 。两个子序列在原字符串中如果没有任何相同下标的字符,则它们是 不相交 的。

请你返回两个回文子序列长度可以达到的 最大乘积 。

子序列 指的是从原字符串中删除若干个字符(可以一个也不删除)后,剩余字符不改变顺序而得到的结果。如果一个字符串从前往后读和从后往前读一模一样,那么这个字符串是一个 回文字符串 。

示例 1:


输入:s = “leetcodecom”
输出:9
解释:最优方案是选择 “ete” 作为第一个子序列,“cdc” 作为第二个子序列。
它们的乘积为 3 * 3 = 9 。

示例 2:

输入:s = “bb”
输出:1
解释:最优方案为选择 “b” (第一个字符)作为第一个子序列,“b” (第二个字符)作为第二个子序列。
它们的乘积为 1 * 1 = 1 。

示例 3:

输入:s = “accbcaxxcxx”
输出:25
解释:最优方案为选择 “accca” 作为第一个子序列,“xxcxx” 作为第二个子序列。
它们的乘积为 5 * 5 = 25 。

提示:

2 <= s.length <= 12
s 只含有小写英文字母。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-of-the-length-of-two-palindromic-subsequences
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

看到12,考虑状压,处理哪些位置能组成回文字符串,并记录能组成回文字符串的长度
然后遍历任意两个回文字符串,看是否有重叠,如果没有重叠,就满足条件
然后选取乘积的最大值

class Solution {
    String ss;
    int l;
    public int maxProduct(String s) {
        //先求出所有回文子序列吧
        ss = s;
        l = s.length();
        int[][] dp = new int[1 << l][2];
        for(int mask = 1; mask < (1 << l); mask++){
            dp[mask] = check(mask);
        }
        
        int max = 0;
        for(int i = 1; i < (1 << l); i++){
            for(int j = i + 1; j < (1 << l); j++){
                if(dp[i][0] == 1 && dp[j][0] == 1 && (i & j) == 0){
                    max = Math.max(dp[i][1] * dp[j][1], max);
                }
            }
        }
        return max;
        
    }
    
    public int[] check(int mask){
        StringBuffer sb = new StringBuffer();
        int len = 0;
        for(int i = 0; i < l; i++){
            if((mask & (1 << i)) != 0){
                sb.append(ss.charAt(i));
                len++;
            }
        }
        int ll = sb.length();
        int left = 0;
        int right = ll - 1;
        while(left < right){
            if(sb.charAt(left) == sb.charAt(right)){
                left++;
                right--;
            }else{
                return new int[]{0, -1};
            }
        }
        return new int[]{1, len};
    }
}

5870. 每棵子树内缺失的最小基因值

题目描述

有一棵根节点为 0 的 家族树 ,总共包含 n 个节点,节点编号为 0 到 n - 1 。给你一个下标从 0 开始的整数数组 parents ,其中 parents[i] 是节点 i 的父节点。由于节点 0 是 根 ,所以 parents[0] == -1 。

总共有 105 个基因值,每个基因值都用 闭区间 [1, 105] 中的一个整数表示。给你一个下标从 0 开始的整数数组 nums ,其中 nums[i] 是节点 i 的基因值,且基因值 互不相同 。

请你返回一个数组 ans ,长度为 n ,其中 ans[i] 是以节点 i 为根的子树内 缺失 的 最小 基因值。

节点 x 为根的 子树 包含节点 x 和它所有的 后代 节点。

示例 1:


输入:parents = [-1,0,0,2], nums = [1,2,3,4]
输出:[5,1,1,1]
解释:每个子树答案计算结果如下:
- 0:子树包含节点 [0,1,2,3] ,基因值分别为 [1,2,3,4] 。5 是缺失的最小基因值。
- 1:子树只包含节点 1 ,基因值为 2 。1 是缺失的最小基因值。
- 2:子树包含节点 [2,3] ,基因值分别为 [3,4] 。1 是缺失的最小基因值。
- 3:子树只包含节点 3 ,基因值为 4 。1是缺失的最小基因值。

示例 2:


输入:parents = [-1,0,1,0,3,3], nums = [5,4,6,2,1,3]
输出:[7,1,1,4,2,1]
解释:每个子树答案计算结果如下:
- 0:子树内包含节点 [0,1,2,3,4,5] ,基因值分别为 [5,4,6,2,1,3] 。7 是缺失的最小基因值。
- 1:子树内包含节点 [1,2] ,基因值分别为 [4,6] 。 1 是缺失的最小基因值。
- 2:子树内只包含节点 2 ,基因值为 6 。1 是缺失的最小基因值。
- 3:子树内包含节点 [3,4,5] ,基因值分别为 [2,1,3] 。4 是缺失的最小基因值。
- 4:子树内只包含节点 4 ,基因值为 1 。2 是缺失的最小基因值。
- 5:子树内只包含节点 5 ,基因值为 3 。1 是缺失的最小基因值。

示例 3:

输入:parents = [-1,2,3,0,2,4,1], nums = [2,3,4,5,6,7,8]
输出:[1,1,1,1,1,1,1]
解释:所有子树都缺失基因值 1 。

提示:

n == parents.length == nums.length
2 <= n <= 10^5
对于 i != 0 ,满足 0 <= parents[i] <= n - 1
parents[0] == -1
parents 表示一棵合法的树。
1 <= nums[i] <= 10^5
nums[i] 互不相同。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-missing-genetic-value-in-each-subtree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

我的思路,先建树
然后后序遍历,每次遍历,将已经有的基因值放到一个优先队列里,记录当前没有的最小基因值
然后往上遍历,合并优先队列,同时处理当前结点的缺失的最小基因值;要注意合并的时候是小大合并,小的优先队列合并到大的里面

看了一下别人写的,其实思路是正确的,就是没有写成多叉树,我哭了啊!!!!!!!!

果然,改成多叉树,过了…

class Solution {
    class Node{
        int val;
        int idx;
        List<Node> list;    //子节点集合
        public Node(int v, int i){
            val = v;
            idx = i;
            list = new ArrayList<>();
        }
    }   
    
    int[] res;
    public int[] smallestMissingValueSubtree(int[] parents, int[] nums) {
        int l = parents.length;
        res = new int[l];
        Map<Integer, Node> map = new HashMap<>();
        
        for(int i = 0; i < l; i++){
            Node node = new Node(nums[i], i);        
            map.put(i, node);
        }
        
        //建树
        for(int i = 0; i < l; i++){
            int p = parents[i];
            if(p == -1)
                continue;
            Node node = map.get(i);
            Node pp = map.get(p);
            //存储每个子节点
            pp.list.add(node);
        }
        
        Node root = map.get(0);
        dfs(root);  //从根节点开始递归
        return res;
    }
    
    public Help dfs(Node node){
        if(node == null)
            return new Help(new PriorityQueue<>(), 1);
        
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        int k = 1; 
        pq.offer(node.val); //将当前结点放入集合
        //遍历所有的孩子节点
        for(Node child : node.list){
            Help help = dfs(child);
            //取所有孩子节点当前缺少基因的最大值
            k = Math.max(help.k, k);
            //得到孩子的基因集合
            PriorityQueue<Integer> pqin = help.pq;    
            //合并,小的往大的合并
            //默认pq是大的集合
            if(pqin.size() > pq.size()){
                PriorityQueue<Integer> temp = pq;
                pq = pqin;
                pqin = temp;
            }
            while(!pqin.isEmpty()){
                pq.offer(pqin.poll());
            }
        }

        while(!pq.isEmpty() && pq.peek() == k){
            pq.poll();
            k++;
        }
        res[node.idx] = k;
        return new Help(pq, k);
    }
    
    class Help{
        PriorityQueue<Integer> pq;
        int k;
        public Help(PriorityQueue<Integer> pq, int k){
            this.pq = pq;
            this.k = k;
        }
    }
}

看到更多的思路是利用没有重复基因值的特点,先找到含有1的一个节点链表,其他节点缺少最小基因值就是1;找到以后,再进行一次dfs,处理这条链上的缺少最小基因值,不写了这里

以上是关于第 258 场周赛(5867. 反转单词前缀/ 5868. 可互换矩形的组数 / 5869. 两个回文子序列长度的最大乘积(状态压缩) / 5870. 每棵子树内缺失的最小基因值(小大合并))(代码片的主要内容,如果未能解决你的问题,请参考以下文章

解题报告力扣 第 273 场周赛

leetcode第294场周赛巫师的总力量和——维护前缀和的前缀和

leetcode第294场周赛巫师的总力量和——维护前缀和的前缀和

LeetCode 第 59 场力扣夜喵双周赛(最短路径数+迪杰斯特拉动态规划+最长公共前缀问题) / 第255场周赛(二进制转换,分组背包,子集还原数组(脑筋急转弯))

Acwing第 55 场周赛完结

Acwing第 55 场周赛完结