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。

這個題目也是逆向思維的簡單應用,並不需要複雜的算法和精妙的構思,反轉一下足夠。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章