题目
给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标。注意这里下标的范围是 1 到 n,不是以 0 开头。
思路
这道题目是找到数组中和为指定值的两个元素,需要遍历每个值num,判断数组是否包含(target-num),并且(target-num)和num不是同一个数。
算法实现
方法1:O(n^2)
如果不考虑算法时间复杂度,可以使用最简单易行的方式进行实现。
public class Solution {
/*
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
public int[] twoSum(int[] numbers, int target) {
// write your code here
for(int i = 0 ; i < numbers.length - 1; i++)
{
for(int j = i+1; j < numbers.length; j++)
{
if(numbers[i]+numbers[j] == target)
{
return new int[]{i+1, j+1};
}
}
}
throw new IllegalArgumentException("no such sum");
}
}
方法2:O(n)
根据算法思路可知,需要判断数组中是否包含某元素以及获取元素的角标。而对于数组对象来说,并没有此功能,因此可以将数组转换成List集合,并使用集合的indexOf方法进行编写。
public class Solution {
/*
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
public int[] twoSum(int[] numbers, int target) {
// write your code here
ArrayList<Integer> al = new ArrayList<Integer>();
for(int i = 0; i < numbers.length; i++)
{
al.add(numbers[i]);
}
//遍历集合
for(int i = 0; i < al.size(); i++)
{
int num1 = al.get(i);
int num2 = target - num1;
//如果集合中包含(target-遍历的值)
if(al.contains(num2))
{
if(num1 != num2)
{
return new int[]{i+1, al.indexOf(num2)+1};
}
else
{
//如果两个元素相同,需要判断数值中是否包含两个相同的元素
int index1 = al.indexOf(num1);
if(index1 != al.size()-1)
{
List<Integer> list = al.subList(index1+1, al.size());
int index2 = list.indexOf(num1);
//如果数组包含两个相同的元素并且和是target
if(index2 != -1)
{
return new int[]{index1+1, index1+index2+2};
}
}
}
}
}
throw new IllegalArgumentException("no such sum");
}
}
方法3:O(n)
方法2中使用ArrayList集合实现此功能,代码较为复杂,并且需要创建多个集合,占用内存空间较大,所以进行改进,使用Map集合实现,此方法使用HashMap。
HashMap集合中的键是唯一的,在使用put(key, value)方法添加新元素时,会调用key.hashCode()计算hash值,如果集合中有hash值相同的键,会继续调用key.equals(HashMap.e)判断HashMap集合中是否包含和key相同的键,如果有就会使用新的值替换旧的值。
将数组中元素和角标作为映射对存入HashMap集合时,如果有重复出现的数值,那么它在Map集合中对应的值是其在数组中最后一次出现的角标。
public class Solution {
/*
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
public int[] twoSum(int[] numbers, int target) {
// write your code here
HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
//将元素和角标存入Map集合
//对于重复的元素,其在Map集合中对应的值是其在数组中最后一次出现的角标
for(int i = 0; i < numbers.length; i++)
{
hm.put(numbers[i], i);
}
//遍历数组
for(int i = 0; i < numbers.length; i++)
{
int temp = target - numbers[i];
//当集合中包含temp值时,并且其角标和numbers[i]不相同,意味着temp和numbers[i]不是同一个数
//返回数组
if(hm.containsKey(temp) && hm.get(temp) != i)
{
return new int[]{i+1, hm.get(temp)+1};
}
}
throw new IllegalArgumentException("no such sum");
}
}
错误总结
1、字符串的长度是一个方法,length(),数组的长度是属性,length。注意区分
2、对于传入的字符串和数组,需要考虑其是否是空的情况。
3、Arrays.asList(T... a)和subList(from, to)返回的都是List集合,是多态。