打怪升级之旅

59 阅读3分钟

每天进步一点点

算法开始第一天 twoSum(两数之和) 刷了n次 写了n次 开始写文章记录一下 到年底希望自己能够坚持 让我开始吧!!!!!

题目描述

给定的一个整数数组nums和一个目标值target,请你再该数组中找到和为目标值的那两个整数,并返回他们的数组下标 tips: 你可以假设每种输入只会对应一种答案,但是,你不要重复利用这个数组中同样的元素

示例:给定 nums = [2,7,11,15] target = 9 返回 [0, 1]

两数之和之暴力递归

思路 已知target 已知第一层循环对应下标i的值 所以只要遍历下标i后面元素 找出元素与 differenceValue相等的下标

/**
 * 两数之和之暴力递归
 * @param {number} target 
 * @param {array} nums 
 * 时间复杂度: T(n) = 3n^2 + 6n + 5 -> 0(n) = O(n^2)
 * 空间复杂度: O(1) 
 */
function twoSum(target,nums){
  let len = nums.length  // 最坏执行的次数 1
  for(let i = 0; i < len; i++){ // 最坏执行的次数: 2n + 2
    let currentValue = nums[i] //  最坏执行的次数: n
    let differenceValue = target - currentValue //  最坏执行的次数: n
    for(let j = i + 1; j < len; j++){  //  最坏执行的次数: 2n^2 + 2n
      if(nums[j] === differenceValue){ // 最坏执行的次数: n^2
        return [i,j] //最坏执行的次数:  1
      }
    }
  }
  throw new Error('没有符合条件的值') //最坏执行的次数:  1
}
console.time('twoSum')
const result = twoSum(9,[2,4,7,11,15])
console.timeEnd('twoSum') // 0.081ms
console.log('>>>>', result) // [0,2]

空间换时间

大部分求和问题 都可以转化为求差问题

思路 可以使用Map来存储已经出现的值和下标 当Map拥有当前下标和目标值的差值 就返回这个两个下标

/**
 * 空间换时间 一次遍历
 * @param {array} nums 
 * @param {number} target 
 * 时间复杂度: T(n) = 4n + 5 -> O(n) = O(n)
 * 空间复杂度: O(n)
 */
const twoSum = function(nums,target){
  let len = nums.length // 最坏执行的次数 1
  let map = new Map() // 最坏执行的次数 1
  for(let i= 0; i< len; i++){  // 最坏执行的次数 2n + 2
    if(map.has(target - nums[i])){ // n
      return [map.get(target - nums[i]),i] // 1
    }
    map.set(nums[i], i) // n
  }
}
console.time('twoSum')
const result1 = twoSum([2,4,7,11,15],9)
console.timeEnd('twoSum') // 0.04ms
console.log('>>>>', result) // [0,2]

相撞指针

思路分析 题目给出是一个有序的数组 可以使用双向指针 最小的值 + 最大的值 > target r-- 最小的值 + 最大的值 < target l++

/**
 * 相撞指针
 * @param {number[]} nums 
 * @param {number} target 
 * 时间复杂度 O(n) = 4n + 4 -> O(n)
 * 空间复杂度: O(1)
 */
const twoSum2 = function(nums, target){
  let len = nums.length // 最坏执行的次数: 1
  let l = 0 // 最坏执行的次数: 1
  let r = len - 1 // 最坏执行的次数: 1
  while(r > l){ // 最坏执行的次数: n
    if(nums[l] + nums[r] > target){  // 最坏执行的次数: n
      r--  // 最坏执行的次数: n
    }else if(nums[l] + nums[r] < target){  // 最坏执行的次数: n
      l++  // 最坏执行的次数: n
    }else{
      return [l, r]  // 最坏执行的次数: 1
    }
  }
}

console.time('twoSum2')
const result2 = twoSum2([2,4,7,11,15],9)
console.timeEnd('twoSum2') // 0.032ms
console.log('>>>>', result2) // [0,2]

n 越大这两种方法的性能差也会越多

ok!! Baybay! 明天见