LeetCode每日一练【15】

LeetCode每日一练

Tree Sum

我的解法

第一次提交

思路:

  1. 升序排序输入的数组
  2. 找到最小非负数, 然后设置两个指针: left(负数) 和 right(非负数)
  3. 因为arr[i] + arr[j] + arr[k] = 0必须的形式一定是[负数, 负数, 非负数(>0)], [负数, 非负数(>=0), 非负数(>0)][0, 0, 0]这三种形式, 因此只需要依次判断原始数组在这三种情况下的输出即可
  4. 考虑到二维数组中的数组重复问题, 还需要对二维数组进行去重处理
  5. 返回去重后的结果
  6. 虽然可以正常返回结果,但是在面对大数据的时候. 遗憾的是,我的解法显示超时
/*
 * @Author: fox
 * @Date: 2022-05-01 00:34:12
 * @LastEditors: fox
 * @LastEditTime: 2022-05-01 20:09:35
 * @Description: https://leetcode.com/problems/3sum/
 */

/**
* @description: 不解释,超过时间限制 Time Limit Exceeded
* @param {number[]} nums
* @return {number[][]}
*/
const threeSum = (arr) => {
    const res = [] // 临时存放返回结果
    const obj = new Object()
    const ret = []  // 存放返回结果
    const myArr = arr.sort((a, b) => a - b) // 将原始数组升序排序
    let middle; // 最小非负数的索引值
    let differ; // 差值

    if (arr.length < 3) return [] // 如果原始数组的长度不超过3,直接返回空数组

    // 1. 找到最小非负数的索引值
    for (let i in myArr) {
        if (myArr[i] >= 0) {
            middle =  i
            break
        }
    }

    // 2. 遍历数组,取得正整数和非负整数的差值,存储到集合中 [-, -, +] [-, +, +]
    for (let left = middle - 1; left >= 0; left--) {
        for (let right = middle; right < arr.length; right++) {
            differ = -(myArr[left] + myArr[right])
            const index = differ > 0 ? myArr.lastIndexOf(differ) : myArr.indexOf(differ);
            if (index !== -1) {
                if (index < left) {
                    res.push([myArr[index], myArr[left], myArr[right]])
                } if (index > right) {
                    res.push([myArr[left], myArr[right], myArr[index]])
                }
            }
        }
    }

    // 3. 如果存在[0, 0, 0]的情况
    if(myArr.filter(item => item === 0).length >= 3) {
        res.push([0, 0, 0])
    }

    // 4. 二维数组去重
    for (let index in res) {
        if (!obj[res[index]]) {
            obj[res[index]] = true
            ret.push(res[index])
        }
    }

    return ret
}

// let arr = [-1, 0, 1, 2, -1, -4]
// console.log(threeSum(arr)) // [[-1,-1,2],[-1,0,1]]

// arr = [1, 1, -2]
// console.log(threeSum(arr)) // [1, 1, -2]

arr = [-1,0,1,2,-1,-4,-2,-3,3,0,4]
console.log(threeSum(arr))

第二次提交

改良思路:

  1. 升序排序输入的数组
  2. 找到最小非负数, 然后设置两个指针: left(负数) 和 right(非负数)
  3. 因为arr[i] + arr[j] + arr[k] = 0必须的形式一定是[负数, 负数, 非负数(>0)], [负数, 非负数(>=0), 非负数(>0)][0, 0, 0]这三种形式, 因此只需要依次判断原始数组在这三种情况下的输出即可
    4. 考虑到二维数组中的数组重复问题, 还需要对二维数组进行去重处理
  4. 去重处理不再使用对象key的唯一性来去重,而是直接判断arr[left] === arr[left + 1] ?arr[right] === arr[right - 1]?
  5. 返回去重后的结果
  6. 虽然可以正常返回结果,但是在面对大数据的时候. 遗憾的是,我的解法显示超时
/*
 * @Author: fox
 * @Date: 2022-05-01 00:34:12
 * @LastEditors: fox
 * @LastEditTime: 2022-05-02 08:19:27
 * @Description: https://leetcode.com/problems/3sum/
 */

