博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
两数之和(Go,LeetCode)
阅读量:4189 次
发布时间:2019-05-26

本文共 4241 字,大约阅读时间需要 14 分钟。

目录


 

题目描述

给定一个整数数组nums和一个目标值target,请你在该数据中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

输入/输出示例:

输入条件 给定nums = [2, 7, 11, 15],  target = 9
返回值 [0, 1]
解释 因为nums[0] + nums[1] = 2 + 7 = 9,所以返回[0, 1]

 

解决方案

方案一:二重循环检索

在二重循环里查找是否存在两个值的和与target相等。

for _, i := range nums:    for _, j := range nums:        if i + j == target {            // find!        }

 

如果找到满足条件的值,就讲对应元素的下标收集起来。最终将所有满足条件的下标所组成的列表返回。

但是这个方案有一个致命的缺点:时间复杂度为O(n^{2}),也就是说大量的时间被浪费在重复的计算上,因此不是最优解。

 

方案二:使用Map和集合查找

集合Set是一个不重复的序列。在Go中由于不存在Set类型,我们可以使用Map来构造Set。

减少无意义的循环嵌套是提高运行效率的方法。将数组切片存放在Map中,以数值为key,以索引为值,就可以使用两个叠加循环得解:

for index, value := range nums {    numsMap[value] = index}for value := range nums {    _, ok := numsMap[target - value]    if ok {        // find    }}

考虑到数组切片中可能出现多个相同的数值,因此字典的value应该是一个集合。即集合保存了数组中某个值的所有索引。

 

代码

package mainimport "fmt"type Set struct {	Base	map[int]string}func CreateSet() *Set {	set := new(Set)	set.Base = make(map[int]string)	return set}func (s *Set) Add(data int) {	s.Base[data] = ""	return}func (s *Set) Adds(data... int) {	for _, d := range data {		s.Base[d] = ""	}}func (s *Set) Exist(data int) bool {	_, ok := s.Base[data]	return ok}func (s *Set) Pop() (int, error) {	if s.Length() <= 0 {		return 0, fmt.Errorf("can not pop element: set is empty")	}	for key := range s.Base {		value := key		delete(s.Base, value)		return value, nil	}	return 0, nil}func (s *Set) Length() int {	return len(s.Base)}func (s *Set) ToSlice() []int {	result := make([]int, 0)	for data := range s.Base {		result = append(result, data)	}	return result}func twoSum(nums []int, target int) []int {	numsMap := make(map[int]*Set)	for index, num := range nums {		_, ok := numsMap[num]		if !ok {			numsMap[num] = CreateSet()		}		numsMap[num].Add(index)	}	result := CreateSet()	for value := range numsMap {		_, ok := numsMap[target - value]		if !ok {			continue		}		index1, err := numsMap[value].Pop()		if err != nil {			continue		}		if numsMap[value].Length() <= 0 {			delete(numsMap, value)		}		_, ok = numsMap[target - value]		if !ok {			continue		}		index2, err := numsMap[target - value].Pop()		if err != nil {			continue		}		if numsMap[target - value].Length() <= 0 {			delete(numsMap, target-value)		}		result.Adds(index1, index2)	}	return result.ToSlice()}

 

代码走读

package mainimport "fmt"// ---------- 定义集合结构 ----------// 本质上集合使用map来存储数据type Set struct {	Base	map[int]string}// 创建一个集合func CreateSet() *Set {	set := new(Set)	set.Base = make(map[int]string)	return set}// 向集合中添加一个元素func (s *Set) Add(data int) {	s.Base[data] = ""	return}// 向集合中添加多个元素func (s *Set) Adds(data... int) {	for _, d := range data {		s.Base[d] = ""	}}// 判断元素是否在集合中存在func (s *Set) Exist(data int) bool {	_, ok := s.Base[data]	return ok}// 将集合中的一个随机元素弹出,并返回该元素func (s *Set) Pop() (int, error) {	if s.Length() <= 0 {		return 0, fmt.Errorf("can not pop element: set is empty")	}	for key := range s.Base {		value := key		delete(s.Base, value)		return value, nil	}	return 0, nil}// 求集合长度func (s *Set) Length() int {	return len(s.Base)}// 将集合转换为切片func (s *Set) ToSlice() []int {	result := make([]int, 0)	for data := range s.Base {		result = append(result, data)	}	return result}// LeetCode定义解决函数func twoSum(nums []int, target int) []int {    // 将数组切片转换为Map,Map的key保存数组切片的值,value是一个Set, 保存了值对应在切片中的所有     // 索引下标	numsMap := make(map[int]*Set)	for index, num := range nums {		_, ok := numsMap[num]		if !ok {			numsMap[num] = CreateSet()		}		numsMap[num].Add(index)	}    // 将所有找到的结果放入result中	result := CreateSet()	for value := range numsMap {		_, ok := numsMap[target - value]		if !ok {            // 如果没有找到,则进行下次遍历			continue		}        // 找出第一个元素的下标,如果集合为空,则将该值从Map中删除		index1, err := numsMap[value].Pop()		if err != nil {			continue		}		if numsMap[value].Length() <= 0 {			delete(numsMap, value)		}        // 需要再次判断的原因是数组切片中存在某个数恰巧是target值的一半,且该数值只存在一个,没有        // 配对的另一个值。因此index1会获取到下标,但是会将该value的键值对删除		_, ok = numsMap[target - value]		if !ok {			continue		}		index2, err := numsMap[target - value].Pop()		if err != nil {			continue		}		if numsMap[target - value].Length() <= 0 {			delete(numsMap, target-value)		}        // 将结果放入result中		result.Adds(index1, index2)	}    // 转换成数组切片输出	return result.ToSlice()}// 自测用例func main() {	r := twoSum([]int{2, 7, 11, 15}, 9)	fmt.Println(r)}

 

传送门

转载地址:http://sdsoi.baihongyu.com/

你可能感兴趣的文章
android——学生信息显示和添加
查看>>
Android——ImageSwitcher轮流显示动画
查看>>
Android——利用手机端的文件存储和SQLite实现一个拍照图片管理系统
查看>>
图像调优1:清晰度相关参数MTF,SFR,MTF50,MTF50P 以及TVL的概念以及换算说明
查看>>
图像调优3: CCM参数的标定
查看>>
ctags在verilog代码浏览中的应用
查看>>
NeoVintageous 在sublime中的使用
查看>>
用ncverilog跑仿真时,如何去除对特定路径的timing检查
查看>>
在ncverilog仿真条件设置中+nospecify ,+notimingcheck 和 +delay_mode_zero之间有什么区别
查看>>
linux下nerdtree安装方法
查看>>
最长回文子串(Go,LeetCode)
查看>>
windows下TortoiseGit安装和使用的图文教程
查看>>
基于Jquery的(可视区域,向上滚动向下滚动两种)图片懒加载
查看>>
原生JS的(可视区域,向上滚动向下滚动两种)图片懒加载
查看>>
使用VMware搭建Hadoop集群虚拟网络配置
查看>>
解决vmware下拷贝主机后不识别eth0网卡
查看>>
Promise简单实践
查看>>
vue中无缝轮播简单实现
查看>>
ES5和ES6中的类定义区别
查看>>
利用解构赋值快速提取对象参数
查看>>