文章目录
- 56. 合并区间
- 解题思路
- c++实现
- 55. 跳跃游戏
- 解题思路
- c++ 实现
- 75. 颜色分类
- 解题思路
- c++ 实现
- 36 下一个排列
- 解题思路
- c++ 实现
56. 合并区间
题目: 以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并
所有重叠
的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例:
解题思路
-
首先利用
sort
对区间起点排序
-
每次取连续的区间查看是否相交,若相加合并。若无相交,由于按照起点排序,后面区间的起点更大,也就不可能再有相交的可能。
c++实现
class Solution {
public:vector<vector<int>> merge(vector<vector<int>>& intervals) {if (intervals.size() <2) return intervals;sort(intervals.begin(),intervals.end());vector<int> tmp = intervals[0];vector<vector<int>> ans;for(int i=1;i<intervals.size();i++){if (tmp[1]>=intervals[i][0]){// 合并区间tmp[0] = min(tmp[0],intervals[i][0]);tmp[1] = max(tmp[1],intervals[i][1]);// ans.push_back(tmp); //注意不要写这句}else{// 区间不相交,则将tmp放入答案// 然后tmp 等于当前元素ans.push_back(tmp);tmp = intervals[i];}}// 记得把最后一个区间放入答案ans.push_back(tmp);return ans;}
};
- 对比连续的两个区间,如果重叠则合并两个区间
- 如果区间不相交,则将前一个区间tmp加入答案中, 并更新tmp区间为当前元素
- 记得把最后一个区间放入答案
55. 跳跃游戏
题目: 给你一个非负整数数组
nums ,你最初位于数组的 第一个下标 。数组中的每个元素
代表你在该位置可以跳跃
的最大长度
。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false
。
示例:
解题思路
- 每次跳跃可到达的最远距离
canreach
,可用如下公式表示:
int currPos =0; // 假设当前位置为0
int canreach = currPos + nums[curPos];
- 第一次跳跃达到最远距离为canreach, 接着从第二个格子到canreach范围内跳跃,每次跳跃更新canreach的值,保存最大的canreach。
- 如果最大的canreach超出(≥)格子范围,则返回true, 否则返回false
参考: https://www.cnblogs.com/itdef/p/16675994.html
c++ 实现
class Solution {
public:bool canJump(vector<int>& nums) {int curPos =0;int canreach = curPos + nums[curPos];for(;curPos<canreach;curPos++){if (curPos>=nums.size()-1) return true;canreach = max(canreach,curPos + nums[curPos]);}if (canreach >= nums.size()-1) return true;return false;}
};
75. 颜色分类
题目: 给定一个包含红色
、白色
和蓝色
、共 n
个元素的数组 nums
,原地对它们进行排序,使得相同颜色
的元素相邻,并按照红色、白色、蓝色
顺序排列。
我们使用整数0、 1 和 2
分别表示红色、白色和蓝色
。
必须在不使用库内置的 sort
函数的情况下解决这个问题。
示例:
你能想出一个仅使用常数空间的一趟扫描算法吗?
解题思路
- 使用整数
0、 1 和 2
分别表示红色、白色和蓝色
, 也就是给我们一个由0,1,2
数字组成的数组,需要我们对其原地
进行排序
- 最基本最朴素的想法是使用如下
sort 排序
,很明显题目要求不能
使用库函数sort
来排序, 它的时间复杂度为nlog(n)
, 但题目要求一趟扫描算
,也就是实现O(n)
时间复杂度:
sort(nums.begin(),nums.end());
- 对题目分析可知,不管怎样排序,最终的结果都是:
所有为0元素
排在数组最左边
,所有为2元素
排在数组最右边
,剩下所有1排
在数组的中间
。 - 可以设置两个边界:
left和right
。 边界left的左边
全部为0
,边界right右边
为2, left 和right中间
部分全为1
- 可以通过
两次扫描
,第一次扫描
,将全部0元素
放在数组最左边,第二次扫描
将所有1元素
紧接着0元素放置,剩下的位置就是元素2
了
c++ 实现
class Solution {
public:void sortColors(vector<int>& nums) {int l=0,r=0;//(1) 将所有0元素 移动到数组最左边for(r=0;r<nums.size();r++){if (nums[r] ==0){swap(nums[r],nums[l]);l++;}}//(2) 将所有1元素,移动到所有0元素之后// 此时剩余的最右边的元素只有2了for(r=0;r<nums.size();r++){if (nums[r] ==1){swap(nums[r],nums[l]);l++;}}return ;}
};
- 使用
swap
函数来调换元素
,这样才能保证变换后素组中的元素是不变的
,只是顺序变换了
,切记不能使用=
后来调换,这样不光改变顺序,同时会改变nums
数组中的元素值,比如,如下错误写法:
for(r=0;r<nums.size();r++){if (nums[r] ==0){nums[l++] = nums[r] ;}}for(r=0;r<nums.size();r++){if (nums[r] ==1){nums[l++] = nums[r] ;}}
- 实现步骤(1)
将所有0元素 移动到数组最左边
, 使用swap
来调换顺序 - 实现步骤(2)
将所有1元素,移动到所有0元素之后
,使用swap
来调换顺序
36 下一个排列
题目: 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
- 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
- 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
- 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
- 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改
,只允许使用额外常数空间。
示例:
解题思路
下一个排序,简而言之,就是找到一个最接近的一个比它大的数
。通过观察规律可以发现:
- 从
右向左
找到第一个不符合升序
的数字, 然后与从右向左
找到第一个比它大
的数字进行交换
。 - 比如
1234
找到第一个不符合升序的数字3,3比4小,再从右向左找一个比它大的数字4进行交换,变成1243即可。 - 经过交换后数字比原来的数字排列大但未必是最接近的最小值,因为交换后右边数字是
降序排列
的,需要调整为升序排列
,这样才能保证得到的是一个最接近它
,比原来排列数字大的。 - 例如 13 4 2 找到第一个不符合升序数字3,再找到交换的数字4,变换为 14 3 2, 这时候 3比2要大,还需要对4右边的数字,升序排列,1 4 2 3才是正解
c++ 实现
class Solution {
public:void nextPermutation(vector<int>& nums) {int i=0;for (i= nums.size()-2;i>=0;i--){ //(1) 逆序查找,找到第一个不符合的(从右往左)升序数字if(nums[i]<nums[i+1]){//(2) 再逆序查找,第一个比刚才的数字大的数字,进行交换for(int j=nums.size()-1;j>i;j--){if (nums[j]>nums[i]){swap(nums[i],nums[j]);//reverse(nums.begin()+i+1,nums.end());//(3) 交换完之后,将两交换数字右边的数字升序排列sort(nums.begin()+i+1,nums.end());return;}}}}if (i<0){reverse(nums.begin(),nums.end());return;}}
};
- (1) 逆序查找,找到
第一个不符合的(从右往左)升序
数字 - (2) 再逆序查找,
第一个比刚才的数字大的数字
,进行交换(注意不是前后两个数字交换
), 比如:[1,3,2] ->[2,3,1]->[2,1,3]
- (3) 交换完之后,将两交换数字
右边的数字升序排列
- 此时找到了最接近的比它大的数字,记得马上就
return
; 否则还会继续交换,得不到正确的结果
- 此时找到了最接近的比它大的数字,记得马上就
- (4) 如果逆序遍历完,都没有发现不符合的升序数字,说明该数字排列本身就是最大的,此时根据题目要求需要返回最小的排列,使用
reverse
函数就可以实现。