[LeetCode] NO.1 Two Sum

 题目:

         Given an array of integers, return indices of the two numbers such that they add up to a specific target.

         You may assume that each input would have exactly one solution.

          Example:

             Given nums = [2, 7, 11, 15], target = 9,
             Because nums[0] + nums[1] = 2 + 7 = 9,
             return [0, 1].

解析过程:
拿到题目,直接能想到的是最简单也是最笨的方法就是对数组进行遍历,代码如下:
   public static int[] twoSum(int[] nums, int target) {
        int indices[] = new int[2];
        for(int i = 0; i < nums.length - 1; i++){
            for(int j = i+1; j < nums.length; j++){
               if((i < j) && (nums[i] + nums[j] == target)){
                   indices[0] = i;
                   indices[1] = j;
               }
            }
        }
        return indices;
     }

    显然这样的策略是耗时的,时间复杂度为O(n2)。

    那么,有没有比较高效的方法呢?根据动态规划的思想,我们可以将问题进行划分。设数组长度为len,我们需要求满足条件的i,j使得 nums[i]+nums[j] = target,我们不妨来看数组最后一项nums[len-1],根据该项是否包含到最终返回结果,可以分两种情况。当len-1 = j时,我们只需要遍历数组的0~len-2项,取nums[i] = target - nums[len-1]的i即可。当len-1 != j时,我们知道我们所求的i和j,也就转化成原数组的子数组(从0到len-2项)上的问题。这样便可以把问题不断进行划分,临界条件是当数组长度等于2的时候。代码如下:

     public static int[] twoSum(int[] nums, int target) {
         return twoSum(nums,nums.length,target);
      }
     
     public static int[] twoSum(int[] nums, int n, int target) { 
         int indices[] = new int[2];
         if(n >= 2){
             int j = n-1;
             int part = target - nums[j];
             for(int i = 0; i < j; i++) {
            	 if(nums[i] == part){
            		 indices[0] = i;
            		 indices[1] = j;
            		 return indices;
            	 }
             }
             return twoSum(nums,n-1,target); 
         }
         return null;
     }

  运行代码,效率提高不少,但是依然不是很高效。时间复杂度还是O(n2),代码里用到了递归的实现方式,我们都知道递归是耗时的,凡是用递归可以实现的,都可以用循环和栈来实现,这个不做探讨。

      我们可以设想,如果数组是有序的,我们解决这个问题是不是比较容易了?有序数组的话,我们可以从数组两端取值,比较两个数的和与目标数target的大小,来决定移动左端还是右端,这样循环下来,一定能找到我们的答案,这样遍历一下的时间复杂度只有O(n)。那么,我们可以考虑给数组排序,排序的时间复杂度在O(nlgn),但是排序之后数组顺序乱了?我们还要找原来的index,怎么办? 这个好办,我们可以再开辟一个数组,用来存最原始的数组,然后找到目标值之后,然后再到这个原数组copy数组里面去定位对应的index即可。代码如下:

    public static int[] twoSum(int[] nums, int target) {
    	int[] copynums = Arrays.copyOf(nums, nums.length);
    	boolean aflag = false,bflag = false;
    	Arrays.sort(nums);
        int indices[] = new int[2];
        int start = 0;
        int end = nums.length - 1;
        int a = 0 ,b = 0;
        while(start < end){
        	int sum = nums[start] + nums[end];
        	if(sum < target){
        		start++;
        	}else if(sum > target){
        		end--;
        	}else if(sum == target){
        		a = nums[start];
        		b = nums[end];
        		break;
        	}
        } 
        for(int i = 0; i < copynums.length; i++){
        	if(!aflag && (copynums[i] == a)){
        		indices[0] = i;
        		aflag = true;
        		continue;
        	}
        	if(!bflag && (copynums[i] == b)){
        		indices[1] = i;
        		bflag = true;
        	}
        	if(aflag && bflag && (indices[0] != indices[1])){
        		break;
        	}
        }
        Arrays.sort(indices);
        return indices;
    }

  排序的时候我们调用了Arrays.sort方法,具体实现可以查看源代码。

      运行上面的代码,我们发现,效率有了质的提高,可以达到我们的要求了。

posted @ 2016-08-02 19:23  三刀  阅读(539)  评论(0编辑  收藏  举报