本題連接 leetcode-cn.com/problems/tw…算法
看到這道題的第一反應就是,挺簡單的,遍歷兩遍數組就能解決,咱們嘗試一下。數組
let twoSum1 = 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),最終經過時間爲204ms,很不推薦,咱們能不能縮短期呢?bash
咱們假設最終找到的兩個值一個是x,一個是y,x + y = target,也就等價於 y = target - x。咱們只須要操做x就能解決這道題。思路是,判斷target - x 這個值是否存在於這個數組中並與x的數組下標不相等。ui
let twoSum2 = function (nums, target) {
for (let i = 0; i < nums.length; i++) {
if (nums.indexOf(target - nums[i]) > -1 && nums.indexOf(target - nums[i]) !== i) { // 排除兩個值相等的狀況
return [i, nums.indexOf(target - nums[i])];
break; // 防止最終結果的下標出現兩次
}
}
}
複製代碼
最終順利經過,但最後的時間爲208ms,爲何一層循環和兩層循環的經過時間這麼接近呢?由於twoSum2雖然只用了一層循環,但用到了js內置的方法indexOf(),這裏面也有一層循環,其實最終仍是兩層循環,這個方法也不推薦。spa
咱們用一個對象把數組裏的下標和值都存起來,對象裏的鍵表明數組的值,對象裏的值表明數組下標,再用twoSum2裏的思路去解題,這樣只須要循環一次。code
let twoSum3 = function(nums,target){
let obj = {};
for(let i=0; i<nums.length; i++){
obj[nums[i]] = i
}
for(let i=0; i<nums.length; i++){
if(obj[target-nums[i]] && obj[target-nums[i]] !== i){
return [i,obj[target-nums[i]]]
}
}
}
複製代碼
這個方法時間複雜度爲o(n),最終經過的時間是80ms,比以前快了兩倍多,除了空間換時間,解題思路和twoSum2徹底同樣。對象
逛了下社區的解題,有不少同窗都用了哈希表來存值,最終實現空間換時間,下降時間複雜度。其實跟twoSum3的思路是同樣的,咱們也試着用哈希表寫一個。leetcode
let twoSum4 = function(nums, target) {
const map = new Map()
for(let i = 0; i < nums.length; i++){
if (map.has(target - nums[i])){
return [ map.get(target - nums[i]), i ]
}
map.set(nums[i], i)
}
};
複製代碼
最終經過時間84ms,跟twoSum3差很少。get
本題最主要的思路就是用空間換時間,我的認爲若是能很明顯地減小時間複雜度,用空間換時間是值得的。反正無論怎樣,寫出來的算法時間複雜度是o(n^2)是很糟糕的,咱們必定要想盡辦法,減小時間複雜度。io