/**
* @description: 改良了一下,但是仍然超过时间限制 Time Limit Exceeded,看来问题不在这里,应该是在Array().indexOf中
* @param {number[]} nums
* @return {number[][]}
*/
const threeSum = (arr) => {
    const res = [] // 临时存放返回结果
    const myArr = arr.sort((a, b) => a - b) // 将原始数组升序排序
    let middle; // 最小非负数的索引值
    let differ; // 差值

    if (arr.length < 3) return [] // 如果原始数组的长度不超过3,直接返回空数组

    // 1. 找到最小非负数的索引值
    for (let i in myArr) {
        if (myArr[i] >= 0) {
            middle =  i
            break
        }
    }

    // 2. 遍历数组,取得正整数和非负整数的差值,存储到集合中 [-, -, +] [-, +, +]
    for (let left = middle - 1; left >= 0; left--) {
        if (myArr[left] === myArr[left + 1]) continue
        for (let right = middle; right < arr.length; right++) {
            if (myArr[right] === myArr[right - 1]) continue

            differ = -(myArr[left] + myArr[right])
            const index = differ > 0 ? myArr.lastIndexOf(differ) : myArr.indexOf(differ); // 负值从左向右遍历 正值从右往左遍历
            
            if (index !== -1) {
                // 如果存在,就让它以从小到大的形式存储到数组中
                if (index < left) {
                    res.push([myArr[index], myArr[left], myArr[right]])
                } if (index > right) {
                    res.push([myArr[left], myArr[right], myArr[index]])
                }
            }
        }
    }

    // 3. 如果存在[0, 0, 0]的情况
    if(myArr.filter(item => item === 0).length >= 3) {
        res.push([0, 0, 0])
    }

    return res
}

let arr = [-1, 0, 1, 2, -1, -4]
console.log(threeSum(arr)) // [[-1,-1,2],[-1,0,1]]

arr = [1, 1, -2]
console.log(threeSum(arr)) // [-2, 1, 1]

arr = [-1,0,1,2,-1,-4,-2,-3,3,0,4]
console.log(threeSum(arr))

第三次提交

二次改良思路:

  1. 升序排序输入的数组
    2. 找到最小非负数, 然后设置两个指针: left(负数) 和 right(非负数)
  2. 设置两个指针: left(数组最小值) 和 right(数组最大值)
  3. 因为arr[i] + arr[j] + arr[k] = 0必须的形式一定是[负数, 负数, 非负数(>0)], [负数, 非负数(>=0), 非负数(>0)][0, 0, 0]这三种形式, 因此只需要依次判断原始数组在这三种情况下的输出即可
    4. 考虑到二维数组中的数组重复问题, 还需要对二维数组进行去重处理
  4. 去重处理不再使用对象key的唯一性来去重,而是直接判断排序数组中arr[left] === arr[left + 1] ?arr[right] === arr[right - 1]?
  5. 返回去重后的结果
  6. 正确提交.
/*
 * @Author: fox
 * @Date: 2022-05-01 00:34:12
 * @LastEditors: fox
 * @LastEditTime: 2022-05-02 10:24:54
 * @Description: https://leetcode.com/problems/3sum/
 */

