第 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. 每棵子树内缺失的最小基因值(小大合并))(代码片的主要内容,如果未能解决你的问题,请参考以下文章
leetcode第294场周赛巫师的总力量和——维护前缀和的前缀和
leetcode第294场周赛巫师的总力量和——维护前缀和的前缀和
LeetCode 第 59 场力扣夜喵双周赛(最短路径数+迪杰斯特拉动态规划+最长公共前缀问题) / 第255场周赛(二进制转换,分组背包,子集还原数组(脑筋急转弯))