[leetcode]3Sum Closest

来源:互联网 发布:java将map转换成json 编辑:程序博客网 时间:2022/08/17 12:25

3Sum Closest

题意:给定一个array和一个target,找出三个数的和与target最接近,输出这三个数的和。

解法:

         O(N^3):暴力方法,竟然能过,不能理解。

public int threeSumClosest2(int[] num, inttarget) {

                   intclosest=Integer.MAX_VALUE;

                   intans=-1;

                   intn=num.length;

                   longtime1=System.currentTimeMillis();

                   for(int i=0;i<n;i++){

                            for(int j=i+1;j<n;j++){

                                     for(int k=j+1;k<n;k++){

                                               if(Math.abs(target-(num[i]+num[j]+num[k]))<closest){

                                                        closest=Math.abs(target-(num[i]+num[j]+num[k]));

                                                        ans=num[i]+num[j]+num[k];

                                               }

                                     }

                            }

                   }

                   System.out.println(System.currentTimeMillis()-time1);

                   returnans;

         }

         O(N^2logN):将所有数对和排序。O(N^2log(N^2))=O(N^2logN)

                               枚举任意一个数,找出其在排序好的数对和中,绝对值差距最小的index,尝试index,以及index-1向左开始第一个不包含该数的数对和,以及index+1向右开始第一个不包含该数的数对和。

                                     还有预处理,让每个数字出现的次数不超过3次。

import java.util.ArrayList;

import java.util.Hashtable;

 

public class Solution136 {

   public int threeSumClosest(int[] num, int target) {   

             long time1=System.currentTimeMillis();

             Hashtable<Integer,Integer>hashnum=new Hashtable<Integer,Integer>();

             int[] num2=new int[num.length];

             int newN=0;

             for (int i=0;i<num.length;i++){

                       if(!hashnum.containsKey(num[i])){

                                hashnum.put(num[i],1);                       

                       }else{

                                if(hashnum.get(num[i])==1){

                                         hashnum.put(num[i],2);

                                }else{

                                         if(hashnum.get(num[i])==2){

                                                   hashnum.put(num[i],3);

                                         }else{

                                                   continue;

                                         }

                                }

                       }

                       num2[newN]=num[i];

                       newN++;

             }

             num=num2;

             int n=newN;

             int tempN=0;

             for (int i=0;i<n;i++){

                       for (int j=i+1;j<n;j++){

                                tempN++;

                       }

             }

             //ArrayList<Integer> twoSum=newArrayList<Integer>();

             //ArrayList<Integer> a=newArrayList<Integer>();

             //ArrayList<Integer> b=newArrayList<Integer>();

             int[] twoSum=new int[tempN];

             int[] a=new int[tempN];

             int[] b=new int[tempN];

             int high=0;

             for (int i=0;i<n;i++){

                       for (int j=i+1;j<n;j++){

                                //twoSum.add(num[i]+num[j]);

                                //a.add(i);

                                //b.add(j);

                                twoSum[high]=num[i]+num[j];

                                a[high]=i;

                                b[high]=j;

                                high++;

                       }

             }

             long time2=System.currentTimeMillis();

             //System.out.println(System.currentTimeMillis()-time1);

             qsort(twoSum,a,b,0,twoSum.length-1);

             //System.out.println(System.currentTimeMillis()-time2);

             long time3=System.currentTimeMillis();

             int closest=Integer.MAX_VALUE;

             int ans=-1;

             for (int i=0;i<n;i++){

                       intpos=binarySearch(twoSum,target,num[i],0,twoSum.length-1);

                       if(Math.abs(target-(num[i]+twoSum[pos]))<closest){

                                if(a[pos]!=i&&b[pos]!=i){

                                         closest=Math.abs(target-(num[i]+twoSum[pos]));

                                         ans=(num[i]+twoSum[pos]);

                                }

                       }

                       for (intj=pos+1;j<twoSum.length;j++){

                                if(a[j]!=i&&b[j]!=i){

                                         if(Math.abs(target-(num[i]+twoSum[j]))<closest){

                                                   closest=Math.abs(target-(num[i]+twoSum[j]));   

                                                   ans=num[i]+twoSum[j];

                                         }

                                         break;

                                }

                       }

                       for (intj=pos-1;j>=0;j--){

                                if(a[j]!=i&&b[j]!=i){

                                         if(Math.abs(target-(num[i]+twoSum[j]))<closest){

                                                   closest=Math.abs(target-(num[i]+twoSum[j]));  

                                                   ans=num[i]+twoSum[j];

                                         }

                                         break;

                                }

                       }

             }

             //System.out.println(System.currentTimeMillis()-time3);

             return ans;

    }

 

         privateint binarySearch(int[] twoSum, int target, int number,int x, int y) {

                   if(twoSum[x]+number==target){

                            returnx;

                   }

                   if(twoSum[y]+number==target){

                            returny;

                   }

                   intmid=twoSum[(x+y)/2];

                   if(mid+number==target){

                            return(x+y)/2;

                   }

                   if(y-x==1){

                            if(Math.abs(target-(twoSum[x]+number))<Math.abs(target-(twoSum[y]+number))){

                                     returnx;

                            }else{

                                     returny;

                            }

                   }

                   if(mid+number>target){

                            returnbinarySearch(twoSum,target,number,x,(x+y)/2);

                   }else{

                            returnbinarySearch(twoSum,target,number,(x+y)/2,y);

                   }

         }

 

         privatevoid qsort(int[] twoSum, int[] a,

                            int[]b, int x, int y) {

                   inti=x;

                   intj=y;

                   intt=twoSum[(i+j)/2];

                   do{

                            while(twoSum[i]<t){

                                     i++;

                            }

                            while(twoSum[j]>t){

                                     j--;

                            }

                            if(i<=j){

                                     inttemp=twoSum[i];

                                     twoSum[i]=twoSum[j];

                                     twoSum[j]=temp;

                                     temp=a[i];

                                     a[i]=a[j];

                                     a[j]=temp;

                                     temp=b[i];

                                     b[i]=b[j];

                                     b[j]=temp;

                                     i++;

                                     j--;

                            }

                   }while(i<=j);

                   if(j>x){

                            qsort(twoSum,a,b,x,j);

                   }

                   if(i<y){

                            qsort(twoSum,a,b,i,y);

                   }

         }

}

 

O(N^2):参考http://www.cnblogs.com/obama/p/3275574.html

         将数组排序之后,枚举每个数,寻找剩下数中与target最接近的两个数,这个过程可以通过与twoSum很类似的方法进行寻找。由于数组有序,left和right分别指向最左侧和最右侧,当a[left]+a[right]>target时,right—否则left++。

         正确性证明:left和right一定有一个先触及最优区间边界,当先触及左边界时,此时一定a[left]+a[right]>target,否则a[left]+a[right-1]<=a[left]+a[right],与target差的很远,那么与假设相悖,同理可证
0 0