蓝桥杯打卡 简单dp专题

南岸以南南岸哀 2023-02-05 21:17:47

给你一个下标从 0 开始的整数数组 nums ,你必须将数组划分为一个或多个 连续 子数组。

如果获得的这些子数组中每个都能满足下述条件 之一 ,则可以称其为数组的一种 有效 划分:

子数组 恰 由 2 个相等元素组成,例如,子数组 [2,2] 。
子数组 恰 由 3 个相等元素组成,例如,子数组 [4,4,4] 。
子数组 恰 由 3 个连续递增元素组成,并且相邻元素之间的差值为 1 。例如,子数组 [3,4,5] ,但是子数组 [1,3,5] 不符合要求。
如果数组 至少 存在一种有效划分,返回 true ,否则,返回 false 。

const int N=1e5+10;
class Solution {
public:
    int f[N];
    bool validPartition(vector<int>& nums) {
        memset(f,0,sizeof(f));
        int n=nums.size();
        vector<int> a(n+1,0);
        for(int i=0;i<n;i++) a[i+1]=nums[i];
        f[0]=1;
        for(int i=2;i<=n;i++){
            if(a[i]==a[i-1]) f[i]|=f[i-2];
            if(i>=3&&a[i]==a[i-1]&&a[i-1]==a[i-2])
                f[i]|=f[i-3];
            if(i>=3&&a[i]==a[i-1]+1&&a[i-1]==a[i-2]+1)
                f[i]|=f[i-3];
        }

        return f[n];
    }
};

 

给你一个由小写字母组成的字符串 s ,和一个整数 k 。如果满足下述条件,则可以将字符串 t 视作是 理想字符串 :

t 是字符串 s 的一个子序列。
t 中每两个 相邻 字母在字母表中位次的绝对差值小于或等于 k 。
返回 最长 理想字符串的长度。

字符串的子序列同样是一个字符串,并且子序列还满足:可以经由其他字符串删除某些字符(也可以不删除)但不改变剩余字符的顺序得到。

注意:字母表顺序不会循环。例如,'a' 和 'z' 在字母表中位次的绝对差值是 25 ,而不是 1 。

const int N=1e5+10;
class Solution {
public:
    int f[N][30];
    int longestIdealString(string s, int k) {
        memset(f,0,sizeof(f));
        int n=s.size();
        vector<int> a;
        a.push_back(150);
        for(auto&x:s){
            a.push_back(x-'a');
        }
        f[0][0]=0;
        int res=0;
        for(int i=1;i<=n;i++){
            int x=a[i];
            f[i][x]=1;
            for(int j=0;j<26;j++) f[i][j]=f[i-1][j];
            for(int j=0;j<26;j++)
            {
                if(abs(x-j)<=k)
                    f[i][x]=max(f[i][x],f[i-1][j]+1);
            }
            res=max(res,f[i][x]);
        }
        return res;
    }
};

 

 

const int N=1010,mod=1e9+7;
class Solution {
public:
    int peopleAwareOfSecret(int n, int delay, int forget) {
       // memset(f,0,sizeof(f));
        vector<int> f(n+1),g(n+1);
        f[1]=g[1]=1;
        for(int i=2;i<=n;i++){
            int l=max(0,i-forget+1);
            int r=max(0,i-delay);
            f[i]=(g[r]-g[max(0,l-1)]+mod)%mod;
            g[i]=(f[i]+g[i-1])%mod;

        }
        return ((g[n]-g[max(0,n-forget)])+mod)%mod;
        
    }
};

在第 1 天,有一个人发现了一个秘密。

给你一个整数 delay ,表示每个人会在发现秘密后的 delay 天之后,每天 给一个新的人 分享 秘密。同时给你一个整数 forget ,表示每个人在发现秘密 forget 天之后会 忘记 这个秘密。一个人 不能 在忘记秘密那一天及之后的日子里分享秘密。

给你一个整数 n ,请你返回在第 n 天结束时,知道秘密的人数。由于答案可能会很大,请你将结果对 109 + 7 取余 后返回。

 

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

 

