學演算法的前端 leetcode 1

鄭明遠發表於2019-03-22

學演算法的前端 leetcode 1

就個人而言,我是喜歡演算法的,奈何不擅長,所以選擇了我同樣喜歡的前端(我才不會告訴你是因為有好多漂亮妹子在呢)。

學演算法的前端 leetcode 1

那麼今天來看下leetcode 第1題,兩數之和:

給你一個陣列,返回2個數之和為一個目標值的下標,輸入資料只會有準確的一種解法,同一個元素不能使用2次。

那有人就說了,這不 so tm easy 嗎,我遍歷一遍陣列 a[i] ,之後再遍歷一遍陣列 a[j] ,只要 a[i] + a[j] === target 不就 ojbk 了嘛。

那這位同學,我就想問下:你還記得在大學時期,青澀的你,在陽光明媚的演算法與資料結構課堂上,老師的淳淳教誨嗎?還是你把時間都花費在隔壁班的女同學上了?

當然,大家都是上過大學的文化人,我就算這麼做過但也不會這麼說呀!好啦好啦,回到正題,上面的解法時間複雜度是 O(n^2) 因為在每一遍 n 的迴圈中你又跑了一遍 n 的迴圈,所以這是不優雅的。

學演算法的前端 leetcode 1

其實你第二遍迴圈裡只是為了找出一個值,但你用了 O(n) 的複雜度,那這裡能不能更快些呢?當然是可以的啦,我們可以使用二分查詢,只需要 O(logn) 的複雜度,但二分的前提是陣列要有序呀,所以得排個序,排序平均是 O(nlogn) 所以最後我們的時間複雜度就變成了 O(nlogn)

學演算法的前端 leetcode 1

那接下來的步驟就顯而易見了,我貼下程式碼吧:

/**
 * 二分查值
 *
 * @param {Array} arr the data
 * @param {nubmer} left the start index
 * @param {number} right the end index
 * @param {number} val the target value
 * @returns {nubmer} the target value's index, if
 * no exist, it will return -1
 */
function binarySearch(arr, left, right, val) {
  if (right < left) {
    throw new Error('right can not less than left')
  }
  let mid
  while (left <= right) {
    mid = Math.floor((left + right) / 2)
    if (arr[mid] < val) left = mid + 1
    else if (arr[mid] === val) break
    else right = mid - 1
  }
  return arr[mid] === val ? mid : -1
}

var twoSum = function(nums, target) {
   nums = nums.map((val, idx) => ({
    val,
    idx
  }))
  nums.sort(function(a, b) {
    return a.val - b.val
  })

  const len = nums.length
  for (let i = 0; i < len - 1; i++) {
    const t = target - nums[i].val
    const idx = binarySearch(nums.map(v => v.val), i + 1, len - 1, t)
    if (idx !== -1) {
      return [nums[i].idx, nums[idx].idx]
    }
  }
}

複製程式碼

這裡提交題目的方式其實就是給你一個 twoSum 函式,你去完成這個函式的功能即可,最後結果如下:

學演算法的前端 leetcode 1

看沒看到,時間上超過了一半的人唉,果然我就是膩害!

那又有人說了:你空間複雜度才超過 5% 的人唉!

就你話多,我有錢,我是富二代,我買幾百個記憶體條給我伺服器裝上,不行啊。

我心裡是這麼想的,當然現實不能真的這樣啦!

那怎麼優化空間複雜度呢?其實 solution 中也講到了,java 是用的 hashMap,我們js也有 Map 呀,所以,你可以用 Map 試試,看看結果能不能超過這麼帥氣、優秀的我!

相關文章