「算法」LeetCode 605. 种花问题(JavaScript版)

老规矩,题目链接:https://leetcode-cn.com/problems/can-place-flowers/
这是一道简单题,解题最重要的部分就是抽象,将问题的解抽象为除法运算,求出两个1之间的0的个数,-1/2并向下取整就能得到这两个1之间可以种的花的数目,最后做判断,即为题解。
本人想到两种解法,基本原理类似,如果别的小伙伴还有更好的解决办法或是觉得我的方法不正确,欢迎大家在评论区提出来~

解法1:

export default (arr, n) => {
    let cnt = 0;
    let max = 0;
    let len = arr.length;
    // first中保存第一个1出现的下标
    let first = arr.indexOf(1);
    // last中保存最后一个1出现的下标
    let last = arr.lastIndexOf(1);
    // 核心算法:返回两个1之间可以种的花的数目
    let MAX = (sum) => {
        return Math.floor((sum - 1) / 2);
    }
    // 记录两个1之间0的个数并求可以种的花的数目,加到max中
    for (let i = first + 1; i < last + 1; i++) {
        if (arr[i] === 0) {
            cnt++;
        } else {
            max += MAX(cnt);
            cnt = 0;
        }
    }
    if (first === -1) {
    	// 若数组全为0,则可以种的花的数目直接由数组长度/2并向上取整
        max = Math.ceil(len / 2);
    } else {
    	// 若数组不全为0,则需要考虑开头和结尾可以种的花的数目,用开头和结尾的0的个数/2并向下取整,加到max中
        max += (Math.floor(first / 2) + Math.floor((len - 1 - last) / 2));
    }
    // 判断n是否小于或等于可种花的总数,是则返回true,否则返回false
    if (n <= max) {
        return true;
    } else {
        return false;
    }
}

解法1思路如下:
首先将数组arr头部和尾部的0全部去掉,只计算第一个1和最后一个1之间可以种的花的数目(至于为什么要这样做,因为头和尾的0只需要判断一边是否有1,而第一个1和最后一个1之间的0就需要判断两侧是否有1),然后就是一个纯数学问题,找规律,两个1之间连续3个0就能种1朵花,连续5个0就能种2朵……以此类推,发现连续0的个数/2然后向下取整就能得到这两个1之间可以种的花的数目,最后就能求得第一个1和最后一个1之间可以种的花的数目,然后再来计算首尾可以种的花的数目,求得总数max,与参数n做比较,如果n <= max则返回true,否则返回false,即为题解。

解法2:

export default (arr, n) => {
    let max = 0;
    // 向数组的首尾都添加一个0
    arr.unshift(0);
    arr.push(0);
    // 遍历整个数组
    for (let i = 1, len = arr.length; i < len - 1; i++) {
    	// 当下标为i的元素为0时,判断其左右两侧是否为0,是则计数器max++,且指针i++
        if (!arr[i]) {
            if (arr[i - 1] === 0 && arr[i + 1] === 0) {
                max++;
                // 这是一个缩短运行时长的方法,可有可无,不影响结果
                if (max === n) {
                    return true;
                }
                i++;
            }
        }
    }
    // 判断n是否小于或等于可种花的总数,是则返回true,否则返回false
    return n <= max ? true : false;
}

解法2思路如下:
先将数组的首尾都补上一个0方便后面使用同样的条件来判断是否可以种下一朵花,然后遍历整个数组,判断下标为i的元素是否为0且左右两侧是否也为0,是则计数器max++,且指针i++(为什么指针i还要自加一次?因为确定该元素和其左右两侧元素都为0后,右侧的0就不能再填1了),最后求得总数max,与参数n做比较,如果n <= max则返回true,否则返回false,即为题解。

小结:
这道题只要将问题成功抽象了,基本上就解出来了,但是这题里面坑有点多,必须考虑数组首尾的0、数组元素全为0以及数组只有1个元素的情况。

解题笔记:

  1. indexOf方法可以返回参数在数组中第一次出现的下标,同理lastIndexOf方法可以返回参数在数组中最后一个次出现的下标
  2. Math.ceil方法可以返回一个数向上取整的结果,Math.floor方法可以返回一个数向下取整的结果
  3. 解题过程中可以加入一些条件使得耗费时间减少

你可能感兴趣的:(LeetCode,JavaScript,ACM,算法,LeetCode刷题记录)