给你一个下标从 0 开始的 m x n 整数矩阵 grid 和一个整数 k 。你从起点 (0, 0) 出发,每一步只能往 下 或者往 右 ,你想要到达终点 (m - 1, n - 1) 。

请你返回路径和能被 k 整除的路径数目,由于答案可能很大,返回答案对 109 + 7 取余 的结果。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/paths-in-matrix-whose-sum-is-divisible-by-k
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

const int N=1010,mod=1e9+7;
class Solution {
public:
    int numberOfPaths(vector<vector<int>>& grid, int d) {
    
       
       int n=grid.size(),m=grid[0].size();
       vector<vector<int>> a(n+1,vector<int>(m+1,0));
       int f[n+1][m+1][50];
       memset(f,0,sizeof(f)); 
       for(int i=0;i<n;i++){
           for(int j=0;j<m;j++)
            a[i+1][j+1]=grid[i][j];
       }
       f[1][1][a[1][1]%d]=1;
       for(int i=1;i<=n;i++){
           for(int j=1;j<=m;j++){
               for(int k=0;k<d;k++){
                   if(i==1&&j==1) continue;
                   if(i-1>=1)f[i][j][k]=(f[i][j][k]+f[i-1][j][(((k-a[i][j])%d)+d)%d])%mod;
                   if(j-1>=1)f[i][j][k]=(f[i][j][k]+f[i][j-1][(((k-a[i][j])%d)+d)%d])%mod;
               }
           }
       }
       return f[n][m][0];
    }
};

 

给你一个 m x n 的整数网格图 grid ,你可以从一个格子移动到 4 个方向相邻的任意一个格子。

请你返回在网格图中从 任意 格子出发,达到 任意 格子,且路径中的数字是 严格递增 的路径数目。由于答案可能会很大,请将结果对 109 + 7 取余 后返回。

如果两条路径中访问过的格子不是完全相同的,那么它们视为两条不同的路径。

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

const int N=1010,mod=1e9+7;
class Solution {
public:
    int f[N][N];
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
    int n,m;
    int dfs(int x,int y,vector<vector<int>>& grid){
            if(f[x][y]!=-1) return f[x][y];
            if(x<0||y<0||x>n||y>m) return 1;
            f[x][y]=1;
            for(int i=0;i<4;i++){
                int tx=x+dx[i],ty=y+dy[i];
                if(tx<=0||tx>n||ty<=0||ty>m) continue;
                if(grid[x][y]<grid[tx][ty])
                {
                    f[x][y]=(f[x][y]+dfs(tx,ty,grid))%mod;
                }
            }
            return f[x][y];
    }
    int countPaths(vector<vector<int>>& grid) {
        memset(f,-1,sizeof(f));
        int res=0;
         n=grid.size(),m=grid[0].size();
        vector<vector<int>> g(n+1,vector<int>(m+1,0));
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++)
                g[i+1][j+1]=grid[i][j];
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                res=(res+dfs(i,j,g))%mod;
            }
        }
        return res;
    }
};

给你一个字符串 s 和一个 正 整数 k 。

从字符串 s 中选出一组满足下述条件且 不重叠 的子字符串:

每个子字符串的长度 至少 为 k 。
每个子字符串是一个 回文串 。
返回最优方案中能选择的子字符串的 最大 数目。

子字符串 是字符串中一个连续的字符序列。

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

const int N=4010;

class Solution {

public:

    int maxPalindromes(string s, int k) {

        int n=s.size();

        bool st[N][N];

        memset(st,0,sizeof(st));

        int f[n+10];

        memset(f,0,sizeof(f));

        s="?"+s;

        for(int i=1;i<=2*n-1;i++){

            int l=i/2,r=i/2+(i%2);

            while(l>=1&&r<=n&&s[l]==s[r]){

                st[l][r]=true;

                l--;

                r++;

            }

        }

        f[0]=0;

        for(int i=1;i<=n;i++) st[i][i]=1;

        for(int i=1;i<=n;i++){

            for(int j=1;j<=i;j++){

                f[i]=max(f[i],f[i-1]);

            if(st[j][i]&&i-j+1>=k) f[i]=max(f[i],f[j-1]+1);

            }

        }

        return f[n];

    }

};

