[LeetCode] 452. Minimum Number of Arrows to Burst Balloons 解题报告

There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter and hence the x-coordinates of start and end of the diameter suffice. Start is always smaller than end. There will be at most 104 balloons.

An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be shot to burst all balloons.

Example:

Input:
[[10,16], [2,8], [1,6], [7,12]]

Output:
2

Explanation:
One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).

这个题目是medium难度,还是需要思考一下的,但是很快就可以想到用贪心算法做。(我一开始把题目看错了,我以为arrow是随便射的,那就是问这些点最多能练成多少条线,这就复杂了,需要对斜率进行排序,特别麻烦。
思路:

我们将前一个数字称为a,后一个数字称为b。按升序,先按a进行排序,相同的情况再按b进行排序。事实上,我们的目标是让一个arrow穿过更多的balloon就可以了(局部最优->全局最优),这个arrow可以穿过的从第i个到第j个ballon可以表示为,min(balloon[i-j][1])>=ballon[j][0],以此类推直到遍历结束。可以用下面这个示意图表示这个思想,不过需要注意的是,可能会出现后面的balloon的end比前面的end要小的情况,所以上面用的是范围内end的最小值。

[LeetCode] 452. Minimum Number of Arrows to Burst Balloons 解题报告_第1张图片

如果想要说明贪心算法得到的确实是最优解,可以用反证法来思考。假设,当前是最优解,我们需要找到下一条arrow的位置,按照上面的方法找到一个位置。假如这个新位置不是最优解,那么需要将这个arrow左移或者右移,但是无论左移还是右移,都会漏掉至少一个balloon,那么都会至少多一支箭,那么肯定也不是最优解。

代码如下,复杂度为O(nlogn)+O(n)=O(nlogn)

public class Solution {
	public int findMinArrowShots(int[][] points) {
		Arrays.sort(points, new Comparator() {
			@Override
			public int compare(int[] o1, int[] o2) {
				if (o1[0] != o2[0]) {
					return o1[0] - o2[0];
				} else {
					return o1[1] - o2[1];
				}
			}
		});
		if (points.length < 1) {
			return 0;
		}
		int nArrow = 0;
		int nLimit = points[0][1];
		for (int i = 1; i < points.length; i++) {
			if (points[i][0] <= nLimit) {
				nLimit = Math.min(points[i][1], nLimit);
			} else {
				nArrow++;
				nLimit = points[i][1];
			}
		}
		return nArrow + 1;
	}

}


你可能感兴趣的:(LeetCode)