D359周赛复盘:贪心解决求最小和问题⭐⭐+较为复杂的双层线性DP⭐⭐

2828.判别首字母缩略词

给你一个字符串数组 words 和一个字符串 s ,请你判断 s 是不是 words首字母缩略词

如果可以按顺序串联 words 中每个字符串的第一个字符形成字符串 s ,则认为 swords 的首字母缩略词。例如,"ab" 可以由 ["apple", "banana"] 形成,但是无法从 ["bear", "aardvark"] 形成。

如果 swords 的首字母缩略词,返回 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 <= words.length <= 100
  • 1 <= words[i].length <= 10
  • 1 <= s.length <= 100
  • words[i]s 由小写英文字母组成

完整版

class Solution {
public:
    bool isAcronym(vector<string>& words, string s) {
        string result = "";
        for(string word:words){
            result.push_back(word[0]);
        }
        if(result==s) return true;
        return false;
    }
};

2829.k-avoiding数组的最小总和(贪心解法)

给你两个整数 nk

对于一个由 不同 正整数组成的数组,如果其中不存在任何求和等于 k 的不同元素对,则称其为 k-avoiding 数组。

返回长度为 nk-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

思路

本题思路是贪心解法。不同正整数组成的数组,且需要选择可能的最小总和,因此需要从小到大开始取值。

我们可以使用一个set集合存储已经选择过的数字,使用 curr 来代表当前尝试选择的数字。开始时,curr 被设置为 1。

  1. 检查curr 是否已经在 used 中或者 k-curr是否在 used 中:
    • 如果 curr 已经被选择过,或者 k-curr 也被选择过(这意味着如果我们选择 curr ,会有一个和为 k 的对存在),那么我们应该跳过这个 curr ,并使 curr 加1
    • 否则,我们选择 curr ,增加总和,并将 curr 加入到 used 中。
  2. 最后返回总和。

完整版

  • 因为是找最小和,所以并不适合用组合总和那一套回溯的方法解决
class Solution {
public:
    int minimumSum(int n, int k) {
        set<int>used;
        int sum=0;
        for(int i=1;i<=n;i++){
            int cur=1;//从1开始尝试
            //只要不满足条件,就一直cur++,一直到满足条件为止!
            while(used.count(cur)||used.count(k-cur)){
                cur++;
            }
            sum+=cur;
            used.insert(cur);
        }
        return sum;
    }
};

举一个简单的例子来解释这个算法。考虑 n = 5 和 k = 4。

  • 首先选择数字 1,sum = 1used = {1}
  • 下一个数字是 2,但是我们不能选择2,因为 2+2 = 4,即 k。因此,我们跳过2。
  • 接着选择数字 3,sum = 4used = {1,3}
  • 选择数字 4,sum = 8used = {1,3,4}
  • 选择数字 5,sum = 13used = {1,3,4,5}
  • 最后选择数字 6,sum = 18used = {1,3,4,5,6}

因此,输出为 18。

类似题:2834.找出美丽数组的最小和

给你两个正整数:ntarget

如果数组 nums 满足下述条件,则称其为 美丽数组

  • nums.length == n.
  • nums 由两两互不相同的正整数组成。
  • 在范围 [0, n-1] 内,不存在 两个 不同 下标 ij ,使得 nums[i] + nums[j] == target

返回符合条件的美丽数组所可能具备的 最小 和。

示例 1:

输入:n = 2, target = 3
输出:4
解释:nums = [1,3] 是美丽数组。
- nums 的长度为 n = 2 。
- nums 由两两互不相同的正整数组成。
- 不存在两个不同下标 i 和 j ,使得 nums[i] + nums[j] == 3 。
可以证明 4 是符合条件的美丽数组所可能具备的最小和。

示例 2:

输入:n = 3, target = 3
输出:8
解释:
nums = [1,3,4] 是美丽数组。 
- nums 的长度为 n = 3 。 
- nums 由两两互不相同的正整数组成。 
- 不存在两个不同下标 i 和 j ,使得 nums[i] + nums[j] == 3 。
可以证明 8 是符合条件的美丽数组所可能具备的最小和。

示例 3:

输入:n = 1, target = 1
输出:1
解释:nums = [1] 是美丽数组。

提示:

  • 1 <= n <= 105
  • 1 <= target <= 105

思路

本题就和上面的贪心很像了,求得也是可能的最小和,所以需要从最小的数字开始取!

完整版

本题代码就和上面几乎一模一样了。因为求解的是可能的最小和,所以都是贪心来做。

class Solution {
public:
    long long minimumPossibleSum(int n, int target) {
        set<long long>used;
        int cur = 1;
        long long sum=0;
        for(int i=1;i<=n;i++){
            while(used.count(cur)||used.count(target-cur)){
                cur++;
            }
            used.insert(cur);
            sum+=cur;
        }
        return sum;
    }
};

2830.销售利润最大化⭐⭐

给你一个整数 n 表示数轴上的房屋数量,编号从 0n - 1

另给你一个二维整数数组 offers ,其中 offers[i] = [starti, endi, goldi] 表示第 i 个买家想要以 goldi 枚金币的价格购买从 startiendi 的所有房屋。

作为一名销售,你需要有策略地选择并销售房屋使自己的收入最大化。

返回你可以赚取的金币的最大数目。

注意 同一所房屋不能卖给不同的买家,并且允许保留一些房屋不进行出售。

示例 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 <= 10^5
  • 1 <= offers.length <= 10^5
  • offers[i].length == 3
  • 0 <= starti <= endi <= n - 1
  • 1 <= goldi <= 10^3

思路

题解:2830. 销售利润最大化 - 力扣(LeetCode)

DP数组含义

dp[i]的含义是:dp[i+1]表示销售编号不超过i的房屋的最大盈利。因为还要考虑房屋为0的情况。

如果用 dp[i] 而不是 dp[i + 1]来表示的话,那 dp[0]的意思就是不超过编号为0的。但是,我们还需要考虑 编号不超过-1的(有点抽象,意思就是一个房屋都不考虑),但是下标不能是-1,所以就要把 dp 数组的下标移一下 , 让它别越界。

递推公式

考虑编号为i的房屋卖或者不卖:

  • 不卖,dp[i+1]=dp[i]
  • 卖,遍历所有终点房屋是房屋i的方案,找收益最大的方案。

完整版

class Solution {
public:
    int maximizeTheProfit(int n, vector<vector<int>>& offers) {
        vector<int>dp(n+1,0);
        sort(offers.begin(),offers.end(),[](vector<int>&a,vector<int>&b){
            return a[1]<b[1];//按照下标1位置升序排序,也就是对购买请求按照房屋终点值从小到大排序
        });
        int index=0;//方案编号
        //dp[i+1]表示从前往后卖到编号(下标)是i的房子时,总的最大获利
        for(int i=0;i<n;i++){
            //不卖i房子
            dp[i+1]=dp[i];
            //卖i房子
            while(index<offers.size()&&i==offers[index][1]){
                dp[i+1]=max(dp[i+1],dp[offers[index][0]]+offers[index][2]);
                index++;
            }
        }
        return dp[n];//dp[n]就对应着卖到下标n-1的房子(也就是最后一栋房子)的最大获益
    }
};

注意不能像下面这么写,因为while循环可能根本进不去,也就是说可能根本不存在i==offers[index][1],即根本不存在以房屋i为结尾的方案,但是dp[i+1]最少也要=dp[i]