给你一个仅由小写英文字母组成的字符串 s 。在一步操作中,你可以:

删除 整个字符串 s ,或者
对于满足 1 <= i <= s.length / 2 的任意 i ,如果 s 中的 前 i 个字母和接下来的 i 个字母 相等 ,删除 前 i 个字母。
例如,如果 s = "ababc" ,那么在一步操作中,你可以删除 s 的前两个字母得到 "abc" ,因为 s 的前两个字母和接下来的两个字母都等于 "ab" 。

返回删除 s 所需的最大操作数。

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

class Solution {
public:
    int deleteString(string s) {
        int n=s.size();
        s="?"+s;
        int lcp[n+10][n+10];
        memset(lcp,0,sizeof(lcp));
        for(int i=n;i>=1;i--){
            for(int j=n;j>=1;j--){
                    if(s[i]==s[j]) 
                        lcp[i][j]=lcp[i+1][j+1]+1;
                    else lcp[i][j]=0;
            }
        }
        int f[n+10];
        memset(f,0,sizeof(f));
        f[n+1]=0;
        for(int i=n;i>=1;i--){
            f[i]=1;
            for(int j=1;i+2*j-1<=n;j++){
                if(lcp[i][i+j]>=j)
                    f[i]=max(f[i],1+f[i+j]);
            }
        }
        return f[1];
    }
};

 

如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。

给你一个  整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。


class Solution {
public:
    int f[15][1024];
    int a[15];
    int len;
    int dfs(int pos,int pre,int lead,int limit,int cnt){
        if(!pos) return !lead;
        if(!limit&&!lead&&f[pos][cnt]!=-1) return f[pos][cnt];
        int res=0,up=limit?a[pos]:9;
        for(int i=0;i<=up;i++){
            if(cnt>>i&1) continue;
            int c=cnt;
            if(lead&&!i){
                res+=dfs(pos-1,0,lead&&!i,limit&&i==up,cnt);
            }
            else{
    c|=1<<i;
    res+=dfs(pos-1,i,lead&&!i,limit&&i==up,c);
            }
        }
        return limit?res:(lead?res:f[pos][cnt]=res);
    }
    int cal(int x){
        len=0;
        memset(f,-1,sizeof(f));
        while(x){
            a[++len]=x%10;
            x/=10;
        }
        return dfs(len,0,1,1,0);
    }
    int countSpecialNumbers(int n) {
        //memset(f,0,sizeof(f));
        return cal(n);
    }
};
class Solution:
    def countSpecialNumbers(self, n: int) -> int:
        s = str(n)
        @cache
        def f(i: int, mask: int, is_limit: bool, is_num: bool) -> int:
            if i == len(s):
                return int(is_num)
            res = 0
            if is_num==False:  # 可以跳过当前数位
                res = f(i + 1, mask, False, False)
            up = int(s[i]) if is_limit else 9
            for d in range(0,up+1):  # 枚举要填入的数字 d
                if mask >> d & 1 == 0:  # d 不在 mask 中
                    res += f(i + 1, mask | (1 << d), is_limit and d == up, True)
            return res
        return f(0, 0, True, False)

 

给你一个整数数组 nums 和一个整数 k 。

找到 nums 中满足以下要求的最长子序列:

子序列 严格递增
子序列中相邻元素的差值 不超过 k 。
请你返回满足上述要求的 最长子序列 的长度。

子序列 是从一个数组中删除部分元素后,剩余元素不改变顺序得到的数组。

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

