week32

312 - 戳气球

经典的区间dp问题了,记住记住区间dp是先枚举长度 再枚举左端点

他这个状态设计注意一下 lr 都是没有打掉的 因为计算分数需要 avatar

还有一个优化: 每次计算nums[l] * nums[k] * nums[r] 可以先把nums[l] * nums[r] 存下来

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        vector<vector<int>> f(n + 2, vector<int>(n + 2));
        // 区间DP模板
        for(int len = 3; len <= n + 2; len++)
            for(int l = 0; len + l - 1 <= n + 1; l++)
            {
                int r = l + len - 1;
                int reslr = nums[l] * nums[r];
                for(int k = l + 1; k < r; k++)
                    f[l][r] = max(f[l][r], f[l][k] + f[k][r] + reslr * nums[k]);
            }
        return f[0][n + 1];
    }
};

313 - 超级丑数

复习一下丑数系列:

263 - 丑数

只包含质因子2, 3, 5 的话 就把质因子2,3, 5 除干净 看看余数是不是1就可以了

264 - 丑数II

丑数的定义是一样的 请找出第n个丑数

有点三路归并的意思, 用 i j k来表示丑数序列中因子2 3 5对应的指针 避免一个丑数同时有多个因子

每次更新 2 * ugs[i], 3 * ugs[j], 5 * ugs[k] 中最小的一个追加在序列内

然后判断更新的数是不是2 3 5 的因子 是的话 对应指针++

对于本题无非是丑数II这个题的扩展,把2 3 5的质数列表扩展即可

但是这里找最小值可以换成堆

  1. o(nk)

  1. o(nlogk)

315 - 计算右侧小于当前元素的数量

保序离散化 + 树状数组 经典了吧 拿离散后的元素当下标 这样可以区间查询到比x大/小的元素个数了

保序离散化

树状数组

代码如下:

316 - 去除重复字母

给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)

去掉重复字母还不算 还要字典序最小 -> 肯定是贪心删除

做法:

每次判断答案字符串的最后一个字母T[j] 大于 S[i]T[j]可删除 -> 删除 直到不行 维持这样的偏序关系 最终得到字典序最优的解

  • 使用栈来贪心的构造最终的字符串,栈的更新规则如下。

  • 前提是当前字符没有在栈中出现。如果当前字符比栈顶字符的值小,且栈顶字符不是最后一次出现,则栈顶出栈。

  • 重复 2 直到栈空或栈顶不满足出栈条件。此时,将当前字符压入栈中,且标记当前字符出现过。

  • 最后将栈中元素从栈底到栈顶的顺序输出。

318 - 最大单词长度乘积

两次枚举肯定是跑不掉的,但是如何快速判断两个字符串是否有相同字母?

二进制枚举的思想

用一个二进制数来表示每个字母是否出现过,这样用与运算就可判断是否有相同字母同时出现。

319 - 灯泡开关

数论题真的不会 记一下推导吧~

avatar

所以最终返回sqrt(n)的下取整就好

Last updated