【LeetCode周赛】LeetCode第359场周赛

判别首字母缩略词

给你一个字符串数组 words 和一个字符串 s ,请你判断 s 是不是 words 的 首字母缩略词 。
如果可以按顺序串联 words 中每个字符串的第一个字符形成字符串 s ,则认为 s 是 words 的首字母缩略词。例如,“ab” 可以由 [“apple”, “banana”] 形成,但是无法从 [“bear”, “aardvark”] 形成。
如果 s 是 words 的首字母缩略词,返回 true ;否则,返回 false 。

示例 1:

输入:words = [“alice”,“bob”,“charlie”], s = “abc”
输出:true
解释:words 中"alice"、“bob” 和 “charlie” 的第一个字符分别是 ‘a’、‘b’ 和 ‘c’。因此,s = "abc"是首字母缩略词。

示例 2:

输入:words = [“an”,“apple”], s = “a”
输出:false
解释:words 中 “an” 和 "apple"的第一个字符分别是 ‘a’ 和 ‘a’。 串联这些字符形成的首字母缩略词是 “aa” 。 因此,s = “a” 不是首字母缩略词。

示例 3:

输入:words = [“never”,“gonna”,“give”,“up”,“on”,“you”], s = “ngguoy”
输出:true
解释:串联数组 words 中每个字符串的第一个字符,得到字符串 “ngguoy” 。 因此,s = "ngguoy"是首字母缩略词。

提示:
1 < = w o r d s . l e n g t h < = 100 1 <= words.length <= 100 1<=words.length<=100
1 < = w o r d s [ i ] . l e n g t h < = 10 1 <= words[i].length <= 10 1<=words[i].length<=10
1 < = s . l e n g t h < = 100 1 <= s.length <= 100 1<=s.length<=100
words[i] 和 s 由小写英文字母组成
思路:
简单模拟题,直接按照题意取出每个单词的首字母,拼接起来,判断和字符串s是否相等即可。
代码:

class Solution {
public:
    bool isAcronym(vector<string>& words, string s) {
        string res;
        for(auto word:words){
            res+=word[0];
        }
        return res==s;
    }
};

k-avoiding 数组的最小总和

给你两个整数 n 和 k 。
对于一个由不同正整数组成的数组,如果其中不存在任何求和等于 k 的不同元素对,则称其为 k-avoiding 数组。
返回长度为 n 的 k-avoiding 数组的可能的最小总和。
示例 1:

输入:n = 5, k = 4
输出:18
解释:设若 k-avoiding 数组为 [1,2,4,5,6] ,其元素总和为 18 。可以证明不存在总和小于 18 的 k-avoiding 数组。

示例 2:

输入:n = 2, k = 6
输出:3
解释:可以构造数组 [1,2] ,其元素总和为 3 。 可以证明不存在总和小于 3 的k-avoiding 数组。

提示:
1 < = n , k < = 50 1 <= n, k <= 50 1<=n,k<=50
思路:
简单模拟题,需要构造一个长度为n的数组,满足不存在求和等于k的两个元素。数据范围很小,那么直接从1开始枚举,将每个数插入数组之前,判断该数字插入是否会和之前的数字相加等于k,不会等于k才能插入数组中。
代码:

class Solution {
public:
    bool Find(vector<int>p,int x,int k){
        for(auto a:p){
            if(a==k-x)return 1;
        }
        return 0;
    }
    int minimumSum(int n, int k) {
        int x=1,sum=0;
        vector<int>p;
        while(p.size()<n){
            if(!Find(p,x,k)){
                sum+=x;
                p.push_back(x++);
            }
            else x++;
        }
        return sum;
    }
};

销售利润最大化

给你一个整数 n 表示数轴上的房屋数量,编号从 0 到 n - 1 。
另给你一个二维整数数组 offers ,其中 o f f e r s [ i ] = [ s t a r t i , e n d i , g o l d i ] offers[i] = [start_i, end_i, gold_i] offers[i]=[starti,endi,goldi] 表示第 i i i 个买家想要以 g o l d i gold_i goldi 枚金币的价格购买从 s t a r t i start_i starti e n d i end_i endi 的所有房屋。
作为一名销售,你需要有策略地选择并销售房屋使自己的收入最大化。
返回你可以赚取的金币的最大数目。
注意 同一所房屋不能卖给不同的买家,并且允许保留一些房屋不进行出售。

示例 1:

输入:n = 5, offers = [[0,0,1],[0,2,2],[1,3,2]]
输出:3
解释:有 5 所房屋,编号从 0 到4 ,共有 3 个购买要约。 将位于 [0,0] 范围内的房屋以 1 金币的价格出售给第 1 位买家,并将位于 [1,3] 范围内的房屋以2 金币的价格出售给第 3 位买家。 可以证明我们最多只能获得 3 枚金币。

示例 2:

输入:n = 5, offers = [[0,0,1],[0,2,10],[1,3,2]]
输出:10
解释:有 5 所房屋,编号从 0 到4 ,共有 3 个购买要约。 将位于 [0,2] 范围内的房屋以 10 金币的价格出售给第 2 位买家。 可以证明我们最多只能获得 10枚金币。

