数组与贪心算法——452、435、646、406、169(1简4中)

452. 用最少数量的箭引爆气球(中等)

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstartxend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 x``startx``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
相关推荐
飞升不如收破烂~12 分钟前
redis的map底层数据结构 分别什么时候使用哈希表(Hash Table)和压缩列表(ZipList)
算法·哈希算法
九圣残炎16 分钟前
【从零开始的LeetCode-算法】3354. 使数组元素等于零
java·算法·leetcode
程序猿小柒1 小时前
leetcode hot100【LeetCode 4.寻找两个正序数组的中位数】java实现
java·算法·leetcode
雨中rain1 小时前
贪心算法(1)
算法·贪心算法
不爱学习的YY酱2 小时前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
平头哥在等你2 小时前
求一个3*3矩阵对角线元素之和
c语言·算法·矩阵
飞滕人生TYF2 小时前
动态规划 详解
算法·动态规划
_OLi_2 小时前
力扣 LeetCode 106. 从中序与后序遍历序列构造二叉树(Day9:二叉树)
数据结构·算法·leetcode
ahadee2 小时前
蓝桥杯每日真题 - 第18天
c语言·vscode·算法·蓝桥杯
地平线开发者3 小时前
CPU& 内存加压工具 stress-ng 介绍
算法·自动驾驶