class Solution {
public:
    //错误写法,while循环可能根本进不去
    int maximizeTheProfit(int n, vector<vector<int>>& offers) {
        vector<int>dp(n+1,0);
        sort(offers.begin(),offers.end(),[](vector<int>&a,vector<int>&b){
            return a[1]<b[1];//按照下标1位置升序排序
        });
        int index=0;//方案编号
        //dp[i+1]表示从前往后卖到编号(下标)是i的房子时,总的最大获利
        for(int i=0;i<n;i++){
            //不卖i房子
            //dp[i+1]=dp[i];
            //卖i房子
            while(index<offers.size()&&i==offers[index][1]){
                dp[i+1]=max(dp[i],max(dp[i+1],dp[offers[index][0]]+offers[index][2]));
                index++;
            }
        }
        return dp[n];//dp[n]就对应着卖到下标n-1的房子(也就是最后一栋房子)的最大获益
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 复盘是指对过去的事情进行思维演练和总结。通过复盘,我们可以回顾过去的经历、分析问题的原因和解决方法,提高思考能力和解决问题的效率。 复盘可以采用不同的方式进行,而对过去的事情做思维演练pdf是其中一种常见的方式。通过整理和记录思考过程,我们可以更系统地分析问题,发现问题的根本原因,并找到解决问题的方法。在pdf文档中,可以记录下相关的信息,如事件的背景、自己的思考过程、所得出的结论等。 在复盘过程中,我们可以回答一些关键问题。首先,我们可以思考问题的起因是什么,事件发生时有没有缺乏对应的准备工作。其次,我们可以分析问题解决的过程,看是否有哪些环节出现了错误或不足。最后,我们可以总结经验教训,思考类似问题如何避免或更好地处理。 通过复盘,我们可以更加全面地了解过去的经历,提高问题解决的能力。同时,通过记录下自己的思考过程,我们还可以形成一份经验宝库,为未来的决策提供参考。因此,对过去的事情做思维演练pdf是一种非常有效的复盘方式。希望通过复盘,我们可以不断提升自我,在面对类似问题时能更加从容应对。 ### 回答2: 复盘是指对过去的事情进行思维演练,以总结经验教训,从而提高自己的决策能力和行动效果。复盘可以应用于个人生活和工作中的各个方面,也可以用于团队和组织的成长和进步。 在进行复盘时,首先需要明确目标和目的。我们需要回顾过去的事件或行动,了解其中的优点和不足,找到改进的方向和方式。通过对过去的事情进行思考和反思,我们可以发现自己在行动中的强项与不足,并从中吸取经验教训,避免重蹈覆辙。 在进行复盘时,我们可以利用各种工具和方法,如思维导图、SWOT分析等,来梳理复盘的内容和思路。我们可以回顾每个环节的具体步骤、决策的过程和原因,分析各种可能的影响因素和结果,评估自己的决策和行动的效果。 通过复盘,我们可以更加清楚地认识自己和环境的特点和规律,发现问题并提出解决方案。同时,复盘还可以帮助我们建立起对复杂情况的敏感性和观察力,提高我们的分析和判断能力。 最重要的是,复盘需要我们具备客观和开放的态度。我们需要坦诚面对自己的错误和不足,勇于承担责任,并且愿意接纳他人的意见和建议。只有这样,我们才能真正从复盘中获取改进和提升的机会。 总之,复盘是对过去事情进行思维演练的过程,通过深入思考和反思,总结经验教训,找到改进的方向和方式。复盘可以帮助我们不断提升自己的决策能力和行动效果,从而更好地应对未来的挑战。 ### 回答3: 复盘是一种思维训练方法,通过对过去的事情进行思维演练,可以帮助我们更好地总结和吸取经验教训。这种方法非常有助于个人和团队的成长与进步。 首先,复盘可以帮助我们对过去的事情进行全面的回顾和总结。通过回顾过去的决策、操作和结果,我们可以更清晰地看到策略的得失。同时,通过总结成功的方面和失败的原因,我们能够更好地认识自己的优势和劣势。 其次,复盘能够帮助我们发现问题并找到解决方案。在复盘过程中,我们可以深入分析出现问题的原因,并找到相应的解决办法。这样,我们可以避免类似问题的再次发生,并提高自己的决策能力和应变能力。 再次,复盘可以增强我们的自我反思能力。通过对过去事情的思维演练,我们可以更深入地了解自己的优点和缺点。同时,我们也能够看清外部环境对自己的影响,进一步提高自己在未来的应对能力。 最后,复盘能够增强个人和团队的学习能力。通过对过去事情的思维演练,我们可以从中吸取经验教训,并将其应用于未来的工作中。这样,我们不仅可以不断改进自己,也能够提高整个团队的绩效水平。 总之,复盘是一种非常有益的思维训练方法。通过对过去事情进行思维演练,我们能够全面总结经验教训,发现问题并找到解决方案,增强自我反思能力,提高个人和团队的学习能力。因此,我们应该经常进行复盘,不断提升自己。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值