题目
Java解法
暴力解法:直接用两层循环
public class Solution {
public int[] TwoSum(int[] nums, int target) {
int[] index = new int[2];
for (int i = 0; i < nums.Length - 1; i++)
{
for (int j = i + 1; j < nums.Length; j++)
{
if (nums[i] + nums[j] == target)
{
index[0] = i;
index[1] = j;
return index;
}
}
}
return new int[] { -1, -1 };
}
}
使用哈希表法(或称为查找表法)
即一次循环进行遍历,如果哈希表里有target-当前数字,那么返回哈希表中存储的下标和当前数字下标,如果没有,存入哈希表
此处有个杠精问题,其实很值得探讨,那就是当出现多个重复数字时怎么办,hashmap是不允许key重复的。例如[3,2,3,2,3]这种。不过经过分析与测试后,这种问题仍然可以用下面这个算法解决,虽然[3,2,3,2,3]这种大概率是不满足题目里“只对应一个答案”这个要求。需记住的是,在hashmap里,当key重复了,put时是更新,而不是报错。
package A1twosum;
import org.junit.Test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class TwoSumDemo {
@Test
public void Test() {
int[] nums = new int[]{2, 7, 11, 15};
int target = 9;
int[] ints = twoSum(nums, target);
System.out.println(ints[0] + " " + ints[1]);
}
/**
* 此方法为哈希表法(或称为查找表法)
* 时间复杂度是O(n),此处n是数组的长度,因为哈希表存或者取都是O(1)的时间复杂度
* 空间复杂度O(n),哈希表里最多需要存n-1个键值对
* @param nums
* @param target
* @return
*/
public int[] twoSum(int[] nums, int target) {
//待查找数组长度
int len = nums.length;
//初始化一个哈希表
//java官方文档建议我们在定义哈希表时定义其初始容量,避免其扩容带来的性能消耗
//此处初始值设为len - 1,原因是哈希表最多存到len-1就能判断找到合适的结果或者没有合适的结果了
HashMap<Integer, Integer> hashMap = new HashMap<>();
//由于第一个元素一定在哈希表里(或者说在它之前)没有与它对应的数值,因此直接存入哈希表
hashMap.put(nums[0], 0);
//从数组下标为1的数值开始遍历
for (int i = 1; i < len; i++) {
//由于此变量超过一处被使用,因此使用变量存储
int another = target - nums[i];
//判断在哈希表中是否存在与这个元素对应求和为target的元素
if (hashMap.containsKey(another)) {
//如果存在,返回即可
return new int[]{i, hashMap.get(another)};
}
//如果不存在,则存入hashmap
hashMap.put(nums[i], i);
}
throw new IllegalArgumentException("这个数组没有合适的两数之和结果");
}
}
C++部分
什么是vector?
vector是一种高级的数组,具有数组没有的一些高级功能
如何初始化?
vector<类型> 名字;
vector<int> results;
如何添加元素?
使用push_back进行添加,这时元素是添加在数组尾部的
results.push_back(i);
c++版本的本题O(n2)实现
class Solution {
public:
//O(n2)的做法
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> results;
for(int i = 0; i < nums.size(); i++){
for(int j = 0; j < i; j++){
if(nums[i]+nums[j] == target){
results.push_back(i);
results.push_back(j);
}
}
}
return results;
}
};
C++的哈希表是什么?
unordered_map,即无序map
如何初始化哈希表?
unordered_map<int,int> hashmap;
如何获取哈希表里key为i的键值对?
auto it = hashmap.find(i);
如何输出键值对的键与值?
it->first;//键
it->second;//值
如何判断获取的键值对是否存在?
if(it != hashmap.end()){
//存在
}
如何向哈希表里添加键值对 key value?
hashmap[key] = value;
C++版本的O(1)本题做法
class Solution {
public:
//O(1)的做法
vector<int> twoSum(vector<int>& nums, int target) {
//创建无序哈希表
unordered_map<int,int> hashtable;
for(int i = 0; i < nums.size(); i++){
//判断哈希表里是否存在target - nums[i]这个key
//auto算是个占位符,自动推测后面已经初始化的元素应该声明的类型
auto it = hashtable.find(target - nums[i]);
//如果存在直接返回,如果不存在,返回结果与hashtable.end()一致
if(it != hashtable.end()){
//注意it->second指的是键值对里面的值,it->first指的是键
return {it->second, i};
}
//向哈希表里添加元素
hashtable[nums[i]] = i;
}
return {};
}
};
python3 解法
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 建立一个字典,将当前数字与字典内的值进行对应,如果target-当前数字在字典内存在
# 返回当前下标与字典值的下标
hashtable = dict()
# 遍历数组,获得下标与值
for i,num in enumerate(nums):
if (target - num) in hashtable:
return [hashtable[(target - num)],i]
hashtable[num] = i
return
需要注意的两个地方,一是建立新的空字典,可以使用dict()。二是判断某个值是否在字典的key里面,可以直接用in