56. 合并区间,738.单调递增的数字

简介: **简介:**本文介绍了两道经典的算法题及其解法,分别是“合并区间”和“单调递增的数字”。 - **合并区间**:通过排序与遍历,将重叠的区间合并为不重叠的区间集合。核心思想是按区间左边界排序,判断当前区间的左边界是否小于等于前一区间的右边界,若满足则更新右边界。时间复杂度为O(nlogn)。- **单调递增的数字**:使用贪心算法解决,从后向前遍历数字字符串,遇到非单调递增的情况时,将前一位减1,并将后续位全部置为9,以确保结果最大且满足单调性。此方法高效且易于实现。两题均通过清晰的逻辑与代码示例展示了算法设计思路,适合初学者理解排序、贪心等基础算法的应用场景。

 题目:56. 合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]

输出:[[1,6],[8,10],[15,18]]

解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]

输出:[[1,5]]

解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示:

1 <= intervals.length <= 104

intervals[i].length == 2

0 <= starti <= endi <= 104

思考历程与知识点:  

本题的本质其实还是判断重叠区间问题。

发现和我们刚刚讲过的452. 用最少数量的箭引爆气球 (opens new window)和 435. 无重叠区间 (opens new window)都是一个套路。

这几道题都是判断区间重叠,区别就是判断区间重叠后的逻辑,本题是判断区间重贴后要进行区间合并。

所以一样的套路,先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。

按照左边界从小到大排序之后,如果 intervals[i][0] <= intervals[i - 1][1] 即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴,所以是<=)

题解:

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. 单调递增的数字

当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。

示例 1:

输入: n = 10

输出: 9

示例 2:

输入: n = 1234

输出: 1234

示例 3:

输入: n = 332

输出: 299

提示:

0 <= n <= 109

思考历程与知识点:  

题目要求小于等于N的最大单调递增的整数,那么拿一个两位的数字来举例。

例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。

这一点如果想清楚了,这道题就好办了。

此时是从前向后遍历还是从后向前遍历呢?

从前向后遍历的话,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]。

这么说有点抽象,举个例子,数字:332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。

那么从后向前遍历,就可以重复利用上次比较得出的结果了,从后向前遍历332的数值变化为:332 -> 329 -> 299

确定了遍历顺序之后,那么此时局部最优就可以推出全局,找不出反例,试试贪心。

题解:

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


