代码随想录算法训练营day37 | 738.单调递增的数字 714. 买卖股票的最佳时机含手续费 968.监控二叉树

day37

      • 738.单调递增的数字
        • 方法一 暴力破解 (超时了)
        • 方法二 贪心算法
      • 714. 买卖股票的最佳时机含手续费
      • 968.监控二叉树

738.单调递增的数字

题目链接

方法一 暴力破解 (超时了)
class Solution {
private:
    // 判断一个数字的各位上是否是递增
    bool checkNum(int num) {
        int max = 10;
        while (num) {
            int t = num % 10;
            if (max >= t) max = t;
            else return false;
            num = num / 10;
        }
        return true;
    }
public:
    int monotoneIncreasingDigits(int N) {
        for (int i = N; i > 0; i--) { // 从大到小遍历
            if (checkNum(i)) return i;
        }
        return 0;
    }
};

方法二 贪心算法

解题思路: 先判断给出的数字是不是单调递增的数字。如果是,直接输出。
如果不是,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9。考虑从后遍历还是从前遍历,如果从前遍历,可能会遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]
例如:332 寻找一个合适的单调递增数字,如果从前遍历可能会是329,不满足题意,真正满足的应该是299。
因此本题可以考虑从后遍历

class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N); //将整数N转换为字符串表示形式
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        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); //stoi函数 作用是将 n 进制的字符串转化为十进制
    }
};



714. 买卖股票的最佳时机含手续费

题目链接
**解题思路:**本题在122.买卖股票的最佳时机II基础上,又增加了手续费这一限制条件。

在做收获利润操作的时候其实有三种情况:

  • 情况一:收获利润的这一天并不是收获利润区间里的最后一天(不是真正的卖出,相当于持有股票),所以后面要继续收获利润。
  • 情况二:前一天是收获利润区间里的最后一天(相当于真正的卖出了),今天要重新记录最小价格了。
  • 情况三:不作操作,保持原有状态(买入,卖出,不买不卖)
class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int result = 0;
        int minPrice = prices[0]; // 记录最低价格
        for (int i = 1; i < prices.size(); i++) {
            // 情况二:相当于买入
            if (prices[i] < minPrice) minPrice = prices[i];

            // 情况三:保持原有状态(因为此时买则不便宜,卖则亏本)
            //if (prices[i] >= minPrice && prices[i] <= minPrice + fee) {
            //    continue;
            }

            // 计算利润,可能有多次计算利润,最后一次计算利润才是真正意义的卖出
            if (prices[i] > minPrice + fee) {
                result += prices[i] - minPrice - fee;
                minPrice = prices[i] - fee; // 情况一,这一步很关键
            }
        }
        return result;
    }
};


968.监控二叉树

题目链接
解题思路: 从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。
此时这道题目还有两个难点

  • 二叉树的遍历
  • 如何隔两个节点放一个摄像头
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;
    }
};

你可能感兴趣的:(算法训练营,算法,贪心算法,leetcode)