最近准备开始刷起LeetCode了,几百年没有写过代码了真的已经对各种数据结构和算法都很陌生了,于是决定从今天开始每天两道题,暂且决定是从Easy开始,用C++来写,希望能坚持下来!
题目:
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].
题目的意思就是给定一组整数,找出这个数组中的相加起来和为target的两个数的下标,并且假设数组中有且仅有一组这样的两个数,也不能使用同一个数两次。
最直观的想法就是直接暴力双重循环,如果符和条件就返回,这样做的时间复杂度为O(n^2),LeetCode的运行时间为196ms,代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
for (int j = i + 1; j < nums.size(); j++) {
if (nums[i] + nums[j] == target) {
result.push_back(i);
result.push_back(j);
break;
}
}
}
return result;
}
};
参考了LeetCode给的解决方法,可以使用HashMap来把时间复杂度降为O(n),但是作为代价,空间复杂度也为O(n)。使用HashMap一共有两种解法:一种是首先遍历数组一次,把数字和下标作为key和value存在HashMap中,然后再遍历一次数组,从HashMap中寻找有没有符合条件的数字;另一种只需要遍历一次数组,在遍历的同时查找当前的HashMap中是否有符合条件的数字,如果没有的话就把当前遍历到的数字加入HashMap。
两次遍历数组需要注意第二次遍历时的判断条件要加上不能两次使用同一个数,也就是target - x不能等于x。代码如下,运行时间4ms:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
hash[nums[i]] = i;
}
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (hash.count(complement) && hash[complement] != i) { // 注意同一个数不能使用两次
result.push_back(i);
result.push_back(hash[complement]);
return result;
}
}
return result;
}
};
一次遍历数组的时候,由于每次查找的时候都找的是在这个数之前已经存放在HashMap中的结果,因此如果想让下标较小的先输出,应当先输出HashMap中的下标、再输出当前的下标。代码运行时间8ms:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (hash.count(complement)) {
result.push_back(hash[complement]);
result.push_back(i);
return result;
}
hash[nums[i]] = i;
}
return result;
}
};
最后想补充一点,之前学C++的时候没有把STL用得很熟,导致已经不记得HashMap对应的数据结构及其用法,通过参考大佬们的C++代码才想起来了unordered_map,在本题中使用到的两个基本用法分别是插入和查找是否有这个key:
插入可以通过直接赋值来完成:hash[key] = value;
查找可以使用计数来完成:hash.count(key)返回的是key在这个HashMap中的key中出现的次数。
2020.3.18 Updated with Java
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> numToIndex = new HashMap<>();
int result[] = new int[2];
for (int i = 0; i < nums.length; i++) {
int remain = target - nums[i];
if (numToIndex.containsKey(remain)) {
return new int[] {numToIndex.get(remain), i};
}
numToIndex.put(nums[i], i);
}
throw new IllegalArgumentException("No solution");
}
}
笔记:
1. return数组:return new int[] {1, 2};
2. 如果没有结果可以直接throw new IllegalArgumentException