const int N=1e5+10;
class Solution {
public:
    struct node{
        int l,r;
        int mx;
    }tr[N*4];
    void pushup(int u){
        tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx);
    }
    void build(int u,int l,int r){
        tr[u]={l,r,0};
        if(l==r){
            return ;
        }
        else{
            int mid=(l+r)>>1;
            build(u<<1,l,mid);
            build(u<<1|1,mid+1,r);
        }
    }
    void modify(int u,int x,int c){
        if(tr[u].l==tr[u].r&&x==tr[u].l){
            tr[u].mx=max(tr[u].mx,c);
            return;
        }
        else{
            int mid=(tr[u].l+tr[u].r)>>1;
            if(x<=mid) modify(u<<1,x,c);
            else modify(u<<1|1,x,c);
            pushup(u);
        }
    }
    int query(int u,int l,int r){
        if(tr[u].l>=l&&tr[u].r<=r){
            return tr[u].mx;
        }
        else{
           int mid=(tr[u].l+tr[u].r)>>1;
           int res=0;
           if(l<=mid) res=max(res,query(u<<1,l,r));
           if(r>mid) res=max(res,query(u<<1|1,l,r));
           return res;
        }
    }
    int lengthOfLIS(vector<int>& nums, int k) {
        memset(tr,0,sizeof(tr));
        build(1,0,100000);
        int n=nums.size();
        vector<int> a(n+1,0);
        for(int i=0;i<n;i++) a[i+1]=nums[i];
        int f[n+10];
        memset(f,0,sizeof(f));
        int res=0;
        for(int i=1;i<=n;i++){
            int x=a[i];
            f[i]=1;
            int t=query(1,max(0,x-k),max(0,x-1));
            f[i]=max(f[i],t+1);
            modify(1,x,f[i]);
            res=max(res,f[i]);
        }
        return res;
    }
};

给你一棵 二叉树 的根节点 root ,树中有 n 个节点。每个节点都可以被分配一个从 1 到 n 且互不相同的值。另给你一个长度为 m 的数组 queries 。

你必须在树上执行 m 个 独立 的查询,其中第 i 个查询你需要执行以下操作:

从树中 移除 以 queries[i] 的值作为根节点的子树。题目所用测试用例保证 queries[i] 不 等于根节点的值。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是执行第 i 个查询后树的高度。

注意:

查询之间是独立的,所以在每个查询执行后,树会回到其 初始 状态。
树的高度是从根到树中某个节点的 最长简单路径中的边数 。

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

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:unordered_map<TreeNode*,int> height;
     vector<int> res;
    int get_height(TreeNode*root){
        if(root==nullptr) return 0;
        height[root]=1+max(get_height(root->left),get_height(root->right));
        return height[root];
    }
    void dfs(TreeNode*root,int depth,int res_h){
        if(root==nullptr) return;
        res[root->val]=res_h;
        dfs(root->left,depth+1,max(res_h,depth+height[root->right]));
        dfs(root->right,depth+1,max(res_h,depth+height[root->left]));
    }
    vector<int> treeQueries(TreeNode* root, vector<int>& queries) {
        get_height(root);
        res.resize(height.size()+1);
        dfs(root,0,0);
        for(auto&q:queries) q=res[q];
        return queries;
    }
};

给你一个字符串 s ,每个字符是数字 '1' 到 '9' ,再给你两个整数 k 和 minLength 。

如果对 s 的分割满足以下条件,那么我们认为它是一个 完美 分割:

s 被分成 k 段互不相交的子字符串。
每个子字符串长度都 至少 为 minLength 。
每个子字符串的第一个字符都是一个 质数 数字,最后一个字符都是一个 非质数 数字。质数数字为 '2' ,'3' ,'5' 和 '7' ,剩下的都是非质数数字。
请你返回 s 的 完美 分割数目。由于答案可能很大,请返回答案对 109 + 7 取余 后的结果。

一个 子字符串 是字符串中一段连续字符串序列。

 

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

const int mod=1e9+7;
class Solution {
public:
    int beautifulPartitions(string s, int k, int minLength) {
        int n=s.size();
        s="?"+s;
        int f[n+10];
        int g[n+10];
        memset(f,0,sizeof(f));
        vector<int> pirmes(10,0);
        pirmes[2]=1;pirmes[3]=1;pirmes[5]=1;pirmes[7]=1;
        f[0]=1;
        for(int i=1;i<=k;i++){
            memcpy(g,f,sizeof(f));
            memset(f,0,sizeof(f));
            int v=0;
            for(int j=1;j<=n;j++){
                if(j-minLength+1>=1&&pirmes[s[j-minLength+1]-'0']) v=(v+g[j-minLength])%mod;
                if(pirmes[s[j]-'0']==0) f[j]=v;   
            }
        }
        return f[n];

    }
};

