代码随想录算法训练营第三十四天 | 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球

24 阅读2分钟

860. 柠檬水找零

链接

文章链接

题目链接

第一想法

返回false就两种情况,要不是10元不够,要不就是5元不够,所以每次交易完查看5元和10元的数量是否大于等于0就可以了

function lemonadeChange(bills: number[]): boolean {
    let num: number[] = [0, 0, 0]//5 10 20元张数
    for (let i = 0; i < bills.length; i++) {
        if (bills[i] == 5) num[0]++ //5元张数增加
        if (bills[i] == 10) {
            num[0]-- //5元张数减少
            num[1]++ //10元张数增加
        }
        if (bills[i] == 20) { //20元有一点复杂 因为有两种情况 第一种是找一张10元和一张5元,第二种是找3张5元
            if (num[1] > 0) num[1]--
            else num[0] -= 2
            num[0]--
            num[2]++
        }
        if (num[0] < 0 || num[1] < 0) return false
    }
    return true
};

看完文章后的想法

文章的想法和我的类似,所以这里就不复制代码了,贪心就在于一点,就是如果20元找零的话,优先找10元和5元的,因为5元比10元更万能

思考

这道题比较简单,主要的思想就是先找10元的再找5元的,贪心在于5元更万能.这道题算是试试水.

406. 根据身高重建队列

链接

文章链接

题目链接

第一想法

不会,想法是先按照k排序的同时按照h排序,排序后之后每一个元素插入数组中,但是结果不对.

看完文章的想法

没想到,我认为是先按照k排序的同时按照h排序,结果是一个也确定不了的,但是先安装h降序排列的同时按照k升序排列,则身高一定是从大到小排列的,每一个按照k直接插入现有的数组就行了,例如这张图:

image.png 代码如下:

function reconstructQueue(people: number[][]): number[][] {
    let res: number[][] = []
    people.sort((a, b) => (b[0] - a[0]) ? (b[0] - a[0]) : (a[1] - b[1]))//排序
    for (let i = 0; i < people.length; i++) {
        res.splice(people[i][1], 0, people[i])//按照k插入
    }
    return res
};

思考

这道题确实是没想到,也想少了,只是想到了利用k来进行排序,就一直按照k来想解法,结果想不出来.没想到用h先把身高拍好后就会发现很简单,没想到,是我自己陷入漩涡了

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

链接

文章链接

题目链接

第一想法

想法是让区间相近的先合并区间,之后看看有几个独立的区间就是需要几只箭,详细注释在代码中

function findMinArrowShots(points: number[][]): number {
    let arr: number[][] = [] //存储合并后的区间
    points.sort((a, b) => a[0] - b[0])//排序 用于让  区间开始 相近的在一起
    for (let i = 0; i < points.length; i++) {
        let boo: boolean = true //用于判断是否是新的区间
        for (let j = 0; j < arr.length; j++) {
            if (arr[j][0] <= points[i][0] && arr[j][1] >= points[i][0] || arr[j][1] >= points[i][1] && arr[j][0] <= points[i][1]) { //加上&&的原因是防止出现[1,2]和[4,5]合并的情况
                arr[j][0] = arr[j][0] <= points[i][0] ? points[i][0] : arr[j][0]//合并开始区间
                arr[j][1] = arr[j][1] >= points[i][1] ? points[i][1] : arr[j][1]//合并结束区间
                boo = false
                break
            }
        }
        if (boo) arr.push(points[i].slice()) //没有合并的区间就新增加一个可以合并的区间
    }
    return arr.length
};

看完文章的想法

文章的想法比我自己的要简单,排序也是和我一样进行排序的,用于让数组尽可能的重叠,但是我是维护了左右两个边界,但是文章维护右边界就可以了,例如这张图:

image.png 例如气球1和2 如果想要一下射到1和2那么右边界最右为6,而气球3的左边界大于1和2气球的公共最右区间,所以3开始要一个新的箭来射,代码如下:

function findMinArrowShots(points: number[][]): number {
    let res: number = 1
    points.sort((a, b) => a[0] - b[0])
    for (let i = 1; i < points.length; i++) {
        if (points[i][0] > points[i - 1][1]) res++ //左边界超过前一个的右边界则箭数加一
        else points[i][1] = Math.min(points[i][1], points[i - 1][1]) //没超过则把当前右边界变为当前右边界和前一个的右边界的最小值
    }
    return res
};

思考

这应该是我第一次遇到重叠区间的题,虽然自己做出来了,但是想法还是不够完全成熟,看完文章后想法用到右边界就可以了,代码比我自己写的精简了许多.

今日总结

今日耗时2.5小时,第二题没做出来,陷入自己的思维出不来了,一三题还好,虽然代码写的不精简,但是也靠自己做出来了.