LeetCode刷题系列---1. 两数之和

LeetCode刷题系列---1. 两数之和

  • 题目
    • 示例
  • 解题
    • 解题思路1
      • 本地代码
      • 提交代码
    • 解题思路2
      • 本地代码
      • 提交代码
    • 别人的题解
      • 别人的代码

题目

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
做题可以直接到两数之和

示例

输入

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

输出

[0, 1]

解释

nums[0] + nums[1] = 2 + 7 = 9

解题

依然给出两份代码,一份是本地可运行的,一份是提交的。

解题思路1

因为题目中没有说数组有序,所以应该是无序数组,首先想到的就是暴力解法。遍历数组中的任意两组和,直到找到一个与目标值匹配的组合,返回结果。
这种解决方案显然并不好,时间复杂度O(n^2),很高。

本地代码

#include 
#include 

using namespace std;

int n, nums[20000];
int target;

vector<int> twoSum(){
 	vector<int> v;
	int p1 = 0;
	while(p1<n){
		int p2 = p1+1;
		while(p2<n){
			if(nums[p1] + nums[p2] == target){
				v.push_back(p1);
				v.push_back(p2);
				return v;
			}
			p2++;
		}
		p1++;
	}
}

int main(){
	scanf("%d", &n);
	for(int a=0; a<n; a++)
		scanf("%d", &nums[a]);
	scanf("%d", &target);
	
	vector<int> res = twoSum();
	
	printf("%d %d", res[0], res[1]);
	
	return 0;
}

提交代码

vector<int> twoSum(vector<int>& nums, int target) {
    int n = nums.size();
    vector<int> v;
	int p1 = 0;
    bool isfind = false;
	while(p1<n){
		int p2 = p1+1;
		while(p2<n){
			if(nums[p1] + nums[p2] == target){
				v.push_back(p1);
				v.push_back(p2);
                isfind = true;
			}
            if(isfind)  break;
			p2++;
		}
        if(isfind)   break;
		p1++;
	}
    return v;
}	

开始提交时提交代码与本地代码一致,都是发现正解直接返回,结果提交编译不通过,报错

Char 5: error: control reaches end of non-void function [-Werror=return-type]

编译器认为这种写法可能存在某些情况得不到返回结果。于是改成了上文的形式,在代码段的结束位置返回结果向量v。

解题思路2

暴力搜索太慢了。昨天刚学了“双指针法”,该方法的其中一种适用场景就是,对于一个有序数组,找到两个数的和等于特定值。
本题中给的是无序数组,要想变成有序数组,需要先排序并且记录排序后的每个元素对应的原始下标,再用双指针法寻找加和等于目标值的两个元素,并返回结果。
快速排序的时间复杂度是O(nlogn),双指针法寻找结果的时间复杂度也是O(nlogn)。

本地代码

#include 
#include 
#include 

using namespace std;

int n, nums[20000];
int target;

struct num{
	int value;
	int index;
	num(){
		value = 0;
		index = 0;
	}
	num(int a, int b){
		value = a;
		index = b;
	}
};

num in[20000];

bool operator<(num a, num b){
	if(a.value < b.value) return true;
	return false;
}

vector<int> twoSum(){
 	vector<int> v;
 	
 	for(int a=0; a<n; a++)
 		in[a] = num(nums[a], a);
 	sort(in, in+n);
 	
 	int p1=0, p2=n-1;
 	while(p1<p2){
 		if(in[p1].value + in[p2].value == target){
 			v.push_back(in[p1].index);
 			v.push_back(in[p2].index);
 			break;
		}
		else if(in[p1].value + in[p2].value < target)
			p1++;
		else p2--;
	}
 	return v;
}

int main(){
	scanf("%d", &n);
	for(int a=0; a<n; a++)
		scanf("%d", &nums[a]);
	scanf("%d", &target);
	
	vector<int> res = twoSum();
	
	printf("%d %d", res[0], res[1]);
	
	return 0;
}

提交代码

    struct num{
	    int value;
	    int index;
	    num(){
		    value = 0;
		    index = 0;
	    }
	    num(int a, int b){
		    value = a;
		    index = b;
	    }
    };

    num in[20000];

    bool operator<(num a, num b){
	    if(a.value < b.value) return true;
	    return false;
    }
    
class Solution {
public:    
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> v;
        int n = nums.size();
        for(int a=0; a<n; a++)
 		    in[a] = num(nums[a], a);
 	    
        sort(in, in+n);
 	
 	    int p1=0, p2=n-1;
 	    while(p1<p2){
 		    if(in[p1].value + in[p2].value == target){
 			    v.push_back(in[p1].index);
 			    v.push_back(in[p2].index);
 			    break;
		    }
		    else if(in[p1].value + in[p2].value < target)
			    p1++;
		    else p2--;
	    }
 	    return v;
    }
};

刚开始提交的时候把我自己写的所有内容都放在class内了,结果编译不通过,报错

error: 'bool operator< must have exactly one argument

原因是类内的运算符重载,只接受一个参数,是将传入参数与类试题进行运算。而我需要的是两个结构体之间的运算,所有把结构体定义和运算符重载移到类外,就能通过了。

别人的题解

看别人的题解,很多人提到通过哈希表解决,时间复杂度能达到O(n),太强了。
遍历数组nums中的元素,在hash表的第nums[i]的位置存入下标i,并查找目标值减当前值是否已经在哈希表中了。如果在则返回对应的下标和当前下标。

别人的代码

    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hash;
        for(int i = 0; i < nums.size(); i++){
        	if(hash.count(target - nums[i])) return {hash[target - nums[i]], i};
        	hash[nums[i]] = i;
		}
		return {-1, -1};
    }

【注】题目中提到不能重复使用同一个元素,即如果给定数组是[2, 4, 6],目标值是8,应该是2+6得到的,而不能是4+4得到的。上述写法其实可以保证元素不重复使用。因为先检查目标值-当前值是否在hash表中,找不到的话再将当前值存入hash表。如果能找到的肯定不当前值(因为还没有存)。
参考两数之和评论区
两数之和官方题解

你可能感兴趣的:(LeetCode刷题)