【用最少数量的箭引爆气球】

在这里插入图片描述

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8][1,6]。
-在x = 11处发射箭,击破气球[10,16][7,12]
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:
- 在x = 2处发射箭,击破气球[1,2][2,3]。
- 在x = 4处射出箭,击破气球[3,4][4,5]

一、解题思路:

想用最少的箭引爆所有气球,那么理论上尽可能把有重合区间的气球攒起来,用一箭解决,而没办法攒到一起的,只能把之前攒的先消耗一只箭解决了,再额外用箭解决新攒的。

为了方便攒气球,需要排序,可以左端/右端,本文选择左端。

[[10,16],[2,8],[1,6],[7,12]]
排序后得到
[[1,6],[2,8],[7,12],[10,16]]

排序后二维数组

[1............6]
     [2...............8]
                  [7.............12]
 	                      [10...........16]

使用一个变量pos存放箭将会射出的位置,对于第一个气球[1,6]而言,为了引爆更多的气球,pos设置为Xend为6肯定比Xstart的1要好,初始消耗cnt=1箭,接下来从第二个开始遍历气球,通过修改箭射出的位置来减少箭的使用数量:

(1)当前气球Xstart<=pos,则当前箭可以引爆当前气球,把当前气球攒起来,因为当前箭需要引爆攒起来的气球,那么pos需要更新为min(pos,Xend),如第二个气球[2,8]和第一个[1,6]攒在一起,那么箭为了引爆之前攒起来的气球[1,6],同时为了以后尽可能可以攒更多的气球,pos应该设置为6,因为6是可以引爆气球1的最大值了,这样才可以在引爆之前气球的情况下,尽可能攒更多的气球。

(2)当前气球Xstart>pos,则当前箭够不着、无法引爆当前气球,则需要把之前攒起来的气球用当前箭消耗掉,再从当前气球开始重新攒气球,则pos=Xend,并且cnt++。
最后得到的cnt就是最少的箭使用数量,而在编码中,pos可以节约掉,将箭的位置通过修改前一个气球的Xend来记录。

二、代码实现

public class Test3 {
    public static void main(String[] args) {
        // 满足xstart ≤ x ≤ xend,最少数量引爆气球
        // int[][] points = {{10, 16}, {2, 8}, {1, 6}, {7, 12}};
        // int[][] points = {{1,2},{3,4},{5,6},{7,8}};
        int[][] points = {{1,2},{2,3},{3,4},{4,5}};
        System.out.println(finNums(points));
    }

    public static int finNums(int[][] points) {
        if (points.length == 0) {
            // 原点
            return 0;
        }

        // 最右区间排序,升序
        Arrays.sort(points, (o1, o2) -> {
            if (o1[1] > o2[1]) {
                return 1;
            } else if (o1[1] < o2[1]) {
                return -1;
            } else {
                return 0;
            }
        });

        // initPosition 初始位置,记录当前射击的右边界值
        // 第一根箭的右边界是points[0][1] 只要后续气球的左边界 <= tmp 则这根箭可以射中它
        int initPosition = points[0][1];
        int result = 1;
        for (int[] tempPoints : points) {
            // 如果当前气球的左边界已经大于箭的右边界,则需要新的一根箭
            // 箭的数量+1 , initPosition 更新为新的一根箭的右边界
            if (tempPoints[0] > initPosition) {
                initPosition = tempPoints[1];
                result ++;
            }
        }
        return result;
    }
}

参考文章
https://www.cnblogs.com/lanpang9661/p/13094662.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值