给你一个正整数数组 nums 和一个整数 k 。

分区 的定义是:将数组划分成两个有序的 组 ,并满足每个元素 恰好 存在于 某一个 组中。如果分区中每个组的元素和都大于等于 k ,则认为分区是一个好分区。

返回 不同 的好分区的数目。由于答案可能很大,请返回对 109 + 7 取余 后的结果。

如果在两个分区中,存在某个元素 nums[i] 被分在不同的组中,则认为这两个分区不同。

 

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

const int mod=1e9+7;
class Solution {
public:
    int countPartitions(vector<int>& nums, int k) {
        if(accumulate(nums.begin(),nums.end(),0ll)<2*k) return 0;
        //第一个分组或第二个分组和小于k
        int ans=1;
        int f[k];
        memset(f,0,sizeof(f));
        f[0]=1;
        for(auto&x:nums){
            ans=ans*2%mod;
            for(int j=k-1;j>=x;j--)
                f[j]=(f[j]+f[j-x])%mod;
        }
        for(int x:f){
            ans=(ans-x*2%mod+mod)%mod;
        }
        return ans;
    }
};

X 轴上有一些机器人和工厂。给你一个整数数组 robot ,其中 robot[i] 是第 i 个机器人的位置。再给你一个二维整数数组 factory ,其中 factory[j] = [positionj, limitj] ,表示第 j 个工厂的位置在 positionj ,且第 j 个工厂最多可以修理 limitj 个机器人。

每个机器人所在的位置 互不相同 。每个工厂所在的位置也 互不相同 。注意一个机器人可能一开始跟一个工厂在 相同的位置 。

所有机器人一开始都是坏的,他们会沿着设定的方向一直移动。设定的方向要么是 X 轴的正方向,要么是 X 轴的负方向。当一个机器人经过一个没达到上限的工厂时,这个工厂会维修这个机器人,且机器人停止移动。

任何时刻,你都可以设置 部分 机器人的移动方向。你的目标是最小化所有机器人总的移动距离。

请你返回所有机器人移动的最小总距离。测试数据保证所有机器人都可以被维修。

注意:

所有机器人移动速度相同。
如果两个机器人移动方向相同,它们永远不会碰撞。
如果两个机器人迎面相遇,它们也不会碰撞,它们彼此之间会擦肩而过。
如果一个机器人经过了一个已经达到上限的工厂,机器人会当作工厂不存在,继续移动。
机器人从位置 x 到位置 y 的移动距离为 |y - x| 。
 

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

class Solution:
    def minimumTotalDistance(self, robot: List[int], factory: List[List[int]]) -> int:
        m=len(factory)
        n=len(robot)
        factory.append([-(10**10)])
        robot.append(-(10**10))
        robot.sort()
        factory.sort()
        f=[[inf]*(n+10) for _ in range(m+10)]
        for i in range(0,m+1):
            f[i][0]=0
        for i in range(1,m+1):
            for j in range(1,n+1):
                cost=0
                limit=factory[i][1]
                f[i][j]=min(f[i][j],f[i-1][j])
                for k in range(j,0,-1):
                    if j-limit>=k:break
                    cost+=abs(robot[k]-factory[i][0])
                    f[i][j]=min(f[i][j],f[i-1][k-1]+cost)
        return f[m][n]

 

...全文
31 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

30,419

社区成员

发帖
与我相关
我的任务
社区描述
打造最热爱学习的高校社区,帮助大家提升计算机领域知识,带大家打比赛拿奖,提高自我,希望大家共同创造良好的社区氛围。
社区管理员
  • 川川菜鸟
  • 亡心灵
  • 星辰菜鸟
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

监督大家学习,每日学习打卡,以投稿形式打卡。扫码关注公众号,可加入粉丝群和领取大量资源。

试试用AI创作助手写篇文章吧