452.用最少数量的箭引爆气球
有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points
,其中points[i] = [xstart, xend]
表示水平直径在 xstart
和 xend
之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x
处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart
,xend
, 且满足 xstart ≤ x ≤ xend
,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points
,返回引爆所有气球所必须射出的 最小 弓箭数 。
示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。
示例 2:
输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。
示例 3:
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:
- 在x = 2处发射箭,击破气球[1,2]和[2,3]。
- 在x = 4处射出箭,击破气球[3,4]和[4,5]。
提示:
1 <= points.length <= 105
points[i].length == 2
-2^31 <= xstart < xend <= 2^31 - 1
思路:
这道题的思路很好想出来,我们先把这个数组按照第二位元素的大小进行从小到大的排序,然后用最小的第二位元素去跟下一个数组的第一位元素进行比较大小,如果这个元素大了,那么我们就换掉末尾变量,最后得到答案。但是值得注意的是,compare函数有可能会超出整型限制,所以要进行像下面这样的修改先比较结束位置 p1[1]
和 p2[1]
,如果它们不同,直接返回比较结果。如果结束位置相同,再比较起始位置 p1[0]
和 p2[0]
。避免了int整型溢出。
解答:
int compare(const void* a, const void* b) {
int* p1 = *(int**)a;
int* p2 = *(int**)b;
if (p1[1] < p2[1]) {
return -1;
} else if (p1[1] > p2[1]) {
return 1;
}
if (p1[0] < p2[0]) {
return -1;
} else if (p1[0] > p2[0]) {
return 1;
}
return 0;
}
int findMinArrowShots(int** points, int pointsSize, int* pointsColSize) {
if(pointsSize == 0)return 0;
qsort(points,pointsSize,sizeof(int*),compare);
int sum = 1;
int end = points[0][1];
for(int i = 1;i < pointsSize;i++)
{
if(points[i][0] > end)
{
sum++;
end = points[i][1];
}
}
return sum;
}
435.无重叠区间
给定一个区间的集合 intervals
,其中 intervals[i] = [starti, endi]
。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
注意 只在一点上接触的区间是 不重叠的。例如 [1, 2]
和 [2, 3]
是不重叠的。
示例 1:
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
提示:
1 <= intervals.length <= 10^5
intervals[i].length == 2
-5 * 10^4 <= starti < endi <= 5 * 10^4
思路:
这道题的思路跟上一道题的思路很像,都是在找重叠区间,只不过这一次只要找到一个重叠区间,我们的统计数就加上1,当不是重叠区间时,我们就移动end,让他到达下一个数组的第二个元素的位置,最后直接返回答案。
解答:
int compare(const void* a,const void* b)
{
int* p1 = *(int**)a;
int* p2 = *(int**)b;
return p1[1] - p2[1];
}
int eraseOverlapIntervals(int** intervals, int intervalsSize, int* intervalsColSize) {
if(intervalsSize == 0)return 0;
qsort(intervals,intervalsSize,sizeof(int*),compare);
int remove = 0;
int end = intervals[0][1];
for(int i = 1; i < intervalsSize;i++)
{
if(end > intervals[i][0])
{
remove++;
}
else
{
end = intervals[i][1];
}
}
return remove;
}
763.划分字母区间
给你一个字符串 s
。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s
。
返回一个表示每个字符串片段的长度的列表。
示例 1:
输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
示例 2:
输入:s = "eccbbbbdec"
输出:[10]
提示:
1 <= s.length <= 500
s
仅由小写英文字母组成
思路:
这个就需要存储相应的元素位置,因为是二十六个字母,创建一个数组,用来存放它们的最终位置,然后我们开始划分字符串,我们先找字符串的最终位置最远的,在找的过程中如果我们发现最终位置与所找的最远位置相等时,也就是说当这个到达最大距离时的最后一个字符刚好是这个字符,这是一个划分字符串的位置,然后把这个位置放进数组中,最后返回最终答案就行了。
解答:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* partitionLabels(char* s, int* returnSize) {
int position[26] = {0};
int length = strlen(s);
for(int i = 0;i < length;i++)
{
position[s[i]-'a'] = i;
}
int start = 0;
int end = 0;
int* result = malloc(sizeof(int)*length);
*returnSize = 0;
for(int i = 0;i < length;i++)
{
end = (end > position[s[i]-'a']) ? end : position[s[i]-'a'];
if(i == end)
{
result[(*returnSize)++] = i - start + 1;
start = i + 1;
}
}
return result;
}
反思
今天的题目最后一道题需要思考,前两道题都还是比较好做的,但是贪心的思想总感觉有时候想不到,也许多做点题目会有些感觉。