相关文章
|
6月前
|
算法 开发者 容器
239. 滑动窗口最大值,347.前 K 个高频元素
**简介:** 本文介绍了两道经典算法题的解法与思路。第一题“滑动窗口最大值”通过单调队列实现高效求解,避免了暴力方法的时间复杂度问题,利用双端队列维护窗口内的最大值。第二题“前 K 个高频元素”则结合哈希表统计频率与优先级队列(小顶堆)进行排序,筛选出频率最高的元素。两者均展示了数据结构在优化算法性能中的重要作用,适合学习滑动窗口与堆排序相关知识的开发者参考。
|
6月前
|
机器学习/深度学习 算法
332.重新安排行程 , 51. N皇后 ,37. 解数独
本文介绍了三道经典的回溯算法问题及其解决方案。第一题“重新安排行程”要求根据给定的航班列表,从 JFK 出发规划行程,并按字典序返回最小的行程组合。通过构建映射关系并使用深度优先搜索(DFS)与回溯法解决 第二题“N 皇后”探讨如何在 n×n 的棋盘上放置 n 个皇后,使彼此不互相攻击。采用递归和剪枝技术验证每一步的合法性,确保行、列及对角线无冲突。 第三题“解数独”需填充空格以满足数独规则:每行、每列及每个 3x3 宫内的数字 1-9 不重复。利用双重循环遍历棋盘,递归尝试每个空格的可能数字,结合有效性检查完成求解。 以上题目均通过回溯法实现,体现了该算法在复杂约束条件下的强大适用性。
39. 组合总和,40.组合总和II,131.分割回文串
1. **组合总和**(LeetCode 39):从无重复元素的整数数组中选取任意数量的数字,使其和等于目标值。允许重复选取同一数字,通过递归与回溯实现。 2. **组合总和 II**(LeetCode 40):在含有重复元素的数组中选取数字,满足和为目标值,每个数字只能使用一次,需去重。 3. **分割回文串**(LeetCode 131):将字符串分割为多个子串,要求每个子串都是回文串,返回所有可能的分割方案。 代码实现中运用了深度优先搜索(DFS)、回溯法以及剪枝技巧,确保高效解决问题。
|
6月前
|
机器学习/深度学习 算法 NoSQL
344.反转字符串, 541. 反转字符串II,剑指Offer 05.替换空格,151.翻转字符串里的单词
1. **344. 反转字符串**:通过双指针法实现字符串的原地反转,时间复杂度为O(n),空间复杂度为O(1)。 2. **541. 反转字符串 II**:在特定规则下对字符串进行部分反转,需注意边界条件处理。 3. **剑指 Offer 05. 替换空格**:将字符串中的空格替换为"%20",采用双指针从后向前填充以节省空间。 4. **151. 反转字符串中的单词**:先去除多余空格,再整体反转和局部反转单词,最终实现单词顺序颠倒的效果。
|
Java 测试技术 容器
Spring框架-ObjectProvider更加宽泛的依赖注入
从上面的过程中我们可以看出,但Spring中某个Bean的依赖类型为ObjectProvider时,我们不需要提供一个ObjectProvider类型的Bean到容器中,只需要提供一个T类型的Bean到容器中,容器会自动将其包装成一个ObjectProvider,然后注入到依赖中
428 0
|
6月前
|
安全 网络安全 网络虚拟化
配置总部采用冗余网关与分支建立IPSec隧道示例
本文介绍了企业总部与分支间通过公网通信的组网需求及配置思路。为提高可靠性,分支网关AR5可接入两台总部网关(AR2和AR3),并建立IPSec隧道保障通信安全。配置步骤包括:1) 配置接口IP地址与静态路由;2) 定义ACL保护数据流;3) 创建IPSec安全提议;4) 配置IKE对等体;5) 创建安全策略;6) 在接口应用安全策略组。最终通过ping测试与查看隧道状态验证配置结果,确保流量安全传输。
配置总部采用冗余网关与分支建立IPSec隧道示例
|
6月前
|
XML 缓存 Java
一文讲透程序编排的核心方式:从表达式语言到并行化实践
高德的poi数据来源多种多样,处理流程也多种多样,但因流程相对固定,因此使用了流程化配置简化开发,使用表达式语言保证灵活性。为了加深对平台的理解,并帮助大家对编排有一定的了解,本文会以影响范围的视角去总结当前编排的方案。
339 13
一文讲透程序编排的核心方式:从表达式语言到并行化实践
|
8月前
|
算法 Go
【LeetCode 热题100】55:跳跃游戏(详细解析)(Go语言版)
本篇解析详细讲解了 LeetCode 热题 55——跳跃游戏(Jump Game)。通过判断是否能从数组起点跳至终点,介绍了两种高效解法:贪心算法和反向思维。贪心法通过维护最远可达位置 `maxReach` 实现一次遍历,时间复杂度 O(n),空间复杂度 O(1);反向法则从终点回溯,判断是否可到达起点。两者均简洁高效,适合面试使用。延伸题目如 LeetCode 45 进一步提升挑战。
249 7
|
人工智能 自然语言处理 程序员
AI战略丨拓展智能边界,大模型体系全面升级
阿里云在基础模型体系和生态、模型工程化落地路径、端云协同解决方案等多维度上都在快速迭代。
|
6月前
|
IDE 开发工具 Python
lingma IDE无法使用很多微软官方插件,代码无法点击跳转
当前环境存在以下问题:1. 无法使用微软官方插件 IntelliCode,影响代码智能补全与开发效率;2. 代码中变量点击后无法跳转定义位置(如图所示,Python导入模块无法跳转),此为重大缺陷,请尽快修复,以提升开发体验。这些问题导致的功能缺失,使当前环境与理想开发需求存在一定差距。