/**
* @description: Runtime: 5.00%  Memory Usage: 99.90%
* @param {number[]} nums
* @return {number[][]}
*/
const threeSum = (arr, len = arr.length) => {
    if (len < 3) return [] // 如果原始数组的长度不超过3,直接返回空数组

    const res = [] // 存放返回结果
    const myArr = arr.sort((a, b) => a - b) // 将原始数组升序排序
    let differ; // 差值

    let [left, right] = [0, len - 1] // 定义左右两个指针,分别指向排序数组的最小值和最大值

    while (left < right && myArr[left] < 0 && myArr[right] >= 0) {
        if (myArr[left] !== myArr[left - 1]) {
            while (left < right && myArr[left] <= 0 && myArr[right] >= 0) {
                if (myArr[right] !== myArr[right + 1]) {
                    differ = -(myArr[left] + myArr[right]);
        
                    if (differ < myArr[right] && differ > myArr[left]) {
                        if (myArr.includes(differ)) {
                            res.push([myArr[left], differ, myArr[right]]);
                        }
                    } else if (differ === myArr[left] && differ === myArr[left + 1]) {
                        res.push([myArr[left], differ, myArr[right]]);
                    } else if (differ === myArr[right] && differ === myArr[right - 1]) {
                        res.push([myArr[left], differ, myArr[right]]);
                    }
                }
                right--;
            }
        }
        right = len - 1
        left++;
    }

    if (myArr.filter(_ => _ === 0).length >= 3) {
        res.push([0, 0, 0])
    }

    return res
}

let arr = [-1, 0, 1, 2, -1, -4]
console.log(threeSum(arr)) // [[-1,-1,2],[-1,0,1]]

arr = [1, 1, -2]
console.log(threeSum(arr)) // [-2, 1, 1]

arr = [-1,0,1,2,-1,-4,-2,-3,3,0,4]
console.log(threeSum(arr))

arr = [3,2,-2,3,-2,-5,4,-1,-5,4]
console.log(threeSum(arr))

大神解法

思路:

  1. 数组排序

  2. 使用三指针 -- 二和法的方法: arr[x] + arr[y] + arr[k] === 0?

    1. arr[x] + arr[y] + arr[k] > 0 移动y指针
    2. arr[x] + arr[y] + arr[k] < 0 移动k指针
    3. arr[x] + arr[y] + arr[k] = 0 数据进入数组ret, 移动y指针和k指针
  3. 数组去重

while (nums[j] === nums[j+1]) j++; // 去重处理
while (nums[k] === nums[k-1]) k--; // 去重处理
/*
 * @Author: fox
 * @Date: 2022-05-02 11:20:41
 * @LastEditors: fox
 * @LastEditTime: 2022-05-02 11:23:19
 * @Description: https://leetcode.com/problems/3sum/
 */

/**
 * @description: Runtime: 89.32%  Memory Usage: 88.32%
 * @param {number[]} nums
 * @param {number} target
 * @return {number[][]}
 */
 function threeSum(nums, target = 0) {     
    const ret = [];

    if (nums.length < 3) {
        return ret;
    }
    nums.sort((a,b) => a - b);   // 数组排序
    
    // 二和法
    for (let i = 0; i < nums.length - 2 && nums[i] <= target; i++) { // 限制nums[i]只能在负数范围内移动
        if (i > 0 && nums[i] === nums[i - 1]) { // 去重处理
            continue;
        }
        for (let j = i + 1, k = nums.length - 1; j < k;) {            
            const sum = nums[i] + nums[j] + nums[k];
            if (sum < target) { // 如果 sum < target 则移动j指针
                j++;
                continue;

            } else if (sum > target) { // 同上,如果sum > target 则移动k指针
                k--;
                continue;
            }             
            
            ret.push([nums[i], nums[j], nums[k]]); // 如果 sum === target 数据入组
     
            while (nums[j] === nums[j+1]) j++; // 去重处理
            while (nums[k] === nums[k-1]) k--; // 去重处理

            // 注意: 下面两条语句的位置,必须放在这里 因为考虑到了continue语句的情况
            j++;
            k--; 
        }

    }

    return ret;
}

let arr = [-1, 0, 1, 2, -1, -4]
console.log(threeSum(arr)) // [[-1,-1,2],[-1,0,1]]

arr = [1, 1, -2]
console.log(threeSum(arr)) // [-2, 1, 1]

arr = [-1,0,1,2,-1,-4,-2,-3,3,0,4]
console.log(threeSum(arr))

arr = [3,2,-2,3,-2,-5,4,-1,-5,4]
console.log(threeSum(arr))
posted @ 2022-05-02 11:34  白い故雪  阅读(22)  评论(0编辑  收藏  举报