提示:
1 < = n < = 1 0 5 1 <= n <= 10^5 1<=n<=105
o f f e r s [ i ] . l e n g t h = = 3 offers[i].length == 3 offers[i].length==3
0 < = s t a r t i < = e n d i < = n − 1 0 <= starti <= endi <= n - 1 0<=starti<=endi<=n1
1 < = g o l d i < = 1 0 3 1 <= goldi <= 10^3 1<=goldi<=103

思路:
动态规划,dp[i+1]表示购买编号不超过i的房屋所能获得的最大利益。

  • 若不购买, d p [ i + 1 ] = d p [ i ] dp[i+1]=dp[i] dp[i+1]=dp[i]
  • 若购买,那么遍历所有 e n d j = i end_j=i endj=i的买家请求, d p [ i + 1 ] = m a x ( d p [ i + 1 ] , d p [ s t a r t j ] + g o l d j ) dp[i+1]=max(dp[i+1],dp[start_j]+gold_j) dp[i+1]=max(dp[i+1],dp[startj]+goldj)
    可以先将所有相同房屋结尾的购买请求,通过结尾房屋编号存储起来。
    d p [ i + 1 ] = m a x { d p [ i ] 不购买 i 房屋 d p [ i + 1 ] = d p [ s t a r t j ] + g o l d j 购买 i 房屋 dp[i+1]=max\begin{cases} dp[i] & 不购买i房屋 \\ dp[i+1]=dp[start_j]+gold_j & 购买i房屋 \\ \end{cases} dp[i+1]=max{dp[i]dp[i+1]=dp[startj]+goldj不购买i房屋购买i房屋

代码:

class Solution {
public:
    int maximizeTheProfit(int n, vector<vector<int>>& offers){
        //dp[i]维护的是只卖到第i个房子的收益
        vector<vector<pair<int, int>>>tmp(n);
        for(auto offer:offers){
            tmp[offer[1]].push_back({offer[0],offer[2]});
        }
        int dp[n+1];//dp[i+1]维护的就是买到第i个房子的收益
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++){
            dp[i+1]=dp[i];//不买第i个房子,那么其收益最大就是dp[i]
            for(auto pii:tmp[i]){
                int start=pii.first,gold=pii.second;//买第i个房子
                dp[i+1]=max(dp[i+1],dp[start]+gold);
            }
        }
        return dp[n];
    }
};

找出最长等值子数组

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。
如果子数组中所有元素都相等,则认为子数组是一个 等值子数组 。注意,空数组是 等值子数组 。
从 nums 中删除最多 k 个元素后,返回可能的最长等值子数组的长度。
子数组 是数组中一个连续且可能为空的元素序列。

示例 1:

输入:nums = [1,3,2,3,1,3], k = 3
输出:3
解释:最优的方案是删除下标 2 和下标 4 的元素。删除后,nums 等于 [1, 3, 3, 3] 。 最长等值子数组从 i = 1 开始到 j = 3 结束,长度等于 3 。可以证明无法创建更长的等值子数组。

示例 2:

输入:nums = [1,1,2,2,1,1], k = 2
输出:4
解释:最优的方案是删除下标 2 和下标 3 的元素。 删除后,nums 等于 [1, 1, 1, 1] 。 数组自身就是等值子数组,长度等于 4 。 可以证明无法创建更长的等值子数组。

提示:
1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
1 < = n u m s [ i ] < = n u m s . l e n g t h 1 <= nums[i] <= nums.length 1<=nums[i]<=nums.length
0 < = k < = n u m s . l e n g t h 0 <= k <= nums.length 0<=k<=nums.length

分析:
分析题意,得知题目的目的就是需要删除每两个相同的数字之间不同的数,在删除k次的情况下,使得连续的相同的数字最多。那么我们可以存储每一个数字出现的位置。对于每一个数字,因为我们找到删除后,连续的该数字最多,比如说,对数字1,我们可以先维护出每两个1之间的距离,那么我们的目的就是要找到一串距离,使得距离和小于k,且距离的个数最多。显然可以用滑动窗口的方法,获得满足条件的答案。
代码:

class Solution {
public:
    const int MAXN = 1e5+5;
    int longestEqualSubarray(vector<int>& nums, int k) {
        if(nums.size()==1)return 1;
        vector<int>p[MAXN];
        for(int i=0;i<nums.size();i++){
            p[nums[i]].push_back(i);//先维护一下每个数字的位置
        }
        int res=1;
        for(int i=1;i<=nums.size();i++){
            int cnt=0,ans=0;
            vector<int>q;
            for(int j=1;j<p[i].size();j++){//维护每个数字两两之间的距离
                q.push_back(p[i][j]-p[i][j-1]-1);
            }
            for(int l=0,r=0;r<q.size();){//双指针,得到最多的距离
                cnt+=q[r++];
                while(cnt>k)cnt-=q[l++];
                ans=max(ans,r-l+1);
            }
            res=max(res,ans);
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a碟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值