週末去看了柯南的也不知道第幾個劇場版的「紺青之拳」,感嘆它已經出了 1000 多集 TV 版了,我以爲程序員都應該去看柯南,雖然破案的邏輯可能會有漏洞,可是對案件真相的追求很是值得咱們學習。程序員
因而打算改變一下公衆號的文章定位:算法
經過回顧柯南每一集的劇情,讓沒有看過的人產生興趣,讓看過的人撿起情懷。數組
回顧柯南的同時順便作一下 leetcode 上面的題目,真的只是順便,不必定是最優解,但確定不是暴力解,又不是參加 ACM 競賽對吧。bash
題目的講解儘量符合「碼上開學」系列的標準,主要是經過解題找到興趣點,而不是死記硬背完成任務,不然就太無趣了。數據結構
讓咱們開始吧~學習
高中生偵探工藤新一被稱爲「日本警察界的救世主」而響譽全國,他幫助警方解決了不少棘手案件。某日,他和兩小無猜小蘭一塊兒去坐雲霄飛車時遇到了一塊兒因情生恨的兇殺事件,其中,有兩名黑衣人引發了工藤的注意,工藤暗中跟蹤卻被發現,黑衣給他灌下毒藥後離開,當被警察發現時,工藤已變成了小孩兒的模樣。測試
我只會貼英文的題目,主要是爲了讓你們熟悉計算機的一些術語。優化
Given an array of integers, return indices of the two numbers such that they add up to a specific target.ui
You may assume that each input would have exactly one solution, and you may not use the same element twice.spa
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
複製代碼
fun twoSum(nums: IntArray, target: Int): IntArray {
}
複製代碼
以後的代碼都以 Kotlin 爲例來寫,也是爲了幫助你們熟悉 Kotlin,後面有時間再考慮 Python 吧。
讀題:
一個數組中若是有兩個數加起來等於 target
,那麼就返回這兩個數的 index
數組,這裏包含如下要點:
那咱們首先先讓它編譯過:
fun twoSum(nums: IntArray, target: Int): IntArray {
// 👇 兜底拋出異常
throw IllegalArgumentException("No two sum solution")
}
複製代碼
接下來分析一下思路:
咱們思考下所謂的算法優化的本質:
根據上面的思路,嘗試開始寫代碼:
fun twoSum(nums: IntArray, target: Int): IntArray {
// 先備份數據
val backupMap = mutableMapOf<Int, Int>()
nums.forEachIndexed { index, i ->
backupMap[i] = index
}
nums.forEachIndexed { index, i ->
// 2 的對立面,就是找 7 的索引
val complementIndex = backupMap[target - i]
if (complementIndex != null) {
// 找到了
return intArrayOf(index, complementIndex)
}
// 沒找到就無論,最後走兜底
}
throw IllegalArgumentException("No two sum solution")
}
複製代碼
再寫一個測試用例:
@Test
fun test() {
val result = twoSum(intArrayOf(2, 7, 11, 15), 9)
println(result.contentToString())
}
複製代碼
最後打印出正確的結果,返回的是 2 和 7 的索引:
[0, 1]
複製代碼
原本到這裏已經搞定收工了,可是咱們再讀一下題目最後一句話:
you may not use the same element twice
意思是說一個元素只能用一次,咱們對數組自己遍歷了兩次,等於對同一個元素用了兩次,不符合題目的要求。
leetcode 官網上這道題給出了三種解法,其實遍歷超過一次的都是不符合題目要求的,也就沒有所謂的「最優解」一說,因此咱們看看能不能再優化下知足題目的要求吧。
我認爲,leetcode 的題目的初衷不是比誰的算法更加優秀,而是切題,由於題目稍微變下,所謂的「最優解」立刻就失效了。
根據上面思路,代碼以下:
fun twoSum(nums: IntArray, target: Int): IntArray {
val backupMap = mutableMapOf<Int, Int>()
nums.forEachIndexed { index, i ->
val complementIndex = backupMap[target - i]
if (complementIndex != null) {
// 找到了
// 👇 注意,這裏找到的索引是以前放進去的,因此要放在前面
return intArrayOf(complementIndex, index)
}
// 沒找到才進行備份
backupMap[i] = index
}
throw IllegalArgumentException("No two sum solution")
}
複製代碼
題目就講到這裏,是否是有種名偵探柯南慢慢破案的感受呢?
真実はいつも一つ!
下集再見~
本系列會在公衆號進行連載