452.用最少数量的箭引爆气球

2020-06-11
用最少数量的箭引爆气球

在二维空间中有许多球形的气球。对于每个气球,

提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,

所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。

开始坐标总是小于结束坐标。平面内最多存在10^4个气球。


一支弓箭可以沿着x轴从不同点完全垂直地射出。

在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend,

且满足  xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。

弓箭一旦被射出之后,可以无限地前进。

我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。。

题解:
思路1:贪心算法
/**
 * @param {number[][]} points
 * @return {number}
 */
var findMinArrowShots = function (points) {
  if (points.length <= 1) return points.length;
  // 首先将数组按照第一项的大小排序 第一项相等则按第二项大小排序
  points.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]);
  // count 需要的次数 如果气球大于1 则至少要一次
  // tmp 是记录当前射击的右边界值
  // 当遍历的每一项的左边界小于此次射击的右边界 则说明此次射击可以射中次气球
  
  let count = 1, tmp = points[0][1];
  for (let i = 1; i < points.length; i++) {
    if (points[i][0] > tmp) { // 如果当前项的左边界大于 tmp  说明此次射击不能够得着这个气球
      // 需要增加一次射击
      count++;
      // 增加一次射击后 tmp则为增加的这次射击的右边界了
      tmp = points[i][1];
    }
    else tmp = Math.min(tmp, points[i][1]); // 如果此次设计能射中当前气球
    // 右边界的大小需要取更小的一项
    // 例如 [1, 100] [2, 18] [28, 30]
    // 当遍历到[2, 18]时, 右边界原先是100 但是 [2,18] 这一项的右边界是 18 必须取更小的18
    // 如果不取18 保持100 那么当遍历到[28, 30]时, 也是满足当前项左边界28 小于 当前射击的右边界 100
    // 所以必须保证 当前射击的右边界tmp 取值是能射中项的最小的右边界 
  }
  return count;
};

 算法优化 上面是自己想的有点复杂了 有更简单的思路

var findMinArrowShots = function (points) {
  if (points.length <= 1) return points.length;
  points.sort((a, b) => a[1] - b[1]); // 按照每一个气球的右边界排序
  let count = 1, tmp = points[0][1]; // tmp 记录每一根箭的右边界
  // 第一根箭的右边界是points[0][1] 只要后续气球的左边界 <= tmp 则这根箭可以射中它
  for (let i = 1; i < points.length; i++) {
    // 如果当前气球的左边界已经大于箭的右边界 则需要新的一根箭
    // 箭的数量+1 tmp更新为新的一根箭的右边界
    if (points[i][0] > tmp) {
      count++;
      tmp = points[i][1];
    }
  }
  return count;
}
原文地址:https://www.cnblogs.com/lanpang9661/p/13094662.html