演算法-兩數相加TwoSum
兩數相加問題
假設存在一個整數陣列,[2,5,7,10,33,23]。 數組裡面的數無序但可保證不重複。給定一個目標值C,例如9. 嘗試找出陣列中所有滿足A+B=C的元素,最終輸出A和B的陣列下標。
例如:2+7=9
則最終輸出[0,2]。 0和2分別對應2,7的下標。
方案一 輪詢法
使用兩個for迴圈依次查詢。 從第一個元素i開始,如果小於C,則使用第二個for迴圈查詢C-i。 如果找到則返回,如果沒找到,則繼續第二輪查詢。
package main import "fmt" func main() { arr := []int{2, 7, 5, 10, 22, 34, 20,} target := 12 var result []int for i, a := range arr { if a < target { for n, b := range arr[i+1:] { if b == target-a { result = []int{i, n + i + 1} break } } } } fmt.Println(result) }
方案二 兩階段MAP方案
方案一的時間演算法複雜度是N的平方(本人的Markdown編輯器不支援latex, 所以只能寫漢字了..),而空間複雜度則是N。可以藉助兩個map,將一層for迴圈去掉。
package main import "fmt" func main() { arr := []int{2, 7, 5, 10, 22, 34, 20,} target := 12 fmt.Println(towPassMap(arr, target)) } func towPassMap(arr []int, c int) (result []int) { m := make(map[int]int) for i, a := range arr { m[a] = i } for i, a := range arr { if _, ok := m[c-a]; ok { result = []int{i, m[c-a]} return } } return }
方案三 一階段MAP方案
藉助一個Map之後,時間複雜度降為了N。而空間複雜度仍然為N。 其實上面的演算法並非最優演算法,我們還可以再進行優化,也就是僅使用一次MAP。
package main import "fmt" func main() { arr := []int{2, 7, 5, 10, 22, 34, 20,} target := 12 fmt.Println(onePassMap(arr, target)) } func onePassMap(arr []int, c int) (result []int) { m := make(map[int]int) for i, a := range arr { m[a] = i if a > c { continue } if _, ok := m[c-a]; ok { return []int{i, m[c-a]} } } return }
因為只存在一個for迴圈,所以時間複雜度仍然為N,但同方案二相比,減少了元素遍歷次數,只有在最差情況下,匹配效率才和方案二相同。