leetcode算法训练#1 Two Sum

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/solopointer/article/details/51356801

题目的大概意思是在一个无序数组中找到两个数字的下标,使得这两个数字的和刚好为指定数。

最简单的解是暴力搜索法,代码如下:

class Solution1 {
public:
<span style="white-space:pre">	</span>vector<int> twoSum(vector<int>& nums, int target) {
<span style="white-space:pre">		</span>for (unsigned int i = 0;i < nums.size();i++)
<span style="white-space:pre">			</span>for (unsigned int t = i+1;t < nums.size();t++)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>if (nums[i] + nums[t] == target)
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>vector<int> res;
<span style="white-space:pre">					</span>res.push_back(i);
<span style="white-space:pre">					</span>res.push_back(t);
<span style="white-space:pre">					</span>return res;
<span style="white-space:pre">				</span>}
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>return vector<int>();
<span style="white-space:pre">	</span>}
};

效果如下,因为时间复杂度是O(n^2),所以耗时很高
};


于是就有了改进思路:

1.对元素进行从小到大排序,时间复杂度O(nlgn)

2.设置头尾两个下标,尾下标从大到小,头下标每次从小到大

3.尾尾下标不必从最后一个开始递减,而是从k开始递减 k使得_numbers[k]+_numbers[0]<=target,因为如果一个数加上最小的数都比目标大,那结果肯定不包括这个数,这样就过滤掉了很多不可能的数字。

代码如下:

class Solution2 {
public:
<span style="white-space:pre">	</span>vector<int> twoSum(vector<int>& nums, int target) {
<span style="white-space:pre">		</span>vector<pair<int, unsigned int>> _numbers;
<span style="white-space:pre">		</span>vector<int> _res;
<span style="white-space:pre">		</span>unsigned int _count = 0;
<span style="white-space:pre">		</span>for_each(nums.begin(), nums.end(), [&_numbers, &_count](int a) {_numbers.push_back(make_pair(a, _count++));});
<span style="white-space:pre">		</span>sort(_numbers.begin(), _numbers.end(), [](pair<int, unsigned int> & a, pair<int, unsigned int> &b) {return a.first < b.first;});
<span style="white-space:pre">		</span>int _i_a = _numbers.size()-1;
<span style="white-space:pre">		</span>while (_numbers[_i_a].first+ _numbers[0].first > target&&_i_a >= 0)
<span style="white-space:pre">			</span>_i_a--;
<span style="white-space:pre">		</span>while (_i_a >= 0)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>int _i_b = 0;
<span style="white-space:pre">			</span>int _result = target + 1;
<span style="white-space:pre">			</span>while ((_result=_numbers[_i_a].first + _numbers[_i_b].first) < target&&_i_b < _i_a)
<span style="white-space:pre">				</span>_i_b++;
<span style="white-space:pre">			</span>if (_result == target)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>if (_numbers[_i_a].second < _numbers[_i_b].second)
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>_res.push_back(_numbers[_i_a].second);
<span style="white-space:pre">					</span>_res.push_back(_numbers[_i_b].second);
<span style="white-space:pre">				</span>}
<span style="white-space:pre">				</span>else
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>_res.push_back(_numbers[_i_b].second);
<span style="white-space:pre">					</span>_res.push_back(_numbers[_i_a].second);
<span style="white-space:pre">				</span>}
<span style="white-space:pre">				</span>return _res;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>_i_a--;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>return _res;
<span style="white-space:pre">	</span>}
};

开始的foreach的时间复杂度为O(n),而排序算法的时间复杂度为O(nlgn),下面的搜索算法的时间复杂度最坏情况下为O(n^2)

性能如下:



另外还有一个更简洁的办法,利用map或者哈希的低时间复杂度,来对每个元素进行检测:

对于当前元素n,若在map中发现target-n这个数,那么就代表找到答案了,否则吧n放入map,继续检测下一个元素,代码如下:

class Solution {
public:
	vector<int> twoSum(vector<int>& nums, int target) {
		vector<int> res;
		unordered_map<int,int> items;
		auto size = nums.size();
		for (int i = 0;i < size;i++)
		{
			if (items.find(target - nums[i]) != items.end())
			{
				vector<int> res = { items[target - nums[i]] ,i };
				return res;
			}
			else if(items.find(nums[i]) == items.end())
				items[nums[i]] = i;
		}

		return vector<int>();
	}
};

运行时间如下:


第四种方法:对数据进行排序后,使用一个头指针与一个尾指针,定义如下规则:

如果两个指针指向的数字之和小于target,则头指针向后移动,因为答案已经不可能包含当前头指针指向的数字

如果两个指针指向的数字之和大于target,则尾指针向前移动,英文答案已经不可能包含当前尾指针指向的数字

这样直到找到答案,时间复杂度为nlgn+n 即O(nlgn)

代码如下:

class Solution {
public:
	vector<int> twoSum(vector<int>& nums, int target) {

		vector<pair<int, unsigned int>> _numbers;
		vector<int> _res;
		unsigned int _count = 0;
		for_each(nums.begin(), nums.end(), [&_numbers, &_count](int a) {_numbers.push_back(make_pair(a, _count++));});
		sort(_numbers.begin(), _numbers.end(), [](pair<int, unsigned int> & a, pair<int, unsigned int> &b) {return a.first < b.first;});
		unsigned int start = 0, end = _numbers.size() - 1;
		while (start < end)
		{
			auto sum = _numbers[start].first + _numbers[end].first;
			if (sum < target)
				start++;
			else if (sum>target)
				end--;
			else
			{
				_res.push_back(_numbers[start].second);
				_res.push_back(_numbers[end].second);
				break;
			}
		}
		return _res;
	}
};



猜你喜欢

转载自blog.csdn.net/solopointer/article/details/51356801