[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方法,具体实现可以查看源代码。
运行上面的代码,我们发现,效率有了质的提高,可以达到我们的要求了。

浙公网安备 33010602011771号