452. 用最少数量的箭引爆气球(中等)
有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组
points
,其中points[i] = [xstart, xend]
表示水平直径在xstart
和xend
之间的气球。你不知道气球的确切 y 坐标。一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标
x
处射出一支箭,若有一个气球的直径的开始和结束坐标为x``start
,x``end
, 且满足xstart ≤ x ≤ x``end
,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。给你一个数组
points
,返回引爆所有气球所必须射出的 最小 弓箭数。
解法一、贪心
其实就是取交集的问题。如果当前区间左边界超过原有区间右边界,更新区间,加一支箭。
顺便吐槽下[[-2147483646,-2147483645],[2147483646,2147483647]]的用例是怎么想出来的wlfbb 直接溢出了导致排序错误
java
class Solution {
public static int findMinArrowShots(int[][] points) {
if(points.length == 1)return 1;
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return (o1[1] > 0 && o2[1] < 0)? 1 : o1[1] - o2[1];
}
});
int pre = points[0][1],ans = 1;
for(int i = 1;i < points.length;i++){
if(points[i][0] > pre){
ans++;
pre = points[i][1];
}
}
return ans;
}
}
435. 无重叠区间(中等)
给定一个区间的集合
intervals
,其中intervals[i] = [starti, endi]
。返回 需要移除区间的最小数量,使剩余区间互不重叠。
解法一、贪心
对右区间排序,然后占了就删,不占就更新
java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length == 1)return 0;
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
int pre = intervals[0][1];
int ans = 0;
for(int i = 1;i < intervals.length;i++){
if(intervals[i][0] >= pre){
pre = intervals[i][1];
}else{
ans++;
}
}
return ans;
}
}
646. 最长数对链(中等)
给你一个由
n
个数对组成的数对数组pairs
,其中pairs[i] = [lefti, righti]
且lefti < righti
。现在,我们定义一种 跟随 关系,当且仅当
b < c
时,数对p2 = [c, d]
才可以跟在p1 = [a, b]
后面。我们用这种形式来构造 数对链 。找出并返回能够形成的 最长数对链的长度 。
你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
解法一、贪心
其实可以复制435的答案然后减一下。。435是数多少个重叠,删了重叠的,其余互不重叠就是646
java
class Solution {
public int findLongestChain(int[][] pairs) {
if(pairs.length == 1)return 1;
Arrays.sort(pairs, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
int r = pairs[0][1],ans = 0;
for(int i = 1;i < pairs.length;i++){
if(pairs[i][0] > r){
r = pairs[i][1];
}else{
ans++;
}
}
return pairs.length - ans;
}
}
406. 根据身高重建队列(中等)
假设有打乱顺序的一群人站成一个队列,数组
people
表示队列中一些人的属性(不一定按顺序)。每个people[i] = [hi, ki]
表示第i
个人的身高为hi
,前面 正好 有ki
个身高大于或等于hi
的人。请你重新构造并返回输入数组
people
所表示的队列。返回的队列应该格式化为数组queue
,其中queue[j] = [hj, kj]
是队列中第j
个人的属性(queue[0]
是排在队列前面的人)。
解法一、贪心
java
class Solution {
public int[][] reconstructQueue(int[][] people) {
Arrays.sort(people, new Comparator<int[]>() {
@Override
public int compare(int[] person1, int[] person2) {
if (person1[0] != person2[0]) {
return person1[0] - person2[0];
} else {
return person2[1] - person1[1];
}
}
});
int[][] res = new int[people.length][];
for(int i = 0;i<people.length;i++){
int space = people[i][1] + 1;
for(int j = 0;j < res.length;j++){
if(res[j] == null){
space--;
if(space == 0){
res[j] = people[i];
break;
}
}
}
}
return res;
}
}
优化后会发现space的讨论是多余的,所有排序已经在比较器时就完成了。也就是说,身高从高到低排列,如果同等高度的话,排前面人多的那个站在后面,然后直接遍历插入即可。
java
class Solution {
public int[][] reconstructQueue(int[][] people) {
Arrays.sort(people, new Comparator<int[]>() {
public int compare(int[] person1, int[] person2) {
if (person1[0] != person2[0]) {
return person2[0] - person1[0];
} else {
return person1[1] - person2[1];
}
}
});
List<int[]> ans = new ArrayList<int[]>();
for (int[] person : people) {
ans.add(person[1], person);
}
return ans.toArray(new int[ans.size()][]);
}
169. 多数元素(简单)
给定一个大小为
n
的数组nums
,返回其中的多数元素。多数元素是指在数组中出现次数 大于⌊ n/2 ⌋
的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。
解法一、哈希表
解法二、排序
java
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/majority-element/solutions/146074/duo-shu-yuan-su-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法三、随机
random的写法比较好玩 其实就是随机一个数然后数它到不到n/2
java
class Solution {
private int randRange(Random rand, int min, int max) {
return rand.nextInt(max - min) + min;
}
private int countOccurences(int[] nums, int num) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == num) {
count++;
}
}
return count;
}
public int majorityElement(int[] nums) {
Random rand = new Random();
int majorityCount = nums.length / 2;
while (true) {
int candidate = nums[randRange(rand, 0, nums.length)];
if (countOccurences(nums, candidate) > majorityCount) {
return candidate;
}
}
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/majority-element/solutions/146074/duo-shu-yuan-su-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法四、分治
每次统计一个小区间
java
class Solution {
private int countInRange(int[] nums, int num, int lo, int hi) {
int count = 0;
for (int i = lo; i <= hi; i++) {
if (nums[i] == num) {
count++;
}
}
return count;
}
private int majorityElementRec(int[] nums, int lo, int hi) {
// base case; the only element in an array of size 1 is the majority
// element.
if (lo == hi) {
return nums[lo];
}
// recurse on left and right halves of this slice.
int mid = (hi - lo) / 2 + lo;
int left = majorityElementRec(nums, lo, mid);
int right = majorityElementRec(nums, mid + 1, hi);
// if the two halves agree on the majority element, return it.
if (left == right) {
return left;
}
// otherwise, count each element and return the "winner".
int leftCount = countInRange(nums, left, lo, hi);
int rightCount = countInRange(nums, right, lo, hi);
return leftCount > rightCount ? left : right;
}
public int majorityElement(int[] nums) {
return majorityElementRec(nums, 0, nums.length - 1);
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/majority-element/solutions/146074/duo-shu-yuan-su-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法五、投票
这个真的还蛮有意思的。。
java
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
Integer candidate = null;
for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}
return candidate;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/majority-element/solutions/146074/duo-shu-yuan-su-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
碎碎念
- 452=取交集数量,435=减重叠,646=数重叠再减。 406其实还挺难,但是也考验比较器写法。感觉需要考虑题意,交集则靠右排序,右比左;并集则靠左排序,左比右。当然406这种更加灵活。感觉贪心类型的题,很多都相当于先排前x个,然后考虑x+1,直到x==n