Two Sum-n方优化与C++map的使用

LeetCode第一题,刚拿到题目时虽然明知道n方的遍历算法会超时,但还是不信邪的提交了一次,然而编程不存在运气,TLE不可避免。但是之后的思维方式比较直接,我并没有立刻想到O(n)的方法,想了一种先对数组进行排序,利用目标数和待选择的数的关系来减小搜索范围:

1.不存在负数:那么比目标数大的数不必搜索

2.存在负数:搜索负数和比目标大的数,或者搜索正数比目标小的数;这种情况还存在全为负数,只能按照最差的n方方式搜索。

按照这个优化思路,虽然算法严格意义上来说是n方复杂度的,但是实际性能并不一定这么差,以下是AC代码:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
typedef struct newtype
{
    int num;int index;
}Data;
int cmp ( const void *a , const void *b )
{
    Data *c = (Data *)a;Data *d = (Data *)b;
    if(c->num != d->num)
        return c->num - d->num;
    else
        return d->index - c->index;
}

int* twoSum(int* nums, int numsSize, int target) {
    int *res,i,j,fuflag=numsSize,bigflag=numsSize;
    int tempgflag=0;
    int tempres;
    Data *data=(Data *)malloc(sizeof(Data)*numsSize);
    for(i=0;i<numsSize;i++)
    {
        data[i].index=i;
        data[i].num=nums[i];
    }
    res=(int *)malloc(sizeof(int)*2);
    qsort(data,numsSize,sizeof(Data),cmp);
    for(i=0;i<numsSize;i++)
    {
        if(data[i].num<0)
            fuflag=i;
        if(data[i].num<=target)
            bigflag=i;
    }
    //1.无负数,只需到比这个数小的位置
    if(fuflag==numsSize)
    {
        for (i = 0; i <=bigflag; i++)
            for (j = i+1; j <=bigflag; j++)
                if (data[i].num + data[j].num == target) {
                    if (data[i].index > data[j].index) {
                        res[0] = data[j].index + 1;
                        res[1] = data[i].index + 1;
                    } else {
                        res[1] = data[j].index + 1;
                        res[0] = data[i].index + 1;
                    }
                    break;
                }
    }
    else//2.有负数,所有数都比这个数大
    {

        for (i = 0; i <= fuflag; i++)
            for (j = bigflag + 1; j < numsSize; j++)
                if (data[i].num + data[j].num == target) {
                    tempgflag=1;
                    if (data[i].index > data[j].index) {
                        res[0] = data[j].index + 1;
                        res[1] = data[i].index + 1;
                    } else {
                        res[1] = data[j].index + 1;
                        res[0] = data[i].index + 1;
                    }
                    break;
                }
        if(tempgflag==0)
        {
            for (i = fuflag + 1; i <= bigflag; i++)
                for (j = i + 1; j <= bigflag; j++)
                    if (data[i].num + data[j].num == target) {
                        tempgflag=1;
                        if (data[i].index > data[j].index) {
                            res[0] = data[j].index + 1;
                            res[1] = data[i].index + 1;
                        } else {
                            res[1] = data[j].index + 1;
                            res[0] = data[i].index + 1;
                        }
                        break;
                    }
        }
        if (tempgflag == 0) {
            for (i = 0; i <= numsSize; i++)
                for (j = i + 1; j <= numsSize; j++)
                    if (data[i].num + data[j].num == target) {
                        if (data[i].index > data[j].index) {
                            res[0] = data[j].index + 1;
                            res[1] = data[i].index + 1;
                        } else {
                            res[1] = data[j].index + 1;
                            res[0] = data[i].index + 1;
                        }
                        break;
                    }
        }
    }
    return res;
}
n方优化

然而在提交之后看了solution才想到另外两种方法,由于确定是两个数字,所以用目标数减去当前某个数字,然后再在候选数里查找这个数!

可以用二分查找,也可以用hash表。

接下来就是使用C++ STL map来实现这个hash过程。

map的使用主要包括声明,赋值,查找,使用迭代器。

声明:

map<int, int> datamap;

赋值:

map遵循<key ,value >的原则,key是不可以重复的!

for(i=0;i<n;i++)
        datamap[nums[i]]=i;

查找:

map<int,int>::iterator it;

it=datamap.find(target-nums[i]);

使用迭代器:

map的迭代器和vector并不相同,需要使用->来获取元素不能直接使用*

if(it!=datamap.end()&&it->second!=i)

使用map的AC代码:

 1 class Solution {
 2 public:
 3     vector<int> twoSum(vector<int>& nums, int target) {
 4         map<int, int> datamap;
 5         vector<int> res;
 6         int i;
 7         int n=nums.size();
 8         for(i=0;i<n;i++)
 9             datamap[nums[i]]=i;
10         map<int,int>::iterator it;
11         for(i=0;i<n;i++)
12         {
13             it=datamap.find(target-nums[i]);
14             if(it!=datamap.end()&&it->second!=i)
15             {
16                 if(i>it->second){
17                     res.push_back(it->second + 1);
18                     res.push_back(i + 1);
19 
20                 }
21                 else
22                 {
23                     res.push_back(i + 1);
24                     res.push_back(it->second + 1);
25 
26                 }
27                 break;
28             }
29         }
30         return res;
31 
32     }
33 };
map

 

本想再试一下hashmap,但是由于并不是标准C++库,所以需要以下头文件和命名空间:

#include <ext/hash_map>
using namespace __gnu_cxx;

才可以在linux上的Eclispe里编译,但是提交发现leetcode的评测环境并不支持以上库,也就没有再试,但是看到网上很多推荐使用unordered_map:

#include <tr1/unordered_map>

使用方法和map,hashmap类似。

PS:

这个题目的数据并不是排好序的!

以下是几组容易wa的测试数据:[-1,-2,-3,-4,-5] -8 ,[0,3,4,0] 0,[-3,4,3,90] 0。

这个题目也是逆向思维的简单应用,并不需要复杂的算法和精妙的构思,反转一下足够。

 

posted on 2015-06-26 12:32  holyprince  阅读(340)  评论(0编辑  收藏  举报

导航