leetCode-俩数之和-4种解法

4,153 阅读3分钟

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

前言

有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来,由此可见,leetcode的题还是有分量的。今天我们就来会会它

介绍

给定一个整数数组 nums  和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那   两个   整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

解法一

  • 一看题目我们就觉得用双层for循环 so easy
var twoSum = function (nums, target) {
    for (let i = 0; i < nums.length; i++) {
        for (let j = i+1; j < nums.length; j++) {
            if (nums[i] + nums[j] === target) {
                return [i, j]
            }

        }
    }
    return new Error("数据nums或者target不符合规范")
};
console.log(twoSum([3,2,4],6));

思路

  • 首先我们遍历数组nums,
  • 再遍历一次nums,把j的默认值设为外层循环的i+1,
  • 这样俩次循环的是数就不会重复了,
  • 最后判断外层循环的当前值和第二次循环的当前值是否相等,相等就返回他们的下标,否则进行下一次循环
  • 如果完成整个循环都没有符合条件的值,那么证明数组nums或者 target不符合规范 问题
  • 这种暴力的解法
  • 时间复杂度O(N2),其中n代表元素的数量,最坏的情况下,任意的俩个述职都需要匹配下才能成功
  • 空间复杂度O(1)

解法二

var twoSum = function (nums, target) {
    let obj = {}
    for (let i = 0; i < nums.length; i++) {
        if (obj[[target - nums[i]]] > -1) {
            return [obj[[target - nums[i]]], i]
        } else {
            obj[nums[i]] = i
        }
    }
    return new Error("数据nums或者target不符合规范")
};
console.log(twoSum([3, 2, 4], 6));

思路

  • 首先创建一个空的数组
  • 循环数组nums
  • 通过target-nums[i]得到剩余值
  • 然后把剩余值当做k获取对象obj中的值
  • 如果值大于-1的话,证明值存在
  • 返回 当前循环的下标i和对象obj中的值
  • 如果值小于等于-1的话
  • 则把当前循环的值num[i]当做k,值为下标,放入对象obj
  • 再次执行循环语句,直到if条件成立或者,或者循环语句结束 注意
  • 我们if判断的时候是obj[[target - nums[i]]] > -1而不是直接这样写 obj[[target - nums[i]]]
  • 如果采用后边的写法,那么如果obj[[target - nums[i]]]中存着的值刚好是数组的下标0
  • 又因为js隐式转换的原因,这个判断是不会走的

解法三

var twoSum = function(nums, target) {
   let obj = Object.create(null)
    for (let i = 0; i < nums.length; i++) {
        if (obj[[target - nums[i]]] > -1) {
            return [obj[[target - nums[i]]], i]
        } else {
            obj[nums[i]] = i
        }
    }
    return new Error("数据nums或者target不符合规范")
};
console.log(twoSum([3, 2, 4], 6));

思路

  • 解法三的思路和解法二基本一致
  • 只是解法三在初始化的时候把空对象替换成了Object.create(null)方法
  • Object.create(null)方法会创建一个无属性的对象。如图所示

image.png

解法四

var twoSum = function (nums, target) {
    let map = new Map()
    for (let i = 0; i < nums.length; i++) {
        if (map.has(target - nums[i])) {
            return [map.get(target - nums[i]), i]
        } else {
            map.set(nums[i], i)
        }
    }
    return new Error("数据nums或者target不符合规范")
};
console.log(twoSum([3, 2, 4], 6));

思路

  • 利用了map数据结构的特性
  • 首先通过new Map()方法定义一个map类型的变量
  • 循环nums
  • 通过target - nums[i]拿到剩余值
  • 通过maphas方法判断当前传入的k的值是否存在
  • 存在的话就证明当前循环的值+map对象中当前k刚好等于target
  • 那么就通过数组的形式返回他们的下标
  • 如果不存在
  • 那么就把当前循环的值作为 k,下标作为值赋值给map
  • 再次执行循环语句,直到if条件成立或者,或者循环语句结束

写在最后

  • 这篇文章虽然写的是俩数之和的解法
  • 其中也涉及了一些js书写的注意点
  • 希望你也能收获满满