当前位置: 首页 > news >正文

day31-贪心__56. 合并区间__ 738.单调递增的数字__968.监控二叉树 (可跳过)

56. 合并区间

合并区间,这道题和昨天的452. 用最少数量的箭引爆气球和435. 无重叠区间 也是类似的思路,我们需要先对所有vector按照左端点或者右端点进行排序。本题按照左端点进行排序。之后,如果前一段的右端点<=后一段的左端,则进行合并操作,然后加入答案。否则就直接加入答案。

代码如下:

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> result;
        if (intervals.size() == 0) return result; // 区间集合为空直接返回
        // 排序的参数使用了lambda表达式
        sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});

        // 第一个区间就可以放进结果集里,后面如果重叠,在result上直接合并
        result.push_back(intervals[0]); 

        for (int i = 1; i < intervals.size(); i++) {
            if (result.back()[1] >= intervals[i][0]) { // 发现重叠区间
                // 合并区间,只更新右边界就好,因为result.back()的左边界一定是最小值,因为我们按照左边界排序的
                result.back()[1] = max(result.back()[1], intervals[i][1]); 
            } else {
                result.push_back(intervals[i]); // 区间不重叠 
            }
        }
        return result;
    }
};

738.单调递增的数字

这道题,我们可以很容易的写出暴力代码。从题目所给num开始,不断的判断num-1 ~ 0,之间的每一个数字是否是单调递增(用/10 取余10的方法)。显然这样的时间复杂度是O(n*m) n为num的最大取值范围, m为num的最大位数。

代码如下:

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;
    }
};

在题目所给的数据量下, 这样的程序会超时。

那现在我们来考虑如何进行贪心呢,首先由于题目所给的是int类型的数字,这种数字不方便我们去遍历访问他的每一位以及后续的修改操作,所以这里,我们考虑将其先转换为string类型。然后,我们来看一下,如果是“233”这个例子,我们会发现它对应的最大递增是“229",并且对于"231",按照题目的要求,它对应的也是"229"。也就是说,我们只要发现了存在strNum[i-1] >= strNum[i]时,就可以把strNum[i-1]–,而后面所有位变成’9’,这就是一个局部最优,而这样的局部最优显然它叠加起来就是全局最优。

但是这一题的遍历顺序有很大的讲究,如果我们选择从前向后遍历的话:

会写出这样的代码:

class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        int flag = strNum.size();
        for (int i = 1; i <= strNum.size()-1; i++) {
            if (strNum[i - 1] >= strNum[i] ) {
                flag = i;
                strNum[i - 1]--;
                break;
            }
        }
        for (int i = flag; i < strNum.size(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};

这样看似逻辑正确对吗?但是提交到leetcode的发生这样的问题

因为如果我们从前向后遍历的话,先处理高位,就直接忽视了后面所有低位的情况,这样做出来的序列显然不是最大的递增序列。

现在我们考虑从后向前的考虑,这样我们能考虑到每一位的递增关系,并且确保它的局部最优叠加的总和是全局最优。

代码如下:

class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(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);
    }
};

968.监控二叉树 (可跳过)

这道监督二叉树相当复杂,二刷再详细写解吧。

大家可以观看视频理解贪心算法,二叉树与贪心的结合,有点难… LeetCode:968.监督二叉树

相关文章:

  • 蓝桥杯 web 常用到的一些知识点
  • 最新的es版本忘记密码,重置密码
  • Spring Boot 中集成 Disruptor_高性能事件处理框架
  • 【大模型理论篇】DeepResearcher论文分析-通过在真实环境中的强化学习实现深度研究
  • 《Uniapp-Vue 3-TS 实战开发》Pinia 及 Pinia 持久化
  • 深度解析基于 Web Search MCP的Deep Research 实现逻辑
  • Facebook账号类型一览
  • 统一功能处理
  • 《Vue Router实战教程》7.编程式导航
  • Java中工厂模式和抽象工厂模式的区别
  • 搜广推校招面经七十二
  • DeepSeek:穿透行业知识壁垒的搜索引擎攻防战
  • 基于神经环路的神经调控可增强遗忘型轻度认知障碍患者的延迟回忆能力
  • 第十七天 - Jenkins API集成 - 流水线自动化 - 练习:CI/CD流程优化
  • 展讯android15源码编译之apk单编
  • JavaWeb 课堂笔记 —— 08 请求响应
  • 蓝桥杯 Web 方向入门指南:从基础到实战
  • tauri2 程序如何拿到启动参数?例如-toen
  • Express中间件(Middleware)详解:从零开始掌握(3)
  • Go:程序结构
  • 湘西网站建设/谷歌关键词热度查询
  • 网站备案 换域名/推广引流吸引人的标题
  • 做网站优化有什么作用/今日军事头条新闻
  • 个人资料展示网站/安卓嗅探app视频真实地址
  • 济南市高新技术官方网站开发区/简述seo和sem的区别与联系
  • c#做asp.net网站/企业培训课程种类