博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
两数之和等于目标值
阅读量:6256 次
发布时间:2019-06-22

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

1. LeetCode(twoCode)

Given an array of integers, find two numbers such that they add upto a specific target number.

The function twoSum should return indices of the two numbers suchthat they add up to the target, where index1 must be less than index2. Pleasenote that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2,7, 11, 15}, target=9

Output: index1=1,index2=2

2. 问题分析

(1) 暴力求解,检查全部对(n2)数字之和。

(2) 题目中并没有说数组是有序或无序,因此能够先按有序思考,毕竟排序方法太成熟了。若数组元素有序则能够从数组的两端開始求解,若两个数之和大于目标值则后端往前移,若小于则前端往后移。若相等则找到结果程序结束。

若前后端相遇则查找失败。显然该方法时间复杂度O(n)。

(3) 若无序,则有两种处理思路:

(3.1) 先对数组进行排序,最快的排序算法O(n),则无序处理代价为O(n) + O(n) = O(n)。

进一步分析:经常使用的线性时间排序算法计数排序、桶排序等均有一定的限制。如当数组中元素跨度较大时计数排序须要较大的空间开销,桶排序要求元素均匀分布。

因此对数组排序常使用快排(O(nlogn)),此时问题求解时间复杂度O(nlogn)。

(3.2) 用哈希存储原始数据。

遍历原始数据,当訪问数据是w,目标值是t时,在哈希表中查找是否存在t-w,若存在则查找成功。若不存在,则继续遍历。直到找到结果或遍历结束。

哈希插入与查找代价均为O(1),因此总体时间复杂度仍是O(n)。

3 实现

3.1 暴力方法

该方法检測n2对元素的和,时间复杂度O(n2)。

vector
Solution::twoSum(vector
&nums, const int target){ vector
result; int size = nums.size(); for (int i = 0; i < size; ++i) { for (int j = i + 1; j < size;++j) { if (target == nums[i] +nums[j]) { result.push_back(i + 1); result.push_back(j + 1); break; } } } return result;}

3.2 先排序再求解1

在这里利用了C++STL中的sort排序函数。从sort源代码实现来看其属于快排的优化,具体的请查看sort源代码。该方法时间复杂度O(nlogn)。

struct numStruct{      int number;      int location;      numStruct(int a = 0, int b = 0):number(a),location(b)      {      }}; boolisLesser(numStruct a, numStruct b){      return a.number < b.number;} vector
Solution::twoSum(vector
&nums, const int target){ vector
result; int size = nums.size(); numStruct *data = new numStruct[size]; for (int i = 0; i < size; ++i) { data[i].number = nums[i]; data[i].location = i; } sort(data, data + size, isLesser); int head, tail; head = 0; tail = size - 1; while (head < tail) { int tempResult = data[head].number+ data[tail].number; if (target == tempResult) { int loc1, loc2; loc1 = data[head].location +1; loc2 = data[tail].location +1; if (loc1 > loc2) { result.push_back(loc2); result.push_back(loc1); } else { result.push_back(loc1); result.push_back(loc2); } break; } else if (target < tempResult) { --tail; } else { ++head; } } delete []data; return result;}

3.3先排序再求解2

(1) 非常多博客里都把使用map当做哈希的方法,实际是错误的。由于map的底层是红黑树而不是哈希,红黑树中序有序。

该方法时间复杂度O(nlogn)。

vector
Solution::twoSum(vector
&nums, const int target){ vector
result; map
data; int size = nums.size(); for (int i = 0; i < size; ++i) { if (!data.count(nums[i])) { data.insert(pair
(nums[i], i)); } } for (int i = 0; i < size; ++i) { if (data.find(target - nums[i]) !=data.end()) { result.push_back(data[target- nums[i]] + 1); result.push_back(i + 1); break; } } return result;}

(2) 由于仅仅须要找到一个结果。因此不是必需索引所有的数据。上述代码优化为:

vector
Solution::twoSum(vector
&nums, const int target){ vector
result; map
data; int size = nums.size(); for (int i = 0; i < size; ++i) { if (data.find(target - nums[i]) !=data.end()) { result.push_back(data[target- nums[i]] + 1); result.push_back(i + 1); break; } data[nums[i]] = i; } return result;}
(3) 又由于红黑树中序有序,因此能够利用中序遍历。

中序遍历为:左-中-右。而逆向中序遍历为右-中-左。值得注意的是map中的键值唯一。因此使用multimap来取代map。

综上。能够像3.2中那样实现。

vector
Solution::twoSum_Map(vector
&nums, const int target){ vector
result; multimap
data; int size = nums.size(); for (int i = 0; i < size; ++i) { data.insert(pair
(nums[i], i)); } multimap
::iterator it =data.begin(); multimap
::reverse_iteratorrit = data.rbegin(); int items = 0; size = data.size(); while (items++ < size) { int tempResult = (*it).first +(*rit).first; if (target == tempResult) { int loc1, loc2; loc1 = (*it).second + 1; loc2 = (*rit).second + 1; if (loc1 > loc2) { result.push_back(loc2); result.push_back(loc1); } else { result.push_back(loc1); result.push_back(loc2); } break; } else if (target < tempResult) { ++rit; } else { ++it; } } return result;}

3.4 哈希实现方式

unordered_map: 该函数即哈希函数。该方法时间复杂度O(n)。

vector
Solution::twoSum1(vector
&nums, const int target){ vector
result; unordered_map
data; int size = nums.size(); for (int i = 0; i < size; ++i) { if (data.find(target - nums[i]) !=data.end()) { result.push_back(data[target- nums[i]] + 1); result.push_back(i + 1); break; } data[nums[i]] = i; } return result;}

4. 效率

在LeetCode系统中。上述代码效率不同。另外须要注意的是尽管使用哈希时间复杂度较低,可是每次插入结点时须要申请空间。因此当n较小时哈希反而比先排序的时间复杂度为O(nlogn)的算法慢。

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

你可能感兴趣的文章
【ABP杂烩】面向切面编程(AOP)知识总结
查看>>
使用PIP扩展BTARN
查看>>
android UI之Shape详解_GradientDrawable
查看>>
O/R Mapping实际开发经验之谈(转)
查看>>
在接口测试中怎么处理开发是否提供接口文档的总结
查看>>
Docker Swarm 让你事半功倍
查看>>
string.Format字符串格式说明
查看>>
oracle用户状态
查看>>
[转]IC行业的牛人
查看>>
linux 16进制 产看文件
查看>>
javaScript事件(四)event的公共成员(属性和方法)
查看>>
linux系统常用命令
查看>>
在 Word 中的受支持的区域设置标识符的列表
查看>>
Caffe + Ubuntu 14.04 64bit + CUDA 6.5 配置说明2
查看>>
An easy to use android color picker library
查看>>
win7 windows server 2008R2下 https SSL证书安装的搭配(搭配https ssl本地测试环境)
查看>>
Oracle SID爆破工具SidGuess
查看>>
用JAVA生成老电影海报
查看>>
c2java select algorithm
查看>>
闪聊的beta版推出了
查看>>