周末去看了柯南的也不知道第几个剧场版的「绀青之拳」,感叹它已经出了 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")
}
复制代码
题目就讲到这里,是否是有种名侦探柯南慢慢破案的感受呢?
真実はいつも一つ!
下集再见~
本系列会在公众号进行连载