leetcode 第 258 场算法比赛

作者: | 更新日期:

这次题有点难,但好像有不是那么难。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

昨天竟然是 leetcode 秋季变成大赛的个人赛,而我忘记了。

算了,这次周赛保持正常心态,好好打,没想到进入前百名了。

一、反转单词前缀

题意:给一个字符串和字符,找到字符串中字符第一次出现的位置。
然后将这个位置之前的字符串反转。

思路:按照题意,循环找到位置,前缀循环反转即可。

二、 可互换矩形的组数

题意:给一个数组,储存的是正整数二维下标。
求斜率相同的二元组个数。

思路:假设斜率相同的元素有 n 个,则二元组有 C(n, 2) 个。
所以需要先对斜率分组,然后依次求个数即可。

具体方法:直接按斜率排序,相同的斜率就是连续的。

注意事项1:考虑到精度,需要把除法转化为乘法。
注意实现2:而输入的范围是 10^5,相乘的时候需要转化为 int64,否则会越界。

三、两个回文子序列长度的最大乘积

题意:给一个字符串,找两个没有交集的回文子序列,使得两个子序列的长度乘积最大。

思路:一开始以为是状态压缩的动态规划。
但是推导状态方程时,发现状态太多储存不下。

然后先做第四题去了。
做完第四题一看榜单,第三题过了三百多个人,那显然不是状态压缩,毕竟会状态压缩的人没那么多。

既然可以过那么多人,显然可以暴力枚举了。
于是可以写两层循环,暴力枚举所有子序列,判断是否有交集,是否是回文串,都满足情况了,取最大值即可。

int n = s.length();
int N = 1<<n;
int ans = 0;
for(int i=1;i<N;i++){
    if(!CheckHuiwen(i, s)) continue;
    for(int j=1;j<N;j++){
        if(i & j) continue;
        if(!CheckHuiwen(j, s)) continue;
        int tmpans = int(__builtin_popcount(i)) * __builtin_popcount(j);
        if(tmpans > ans){
            ans = tmpans;
        }
    }
}
return ans;

四、每棵子树内缺失的最小基因值

题意:给一个有根树,每个节点有一个唯一的权重值。
问每个节点为根的子树里,最小的未出现的权重值是多少。

思路:一开始想使用树套树或者 LCA 来做,但是一计算复杂度,每个节点需要维护一个权重集合,内存和复杂度爆炸了。

然后就想着怎么去优化。

很快发现,对于子树节点没 1 的子树根,答案肯定都是 1.
所以权重为 1 的节点到根节点的值不确定外,其他节点的答案肯定都是 1。

这样本来是一道树的题,转化为了一个链的问题。

对于链,从下到上只需要维护一个权重集合即可,复杂度O(n)

int x = -1;
for(int i=0;i<n;i++) {
    if(nums[i] == 1) {
        x = i;
        break;
    }
}

while(x != -1) {
    Dfs(x);
    while(flag[minVal]) {
        minVal++;
    }
    ans[x] = minVal;
    x = parents[x];
}
return ans;

五、最后

这次比赛最后一题很奇妙,想到转化为链了,就是大水题,一个 DFS 就搞定了。
想不到转化为链,那就是超级复杂的数据结构题了。

同样,第三题暴力枚举的话,就是大水题,两层循环搞定,否则也是很复杂的动态规划题。

这两道题你都是怎么做的呢?

加油,算法人。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越