1. Two Sum

245 阅读4分钟

Description:

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, and you may not use the same element twice.

Example:

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

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

Solution:

1、先想到了两遍for循环,暴力解法,但是转念一想,肯定有其他方法可以降低时间复杂度,于是就有了第一种错误的方法。

排序后使用头指针和尾指针来做。

错误点:这样做忽略了给定的array元素位置不可变的前提(如果可以改变的话,返回下标还有什么意义呢?)

class Solution {

public:
    
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        sort(nums.begin(),nums.end());
        int begin = 0;
        int end = nums.size() - 1;
        while(begin < end) {
            if (nums[begin] + nums[end] > target) {
                end --;
            }
            else if(nums[begin] + nums[end] < target) {
                begin ++;
            }
            else {
                res.push_back(begin);
                res.push_back(end);
                break;
            }
        }
        return res;
    }
};

2、还是延续了上面的思路,接下来准备把排序之后的array存起来,然后在遍历一遍,找到原始array对应的两个值的下标,最后返回。

错误点:内存超了。

class Solution {

public:

    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        vector<int> tmp = nums;
        sort(tmp.begin(),tmp.end());
        int begin = 0;
        int end = tmp.size() - 1;
        while(begin < end) {
            if (tmp[begin] + tmp[end] > target) {
                end --;
            }
            else if(tmp[begin] + tmp[end] < target) {
                begin ++;
            }
            else {
                break;
            }
        }
        int i = 0;
        while (i < nums.size()) {
            if (nums[i] == tmp[begin]) {
                res.push_back(i);
            }
            if (nums[i] == tmp[end]) {
                res.push_back(i);
            }
        }
        return res;
    }
};

3、上面的方法行不通,还是需要遍历两遍来做。

c++:

class Solution {

public:

    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        for (int begin = 0; begin < nums.size()-1; begin++) {
            for (int end = begin +1; end < nums.size(); end++) {
                if (nums[begin] + nums[end] == target) {
                    res.push_back(begin);
                    res.push_back(end);
                    return res;
                }
            }           
        }
        return res;
    }
};

python:

class Solution(object):

    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        begin = 0
        res = []
        while begin < len(nums) - 1 :
            end = begin +1
            while end < len(nums) :
                if nums[begin] + nums[end] == target:
                    res.append(begin)
                    res.append(end)
                    return res
                end += 1
            begin +=1

4、看了官方给的solution,的确可以用空间换时间,这里需要变换的想到两个点:一个是a + b = c 也可以写为 a = c - b; 另一个是可以使用map将a和a的下标存起来。最后只需要判断(c - b)是否在map中就可以了。

易错点:题目中明确说明了,一个元素不会使用两遍,所以还需要添加判断条件,a, b的下标是否一致。

c++ :

class Solution {

public:

    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        map<int,int> tmp_map;
        for (int begin = 0; begin < nums.size(); begin++) {
            tmp_map[nums[begin]] = begin;
        }
        for (int begin = 0; begin < nums.size(); begin++) {
            if (tmp_map.find(target - nums[begin]) != tmp_map.end() && begin != tmp_map[target - nums[begin]]) {
                res.push_back(begin);
                res.push_back(tmp_map[target - nums[begin]]);
                return res;
            }
        }
        return res;
    }
};

python:

class Solution(object):

    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        res = []
        tmp_map = {}
        it = 0
        while it < len(nums):
            tmp_map[nums[it]] = it
            it += 1
        it = 0 
        while it < len(nums):
            if (target - nums[it]) in tmp_map and it != tmp_map[target - nums[it]]:
                res.append(it)
                res.append(tmp_map[target - nums[it]])
                return res
            it += 1

5、更好的写法:

这个是针对语法来说的,别人的可能写的更好,更加精简。

c++:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> map;
        
        for (int i = 0; i < nums.size(); ++i) {
            unordered_map<int,int>::iterator iter = map.find(target - nums[i]); 
            
            if (iter != map.end())
                return {iter->second, i};
                
                map[nums[i]] = i;
        }
        //error comes up if there isn't this last "return" line.
        return {0,1};
    }
};

python:

 class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        Dict = {}
        for i in range(len(nums)):
            if target - nums[i] in Dict:
                return [i,Dict[target-nums[i]]]
            else:
                Dict[nums[i]] = i

6、其他

map: map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。

unordered_map: unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此,其元素的排列顺序是无序的。