今天我遇到这样一个问题,问题描述如下:
给出一个数组,再给定一个数target,如果数组中有两个数的和等于target,那么返回这两个数的索引,如果说有多对数都符合条件则返回第一对,返回的结果用一个长度为2的数组保存,并且返回的数组按升序排列:
如:[2,7,11,15] target=9,那么返回[1,2],这只是一个最普遍的例子,因为数组中可以有重复的数,如[0,4,1,0 ] target=0,那么返回[1,4],另外一个特例就是两个数可能在同一个位置上这样不能返回同一个索引,如[0,1,4] target=0,并不是返回[1,1],而是不存在这样两个数,讲清楚题之后那么我们再看具体的解题思路。
思路一:当然是最简单的啊,那就是穷举法,那么对上述所有情况都适用,但是时间复杂度为o(n*n),如果n变得很大时,那么就变得不可接受了。
思路二:试想一下在java当中,如果利用set来存储数组当中的每一元素的时候,那么可以减小时间复杂度,这时时间复杂度为o(n),思路是当遍历某一数n的时候,看target-n是否在set当中,如果存在那么,就证明这对数是存在的,但是我们仅仅是set是找不到,target-n的索引的,并且如果有两个索引在一个位置,那么这时set是无法区分的,有人数当遍历某个数的时候把它从集合中删除不就行了吗,就会解决现在这个问题,但是新的问题会出现,如果两个数相同的话,那么删除元素的方法是不能够解决的,基于上述无法解决的问题,我们想到了map,map的key保存的是数组中的数,而value则存着的是这个数的索引,思路是当遍历到元素n时判断,target-n是否在map中,如果在则返回索引,这是还是会出现上述的两个问题,首先如果有多个数重复的时候,那么map中同一个数它的value值存放的是,这些相同数的最后一个索引,所以我们在判断是否存在这样一对数的时候再加上条件,判断找到的索引,和当前遍历的元素的索引是不是相同的,如果相同则是没找到,如果不同才算找到了,这同时也解决了两个数的索引出现在同一个位置上的问题,所以问题得以解决,运用map时间复杂度可以达到o(n)。以下是我的代码:
package twoSum;
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int[] twoSum(int[] nums, int target) {
if(nums==null||nums.length<2){
return null;
}
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<nums.length;i++){
map.put(nums[i], i+1);
}
for(int j=0;j<nums.length;j++){
if(map.containsKey(target-nums[j])&&map.get(target-nums[j])!=(j+1)){
int[] t=new int[2];
t[0]=j+1;
t[1]=map.get(target-nums[j]);
return t;
}
}
return null;
}
public static void main(String[] args) {
int[] nums={0,4,3,0};
int[] ret=new Solution().twoSum(nums,0);
for(int i=0;i<ret.length;i++){
System.out.println(ret[i]);
}
}
}
对于此问题的扩展,其实还可以扩展到三个数,问题描述可以是这样,从一个数组中找出三个数的索引,让他们的和等于0,如果用穷举法的话,那么时间复杂度将达到o(n*n*n),但是如果运用上面的思路的话,遍历数组,选取一个数作为3个数中的一个数n,然后从剩余的数中找出两个数的和等于-n的两个数,那么这样的话,时间复杂度会减少到o(n*n),并且如果再仔细斟酌,那么第一个遍历过的数都不会被算在内,那么程序将会更加快,这里只提供思路,代码就不提供了,谢谢!!!