个人主页:@Sherry的成长之路
学习社区:Sherry的成长之路(个人社区)
专栏链接:练题
长路漫漫浩浩,万事皆有期待
738. 单调递增的数字 - 力扣(LeetCode)
题目描述,就是找出比给定整数小的一个最大整数,且该整数满足最高位到最低位依次递增(可以出现相等数字)。找到的最大递增数字也可以和给定数字相等,只要满足单调递增就可以了。
题目乍一看没什么理解上的难度,但是真的要分析出来,确实有些难度,并不是思路有很难,而是很难想出来。要做出来题,主要是要想清一点,给定一个数是如何求到最大的单调递增,例如给的数是98求出来的数是89,89满足小于等于98的且单调递增,而且你找不出任何比89更大的单调递增,那么它一定是符合的,322得到的是299,这两个示例看似没有共同点,实际上是暗藏玄机的。都是将一个数的最高位减一,然后其余位数变成9,就能得到了,那可有反例呢?1234就是反例,它求出的应该是1234也就是数字本身,这时我们就要加一个限制条件,先判断数字,再变化各位不要无脑变化。
具体思路是:比较各个数位,相邻数位中是否出现第一个数比第二个数大,如果出现了那说明符合之前的规律,如果如相反,则说明给出的数在目前这两位是1234这种类型的,往后遍历再试试。那问题来了,是从前向后遍历还是从后向前遍历呢?答案应该是从后向前依次遍历,如果是从前向后的话遇到了当前数据比上一位数小的情况则上一位数要减小1,那如果减小1了之后它又比之前位数小了这怎么办呢?这就出现bug了,所以不要从前向后遍历,这样会改变之前的数据,应该从后向前遍历,改变的是下一个数的值,这样就不会改变之前遍历过的数了。
具体见代码
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strnum=to_string(n);
int flag=strnum.size();
for(int i=strnum.size()-1;i>0;i--){
if(strnum[i-1]>strnum[i]){
flag=i;
strnum[i-1]--;
}
}
for(int i=flag;i<strnum.size();i++)
strnum[i]='9';
return stoi(strnum);
}
};
看了代码后发现,其实我们所要注意的不止这些,还有flag做标记,它的作用是标记从哪一位数之后的数应该全部变为9,这一点也是相当重要的,这样的思路我们可以在全部的数位遍历完之后再去修改要改成9的位,方便了我们的操作。在操作给定数之前由于是int类型的,操作起来会有一些不方便,所以我们将其变为字符串类型,这样可以方便我们对该数进行数位上的操作。
714. 买卖股票的最佳时机含手续费
思路:贪心算法
由于本题有手续费,所以可能会出现买卖利润不足以覆盖手续费的情况;
贪心策略:最低值买入,最高值(算上手续费还有盈余)卖出;寻找买入日和卖出日;买入日:遇到价格更低点就记录;卖出日:只要当前价格大于(最低价格+手续费),就可以收获利润,准确的卖出日为连续收获利润区间的最后一天。
情况一:今天可以收获利润,但不是收获利润区间里的最后一天,持有股票。情况二:前一天是收获利润区间的最后一天(即已经卖出),今天重新记录最小价格。情况三:不操作,保持原有状态(买入,卖出,不买不卖)。
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int sum = 0;
int buy = prices[0]+fee;//记录最低价格
for(int p:prices){
if(p+fee<buy){//情况二:重新买入
buy=p+fee;
}else if(p>buy){//情况一:可获利
sum+=p-buy;
buy=p;//还在收获利润的区间里,并非真正的卖出,不需要考虑fee
}
}
return sum;
}
};
968.监控二叉树
思路:
摄像头可以覆盖上中下三层;把摄像头放在叶子节点的父节点位置,才能充分利用摄像头的覆盖面积。局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少。
【遍历顺序】从下往上,因此使用后序遍历;
【隔两个节点放一个摄像头】0表示该节点无覆盖,1表示本节点有摄像头,2表示本节点有覆盖;其中,空节点的状态只能是有覆盖。
【递归终止条件】遇到空结点,返回2;
【单层逻辑处理】情况1:左右节点都有覆盖(2),那么中间节点无覆盖(0);情况2:左右节点至少有一个无覆盖(0),那么中间节点放摄像头(1);情况3:左右节点至少有一个摄像头(1),那么中间节点有覆盖(2);情况4:递归完后若头节点没有覆盖,result++;
class Solution {
private:
int result;
int traversal(TreeNode* cur) {
if (cur == NULL) return 2;
int left = traversal(cur->left); // 左
int right = traversal(cur->right); // 右
if (left == 2 && right == 2) return 0;
else if (left == 0 || right == 0) {
result++;
return 1;
} else return 2;
}
public:
int minCameraCover(TreeNode* root) {
result = 0;
if (traversal(root) == 0) { // root 无覆盖
result++;
}
return result;
}
};
今天我们完成了单调递增的数字、买卖股票的最佳时机含手续费、监控二叉树三道题,相关的思想需要多复习回顾。接下来,我们继续进行算法练习。希望我的文章和讲解能对大家的学习提供一些帮助。
当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~