LeetCode-兩數之和

梨子啊荔枝發表於2024-08-06

前言

這道題是Leetcode的第一題,也是經典題目之一,幾乎所有刷題網站的第一題都是“兩數之和”,只是Leetcode這道題不一樣。
在這篇部落格中,我們介紹了兩種解法:

暴力演算法 雜湊表演算法
\(\mathcal{O}(n^2)\) \(\mathcal{O}(n)\)

題目描述

給定一個整數陣列 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]

示例2:

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

提示

  • \(2 \leq nums.length \leq 10^4\)
  • \(-10^9 \leq nums[i] \leq 10^9\)
  • \(-10^9 \leq target \leq 10^9\)
  • 只會存在一個有效答案

題目分析

由於題目描述得比較清晰,所以不用過多分析。需要注意的是,題目已經說明每種輸入只對應一個答案,說明我們不用考慮有多個答案的情況。

暴力演算法

閱讀完題目之後,首先能想到的解法就是確定一個值 \(nums[i] , 0 \leq i \leq nums.length-1\) ,在剩餘的序列中找到 \(target-nums[i]\)

解題程式碼

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for (int i = 0 ; i < nums.size() - 1 ; i ++) {
            /* j 從 i+1 開始,是因為兩個下標不能相同,題目有說明*/
            for (int j = i + 1 ; j < nums.size() ; j++) {
                if ( nums[j] == target - nums[i]) {
                    return {i , j};
                }
            }
        }
        return {};
    }
};

複雜度分析

\(nums\) 的長度為 \(n\) ,可以得到等式

\[\begin{equation}\begin{aligned} Complex &= \underbrace{(n-1) + (n-2) + (n-3) +\cdots + 1}_{n-1} = \frac{[1 + (n-1)]\times(n-1)}{2} \\ &= \frac{n^2-n}{2} = \frac{1}{2}n^2 -\frac{1}{2}n. \end{aligned}\end{equation} \]

因此\(\mathcal{O}(Complex) = \mathcal{O}(\frac{1}{2}n^2 -\frac{1}{2}n) = \mathcal{O}(n^2)\)

我們在剛開始刷題的時候,可以先試著自己寫出暴力演算法,然後分析一下時間複雜度,再嘗試其他解題方法。

由暴力演算法可以得知,主要的時間消耗是在尋找 \(target-nums[i]\) 上,如果能降低尋找 \(target-nums[i]\) 的時間,就能實現一個時間複雜度小於 \(\mathcal{O}(n^2)\) 的演算法。

因此我們考慮用 雜湊表 來解決這一問題 。

雜湊表演算法

最開始接觸到雜湊表思想是從桶排序演算法,它的典型思想是以空間換時間,雜湊表的時間複雜度為\(\mathcal{O}(1)\)

我們可以將陣列分為兩部分,如下圖:

image

解題程式碼

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> idx;

        for (int j = 0 ; j < nums.size() ; j++) {
            auto it = idx.find(target-nums[j]);
            if ( it != idx.end()) {
                return { it->second , j};
            }
            idx[nums[j]] = j;
        }
        return {};
    }
};

複雜度分析

\(nums\) 的長度為 \(n\) ,可以得到時間複雜度等式

\[\begin{equation}\begin{aligned} \mathcal{O}(Complex) &= \mathcal{O}(\text{雜湊查詢}) + \mathcal{O}(\text{遍歷})\\ &=\mathcal{O}(1) + \mathcal{O}(n) = \mathcal{O}(n+1)\\ &= \mathcal{O}(n). \end{aligned}\end{equation} \]

空間複雜度為 \(\mathcal{O}(n)\).

相關文章