题述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
思路
刚看到这个题的第一想法就是无脑双循环 即暴力破解 于是就有了解法一 :
public class Solution {
public int[] TwoSum(int[] nums, int target) {
var res = new int[2];
for(var i=0;i<nums.Length;i++){
for(var j=i+1;j<nums.Length;j++){
// 以i为基数遍历后面的所有数
// 而j在循环的时候 其之前的数字必定已经被循环过了 即以i+1为初始值
if(nums[i]+nums[j]==target){
res[0]=i;
res[1]=j;
// 直接返回 否则在得出结果后依然会继续循环 浪费时间
return res;
}
}
}
// 结束所有循环后依然没有得到合理解
return res;
}
}
执行用时: 296 ms / beats 53% C# submitters
内存消耗: 32 MB / beats 15% C# submitters
常规解
遍历数组每个项与其他可配对项求和 得到需求值后返回这两个项的index ;
显然 这个解法过于普通
于是开始寻求其他更快的解法 …
解法二 :
public class Solution {
public int[] TwoSum(int[] nums, int target) {
var temp=0;
for(var i=0; i<nums.Length;i++){
// 逐数求差
temp = target-nums[i];
var index = Array.IndexOf(nums,temp);
if(index >= 0 && index!=i){
return new int[2]{i,index};
}
}
return null;
}
}
执行用时: 500 ms / beats 6% C# submitters
内存消耗: 31.5 MB / beats 49% C# submitters
哈哈哈哈哈哈尼玛 !?
正经人谁会用时间换空间…
这并不是我想要的效果…but, 这算是另一种思路
遍历整个数组 逐个计算需要的差
然后用Array.IndexOf的便利来直接获取需求值的序号(需求值存在的话)
这里有个坑 利用已经封装好的IndexOf方法
有没有看过IndexOf的源码 ? ? ?
如果内部实现也是遍历每个成员去比较 那么实际上这个解法和上个解法的时间复杂度同样是O(n²) 甚至会多出一些比较 比如 index < j 的那么些个数 …
所以貌似这个算法的耗时更久也是情理之中 ?
好吧
不难看出 时间损耗就是那两层循环
emmm …
那么 如果我在找到这个数的时候直接能得到他的index 那不就省掉了一层循环 ?
岂不美哉 ? ?
于是开始考虑用空间换时间…
解法三 :
public class Solution {
public int[] TwoSum(int[] nums, int target) {
Hashtable ht = new Hashtable();
for(var i=0;i<nums.Length;i++){
if(!ht.ContainsKey(target - nums[i])){
// 不存在指定值的键 插入等待下一个
ht.Add(nums[i],i);
}
else{
return new int[]{i,(int)ht[target - nums[i]]};
}
}
return null;
}
}
执行用时: 220 ms / beats 100% C# submitters
内存消耗: 32.9 MB / beats 5.03% C# submitters
利用Hashtable的特性
遍历数组 计算nums[i] 的需要的配对值是否存在与 ht 中 , 否则将
{ key = nums[i] , value = i } 存入ht
那么 在数组的其他数查找匹配值时 一旦找到存在需求值的键 即可得到其index
hashtable的性能诚不欺我
那么 问题又出现了 ContainsKey的内部是如何实现的 ?
盲猜一波其空间复杂度应该是O(1) 直接寻访Key值的存储数据 非null则存在 ?
好了 这道题目应该就折腾到这里 `( •̀ ω •́ )✧