LeetCode || Two Sum

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jiadebin890724/article/details/23305449

Two Sum

 Total Accepted: 16363 Total Submissions: 87273My Submissions

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

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note 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

1、code_v1:
class Solution {
public:
    vector<int> twoSum(vector<int> &numbers, int target) {
        int i, j, sum;
        vector<int> results;
        for(i=0; (i<numbers.size()-1); i++){
            //if(numbers[i]>target) continue; //这样判断不行,因为可能有负数+正数=target的情况
            for(j=i+1; j<numbers.size(); j++){
                //if(numbers[j]>target) continue;
                sum=numbers[i]+numbers[j];
                if(sum==target){
                    //cout<<"index1="<<(i+1)<<", index2="<<(j+1)<<endl;
                    results.push_back(i+1);
                    results.push_back(j+1);
                }
            }
        }
        return results;
    }
};

此代码提交后会出现超时问题,看来系统不能容忍O(N^2)的方法了,在讨论板里看到了O(N)的方法,使用hashtable,java编写,代码如下:


思路是循环一次,每次都判断当前数组索引位置的值在不在hashtable里,不在的话,加入进去,key为数值,value为它的索引值;在的话,取得他的key,记为n(此时n一定小于循环变量i),接下来再在hashtable中查找(target-当前数值)这个数,利用了hashtable中查找元素时间为常数的优势,如果找到了就结束,此处需要注意的是,如果数组中有重复的值出现,那么第二次出现时就不会加入到hashtable里了,比如3,4,3,6;target=6时,当循环到第二个3时,也可以得到正确结果。
        最终ac的代码如下:
class Solution {
public:
    vector<int> twoSum(vector<int> &numbers, int target) {
        int i, sum;
        vector<int> results;
        map<int, int> hmap;
        for(i=0; i<numbers.size(); i++){
            if(!hmap.count(numbers[i])){
                hmap.insert(pair<int, int>(numbers[i], i));
            }
            if(hmap.count(target-numbers[i])){
                int n=hmap[target-numbers[i]];
                if(n<i){
                    results.push_back(n+1);
                    results.push_back(i+1);
                    //cout<<n+1<<", "<<i+1<<endl;
                    return results;
                }

            }
        }
        return results;
    }
};

总结:读完题首先想到的就是两层遍历法,但是显然时间复杂度太高,是O(N^2),不符合要求,于是就应该想如何降低复杂度,首先应该想将逐个比较转变为直接查找,即首先计算出 target与当前元素的差,然后在序列中寻找这个差值,这样首先就把问题简化了,而寻找的过程可以先对序列进行快排,然后二分查找,这样整体的复杂度就降低为 O(N*logN) 了;查找最快的方法是利用一个 map容器存储每个元素的索引,这样取得某个特定元素的索引只需要常数时间即可完成,这样就更快了,最多只需遍历一次序列,将元素及其索引加入map中,在遍历的过程中进行对应差值的查找,如果找到了就结束遍历,这样时间复杂度最多为 O(N),It's amazing!
        本来想用C++的hash_map,后来发现STL并没有这个容器,貌似需要自己实现代码才能用,遂用map了,map底层使用红黑树实现的,所以它的查找时间是O(logN),略逊于hash_map,但是这不是绝对的,hash_map虽然理论上是O(N),其实他还有计算hash值的时间消耗,也存在时间比O(logN)还大的时候(在一篇博客里看到的)。还要注意在leetcode里提交时要把cout的代码注释掉,否则可能会导致评判结果出错,本题还要注意就是map的count函数用于查找某个key是否存在,存在返回1,否则返回0;根据某个key取得其在map中的value值的方法是直接用map[key]即可。

总之,这是自己做的第一道leetcode题,感觉比其他oj要严格一些,比如这题有严格的执行时间要求,O(N^2)的不能过,可以给自己优化程序的理由。继续加油!



展开阅读全文

没有更多推荐了,返回首页