题目及测试用例
package pid001;
/*两数之和
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
*/
public class main {
public static void main(String[] args) {
int[][] testTable = {{1,1,2},{1,1,2,2,5,6,7,7},{1,2,3,5},{-1,1,1,1}};
int[] testTable2={3,7,4,0};
for (int i=0;i<testTable.length;i++) {
test(testTable[i],testTable2[i]);
}
}
private static void test(int[] ito,int ito2) {
Solution solution = new Solution();
int[] rtn;
long begin = System.currentTimeMillis();
for (int i = 0; i < ito.length; i++) {
System.out.print(ito[i]+" ");
}//开始时打印数组
System.out.println("ito2= "+ito2);
rtn = solution.twoSum(ito,ito2);//执行程序
long end = System.currentTimeMillis();
for (int i = 0; i < rtn.length; i++) {
System.out.print(rtn[i]+" ");
}//打印结果几数组
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(错误)
原因是本解法是先排序,再返回数的index
而要求是返回未排序前的数组中数的index
不过觉得思路不错,排序后从头和尾相加
大了则后面-1
小了则前面+1
public int[] twoSum(int[] nums, int target) {
int length=nums.length;
if(length==1){
return null;
}
Arrays.sort(nums);
int begin=0;
int end=length-1;
while(true){
int sum=nums[begin]+nums[end];
if(sum>target){
end--;
continue;
}
else{
if(sum<target){
begin++;
continue;
}
else{
int[] result={begin,end};
return result;
}
}
}
}
解法2(成功,29ms,比较慢)
相当于死算法o(n2)
从第一个开始向后循环,每次都向后一个个查有没有和为target的
public int[] twoSum(int[] nums, int target) {
int length=nums.length;
for(int i=0;i<length;i++){
int now=nums[i];
for(int j=i+1;j<length;j++){
if(now+nums[j]==target){
int[] result={i,j};
return result;
}
}
}
return null;
}
解法3(错误)
是解法1的改进
创建了一个hashmap,在排序之前进行赋值,数的值为key,index为value,如果数重复,则index被覆盖,不过在本题中无所谓
本来以为无所谓,但在[3,3] 6的测试用例中失败
public int[] twoSum3(int[] nums, int target) {
int length=nums.length;
if(length==1){
return null;
}
Map map=new HashMap<Integer,Integer>();
for(int i=0;i<length;i++){
map.put(nums[i],i);//数的值为key,index为value,如果数重复,则index被覆盖,不过在本题中无所谓
}
Arrays.sort(nums);
int begin=0;
int end=length-1;
while(true){
int sum=nums[begin]+nums[end];
if(sum>target){
end--;
continue;
}
else{
if(sum<target){
begin++;
continue;
}
else{
int[] result={(int)map.get(nums[begin]),(int)map.get(nums[end])};
//int[] result={begin,end};
return result;
}
}
}
}
解法4(成功,7ms,很快)
时间 o(nlogn)
对解法三的进一步改进,由于hashmap有重复的数的出现,本方法先copy了一个数组,最后再用找到的两个数在copy的数组中进行查找,手动排除重复的可能。
算法思路主要为解法1
排序后从头和尾相加
大了则后面index-1
小了则前面index+1
最后再copy的数组查找index
public int[] twoSum(int[] nums, int target) {
int length=nums.length;
int beginIndex=0;
int endIndex=0;
if(length==1){
return null;
}
int[] copy=Arrays.copyOf(nums, length);
Arrays.sort(nums);
int begin=0;
int end=length-1;
while(true){
int sum=nums[begin]+nums[end];
if(sum>target){
end--;
continue;
}
else{
if(sum<target){
begin++;
continue;
}
else{
for(int i=0;i<length;i++){
if(copy[i]==nums[begin]){
beginIndex=i;
break;
}
}
for(int i=0;i<length;i++){
if(copy[i]==nums[end]){
if(i!=beginIndex){
endIndex=i;
break;
}
}
}
int[] result={beginIndex,endIndex};
return result;
}
}
}
}
解法5(成功,7ms,很快)
可以使用哈希表优化,让寻找差值是否在nums中这个操作的时间复杂度从O(N)下降到O(1),整体时间复杂度变为O(N),性能得到极大提升。
事实证明,我们可以一次完成。在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。
在hashmap中以数的值为key,index为value,每次检测是否有target-值得key,时间o(n)
比解法4快
public int[] twoSum(int[] nums, int target) {
int length=nums.length;
int[] result=new int[2];
//key为nums里的value,value为nums里的index
HashMap<Integer, Integer> map=new HashMap<>();
for(int i=0;i<length;i++){
if(map.containsKey(target-nums[i])){
result[0]=map.get(target-nums[i]);
result[1]=i;
return result;
}
map.put(nums[i], i);
}
return result;
}