[Leetcode] 1. Two Sum 解题报告

题目:

 

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

 

UPDATE (2016/2/13):
The return format had been changed to zero-based indices. Please read the above updated description carefully.

思路:

1、暴力枚举法:两重循环搜索所有的情况,时间复杂度O(n^2),空间复杂度O(1)。肯定无法满足题目要求。

2、将数组排序(前提是允许修改原数组),然后用两个指针从左右分别扫描数组:

1)如果当前和大于target,则右指针左移一位;

2)如果当前和小于target,则左指针右移一位;

3)如果当前和等于target,则加入结果集中,并返回(由于题目中假设每对输入中有且仅有一对结果)。

这种方法中排序的时间复杂度是O(n*logn),扫描数组的时间复杂度是O(n),所以总体时间复杂度是O(n*logn),空间复杂度是O(1)。

3、定义一个hash表,并且依次扫描原数组中的数。如果hash表中存在(target - nums[i]),则分别两者的下标;否则将nums[i]放入hash表中。这种方法的时间复杂度可以降至O(n),但是空间复杂度为O(n),是一种典型的用空间换时间的做法。

 

注意target - nums[i]有可能越界,所以需要将remain的类型定义为long long(不过目前的测试用例似乎没有测试到这种edge case)。

 

代码:

C++:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
        unordered_map<int, int> hashMap;
    	std::vector<int> indices;
    	for (size_t i = 0; i < nums.size(); i++)
    	{
    		long long remain = target - nums[i];        // avoid the overflow of int
    		if(remain < INT_MIN || remain > INT_MAX)
    		    continue;
    		if (hashMap.find(remain) != hashMap.end())
    		{
    			indices.push_back(hashMap[remain]);
    			indices.push_back(i);
    			return indices;
    		}
    		hashMap.insert(pair<int, int>(nums[i], i));
    	}
    	return indices;
    }
};

Python3:

class Solution:
    def twoSum(self, nums: 'List[int]', target: 'int') -> 'List[int]':
        if len(nums) <= 1:
            return False
        indices = {}
        for i in range(len(nums)):
            if nums[i] in indices:
                return [indices[nums[i]], i]    # return the results
            else:
                indices[target - nums[i]] = i   # add this to indices

Follow up:

1、如果算法可能无解,或者有多个解,则现有算法需要如何修改?

考虑到target具有不同的分解方式,例如3+5=8,并且2+6=8,所以在获得一个解时就不能提前返回了。此外,由于数组中还可能有重复元素,所以最好将hashMap的value类型修改为set<int>,而且必须首先对整个数组做一个遍历,建立起一个包含完整数据的hashMap,然后再对数组进行第二次扫描。在这个过程中,为进一步提高效率,可以考虑第一次扫描时,在hashMap中只存放小于等于target/2的值。然后在第二次扫描时,只有遇到大于target/2的值,才在hashMap中找对应项。当然最后别忘了处理一下target/2的特殊情况。

2、如果给定的数组特别大,则怎么办?如果有多台计算机可供使用,则如何优化算法?

如果数组特别大,则意味着无法将它们全部同时加入内存。假如有多台计算机,可以考虑将数组拆分,然后分别计算,最后合成结果。假如有n台计算机,我们可以将数组中小于等于target/2的所有数分成n份,然后分别计算。假如其中一份的范围是[left_min, left_max],则在该计算机上只考虑范围在[target - left_max, target - left_min]之内的数。最后将每台计算机上的计算结果合并起来即可。此时target/2的情况也需要特殊处理。至于如何拆分数据,则有两种思路可供考虑:1)在一台超级计算机上将数据将数据分成n份,然后分别发送到各台计算机;2)将数组数据复制n份,分别存到各台计算机上,然后每台计算机处理的时候,只处理处于自己处理范围之内的数据。这两种方式各有优劣。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值