本博客rss订阅地址: http://feed.cnblogs.com/blog/u/147990/rss

LeetCode:Two Sum

题目链接

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

注意:元素可能有重复

最简单的做法就是一个两重循环,时间复杂度是O(n^2),下面提供两种更高效的解法

算法1:

将数组的数组映射到哈希表,key是元素的值,value是该值在数组中的索引。考虑到数组中元素有重复,我们使用STL中的unordered_multimap, 它可以允许重复的key存在。映射以后,对于数组中的某个元素num,我们只要在哈希表中查找num2 = target-num。需要注意的是在哈希表中找到了num2,并不一定代表找到了题目要求的两个数,比如对于数组2 7 11 15,target = 4,当num = 2时,num2 = target-num = 2,此时num2可以在哈希表中找到,但是num和num2指向的是同一个元素。因此当num2 = num时,在哈希表找到num2的同时,还需要保证哈希表中num2的个数>=2。

该算法时间复杂度为O(n)

 1 class Solution {
 2 public:
 3     vector<int> twoSum(vector<int> &numbers, int target) {
 4         int n = numbers.size();
 5         vector<int> res;
 6         unordered_multimap<int, int> umap;
 7         for(int i = 0; i < n; i++)
 8             umap.insert(make_pair(numbers[i], i));
 9         for(int i = 0; i < n; i++)
10         {
11             auto range = umap.equal_range(target - numbers[i]);
12             if(range.first != umap.end())//found
13             {
14                 if(numbers[i] != target - numbers[i])
15                 {
16                     auto range2 = umap.equal_range(numbers[i]);
17                     res.push_back(min(range.first->second, range2.first->second) + 1);
18                     res.push_back(max(range.first->second, range2.first->second) + 1);
19                 }
20                 else
21                 {
22                     auto ite = ++(range.first);
23                     if(ite != range.second)
24                     {
25                         auto range2 = umap.equal_range(numbers[i]);
26                         res.push_back(min(ite->second, range2.first->second) + 1);
27                         res.push_back(max(ite->second, range2.first->second) + 1);
28                     }
29                 }
30             }
31         }
32         return res;
33     }
34 };

算法2:

首先对数组按小到大排序,然后设定两个指针head、tail分别指向排序好的数组的首尾:                                     本文地址

  • 如果两个指针对应的元素和等于target,那么找到了
  • 如果两个指针对应的元素和小于target,那么需要增加和的大小,则把head指针向后移动
  • 如果两个指针对应的元素和大于target,那么需要减少和的大小,则把tail指针向前移动
  • head赶上tail指针时,结束

由于本题中需要返回最后找到的数对的索引,因此,排序是我们不移动原来数组的元素,只是把元素的的索引放到一个新的数组,对这个新的索引数组排序

 1 class Solution {
 2 private:
 3     static vector<int> *numbersCopy;
 4     static bool cmp(int idx1, int idx2)
 5     {
 6         return (*numbersCopy)[idx1] < (*numbersCopy)[idx2];
 7     }
 8 public:
 9     vector<int> twoSum(vector<int> &numbers, int target) {
10         numbersCopy = &numbers;
11         int n = numbers.size();
12         vector<int> res;
13         vector<int> idx(n);
14         for(int i = 0; i < n; i++)
15             idx[i] = i;
16         sort(idx.begin(), idx.end(), Solution::cmp);
17         
18         int head = 0, tail = n-1;
19         while(head < tail)
20         {
21             if(numbers[idx[head]] + numbers[idx[tail]] < target)
22                 head++;
23             else if(numbers[idx[head]] + numbers[idx[tail]] > target)
24                 tail--;
25             else //found
26             {
27                 res.push_back(min(idx[head], idx[tail]) + 1);
28                 res.push_back(max(idx[head], idx[tail]) + 1);
29                 break;
30             }
31         }
32         
33         return res;
34     }
35 };
36 vector<int> * Solution::numbersCopy = NULL;

 

推荐参考博客:

程序员编程艺术:第五章、寻找满足和为定值的两个或多个数

求和问题总结(leetcode 2Sum, 3Sum, 4Sum, K Sum)

编程之美2.12-快速寻找满足条件的两个数

 

【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3647244.html

posted @ 2014-04-05 15:20  tenos  阅读(2508)  评论(0编辑  收藏  举报

本博客rss订阅地址: http://feed.cnblogs.com/blog/u/147990/rss

公益页面-寻找遗失儿童