代码随想录算法训练营:30/60
非科班学习算法day30 | LeetCode452:用最少数量的箭引爆气球 ,Leetcode435:无重叠区间 ,Leetcode763:划分字母区间
介绍
包含LC的两道题目,还有相应概念的补充。
相关图解和更多版本:
代码随想录 (programmercarl.com)https://programmercarl.com/#%E6%9C%AC%E7%AB%99%E8%83%8C%E6%99%AF
二、LeetCode题目
1.LeetCode452:用最少数量的箭引爆气球
题目链接:452. 用最少数量的箭引爆气球 - 力扣(LeetCode)
题目解析
越来越理解贪心的想法了,实际上还是找到“个例”,然后推广到全部的情况,就是数学归纳法,只不过我们没有严格证明,所以我们的解法在跑案例的时候可能会卡住
这道题最主要的思路就是把射箭问题抽象成处理区间重叠问题,画图可以看出来,在对数组排序的情况下,重叠的数组都可以用一下打中,当没有重叠的时候就要再找一只箭。
这里面首先我们需要直到什么叫没有重叠,那就是后面区间的左端点小于前一个区间的右端点,那么这两个区间必有交集。
同时排序是非常常见的处理,如果数据无从处理应该想到能不能先有序化。
c++代码如下:
class Solution {
public:
// 对数组内部升序排列-按照左区间
static bool cmp(vector<int>& a, vector<int>& b)
{
return a[0] < b[0];
}
int arr = 1;
int findMinArrowShots(vector<vector<int>>& points) {
// 异常处理
if (!points.size())
return 0;
// 排序
sort(points.begin(), points.end(), cmp);
for (int i = 1; i < points.size(); i++) {
if (points[i][0] > points[i - 1][1]) {
// 下一只箭(重叠区间)
arr++;
}
// 重叠区间处理
else {
points[i][1] = min(points[i - 1][1], points[i][1]);
}
}
return arr;
}
};
这里再给出一个对原区间除了排序就没有其他修改操作的写法:
class Solution {
public:
// 对数组内部升序排列-按照左区间
static bool cmp(vector<int>& a, vector<int>& b)
{
return a[0] < b[0];
}
int arr = 1;
int findMinArrowShots(vector<vector<int>>& points) {
// 异常处理
if (!points.size())
return 0;
// 排序
sort(points.begin(), points.end(), cmp);
//新建一个cur区间
vector<int> cur = points[0];
for (int i = 1; i < points.size(); i++) {
if (points[i][0] > cur[1]) {
// 下一只箭(重叠区间)
arr++;
cur = points[i];
}
// 重叠区间处理
else
{
cur[1] = min(points[i][1], cur[1]);
}
}
return arr;
}
};
注意点:这个写法是新建了一个cur区间作为判断重叠区间的依据。在维护的过程中,如果没有公共交集了,那么要将cur的左区间重置为当前元素的左区间,其他情况则关注右区间就可以。
2.Leetcode435:无重叠区间
题目链接:435. 无重叠区间 - 力扣(LeetCode)
题目解析
和之前的处理方式基本相同,需要注意的就是这里等号的处理,是不属于重叠区间的。
C++代码如下:
class Solution {
public:
//依旧升序排列
static bool cmp(vector<int>& a, vector<int>& b)
{
return a[0]<b[0];
}
int res = 0;
int eraseOverlapIntervals(vector<vector<int>>& intervals)
{
if(!intervals.size()) return 0;
sort(intervals.begin(), intervals.end(), cmp);
for(int i = 1; i<intervals.size();i++)
{
if(intervals[i][0]<intervals[i - 1][1])
{
res++;
intervals[i][1] = min(intervals[i][1], intervals[i - 1][1]);
}
}
return res;
}
};
3.Leetcode763:划分字母区间
题目链接:763. 划分字母区间 - 力扣(LeetCode)
题目解析
本质上是区间的合并,思路有点巧妙(邪门),首先遍历一遍,用哈希表记录当前元素在字符串中出现的最大位置。
如果我们想切分字符串,我们要保证,该字符串内所有元素都出现在被截取之后的字符串中。所以我们继续遍历,不断更新我们需要覆盖的右区间端点。
直到!找到下标和右区间端点一样的位置,这里需要理解就相当于找到了最短的一次切分距离,可以进行记录。
C++代码如下:
class Solution {
public:
vector<int> partitionLabels(string s)
{
//创建哈希表记录字母出现的最后位置
int hash[26] = {0};
for(int i = 0; i<s.size(); ++i)
{
hash[s[i] - 'a'] = i; //实时更新
}
vector<int> res;
int start = 0;
int end = 0;
for(int i = 0; i<s.size(); ++i)
{
//合并区间
end = max(end, hash[s[i] - 'a']);
if(end == i)
{
res.push_back(end - start +1);
start = i+1;
}
}
return res;
}
};
注意点1:说贪也贪,说不贪就纯模拟。需要学会的除了思路就是怎么将字符的相对位置表示。
总结
打卡第30天,坚持!!!
上一篇: [ctf]命令执行漏洞 (I)
下一篇: PHP 代码/命令执行漏洞概述
推荐阅读
-
代码随机化算法训练营第 15 天|第 15 天 二叉树
-
代码随想录算法训练营第五十八天| 110.字符串接龙,105.有向图的完全可达性,106.岛屿的周长-105.卡码网有向图的完全可达性
-
代码随机化算法训练营第 50 天
-
[代码随机化第 30 天] 贪婪算法第 04 部分
-
代码随机化算法训练营 | 235. 二进制搜索树的最近共同祖先, 701. 二进制搜索树中的插入操作, 450. 二进制搜索树中删除节点
-
代码随机化算法训练营第 41-2 天。买卖股票的最佳时机 II
-
代码随机化算法训练营第 32 天
-
代码随想录算法训练营第三十天 | 01背包问题 二维 01背包问题 一维 416. 分割等和子集
-
代码随想录算法训练营:30/60
-
Studying-代码随想录训练营day34| 62.不同路径、63.不同路径II、343.整数拆分、96.不同的二叉搜索树