【leetcode】1. two sum两数之和

LeetCode 第一题,难度 Easy,但很适合拿来练手:题意直白,优化路径也清晰。
题意理解
给定一个整数数组 nums 和一个目标值 target,在数组里找出两个不同下标 i、j,使得 nums[i] + nums[j] === target。题目保证恰好有一组解,且不能重复使用同一个元素。
Example 里 nums = [2, 7, 11, 15]、target = 9,答案是 [0, 1],因为 2 + 7 = 9。注意返回的是下标,不是数值本身。
Description
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
0. My solution(Brute Force)
最直觉的做法:双重循环,枚举所有 (i, j) 组合,看两数之和是否等于 target。内层从 0 开始扫,所以 i === j 时要用 i != j 挡一下。
var twoSum = function(nums, target) {
for(let i = 0; i < nums.length; i++) {
for(let j = 0; j < nums.length; j++) {
if(nums[i] + nums[j] === target && i != j) {
return [i, j]
}
}
}
};
· Time complexity: O(n^2), For each element, I try to find its complement by looping through the rest of array which takes O(n)*O(n) time. Therefore, the time complexity is O(n^2).
· Space complexity : O(1).
暴力法能过,但数据量一大就超时。核心问题是:对每个 nums[i],我们都在数组里线性找它的「补数」target - nums[i]。
1. Improve
内层循环从 i + 1 开始,避免 (i, j) 和 (j, i) 重复判断,也省掉 i != j 的判断。
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]
}
}
}
};
时间复杂度仍是 O(n²),只是常数小一点。
2. Improve again
用 indexOf 在 i 之后找补数,写法更短。indexOf(complement, i + 1) 保证找到的下标在 i 后面,不会用到同一个元素。
var twoSum = function(nums, target) {
for(var i = 0; i< nums.length; i++){
var complement = target - nums[i];
var found = nums.indexOf(complement, i + 1);
if(found !== -1){
return [i, found];
}
}
return [0, 0];
};
indexOf 本身也是 O(n),整体还是 O(n²)。另外最后一行 return [0, 0] 按题意其实走不到(保证有解),留着算是防御性写法。
3. Improve again
哈希表(JavaScript 里用普通对象 {} 就行):先一遍把「值 → 下标」存进去,再一遍查补数是否在表里。查表 O(1),总时间 O(n)。
var twoSum = function(nums, target) {
if (nums.length === 2) return [0, 1];
const len = nums.length;
let hashTable = {};
for(let i = 0; i < len; i++){
// Add a new obj to the hashTable where key = nums[i] and value = i
hashTable[nums[i]] = i;
}
for(let i = 0; i < len; i++) {
let complement = target - nums[i];
let found = hashTable[complement]; // Determine whether the complement exist in the hashTable
if(found !== undefined && found != i) return [i, found];
}
return [0,0];
}
JavaScript 实现注意点
- 对象键会被转成字符串,本题全是整数,一般没问题;若值可能是对象或
NaN,要另想方案。 found != i用宽松不等即可,下标都是数字。- 也可以边遍历边写入哈希表,只扫一遍;上面写法是「先建表再查」,逻辑更直观。
- 长度只有 2 时直接返回
[0, 1],小优化,可写可不写。
版权声明: 本文首发于 指尖魔法屋-【leetcode】1. two sum两数之和(https://blog.thinkmoon.cn/post/295-notes-leetcode-two-sum/) 转载或引用必须申明原指尖魔法屋来源及源地址!