思路
先想解题的大致思路再根据解题思路来实现, 在实现的过程中考虑corner case :
- 首先当然是在原数组的基础上, 暴力搜索, 比如先固定第一个点, 然后从其余的元素中寻找第二个点, 不过这样做的话, 时间复杂度是平方级别, 所以我很快放弃了.
- 然后我就想能不能让数组先排序, 然后再在排序数组的基础上, 设两个游标, 一左一右, 通过移动游标来实现寻找目标点, 这样的话, 排序只需要O(nlogn)然后在排序数组的基础上寻找目标点只需要O(n), 这也是我最终实现的方式.
实现
一些具体的情况以及corner case的考虑 :
- 我感觉原数组应该是不可变的, 所以我使用一个临时数组对原数组进行了拷贝(其实这里的拷贝挺耗时的, 不过还是O(n)), 然后对临时数组进行排序, 在临时数组中找出这之后再到原数组中找出这两个点.
- 需不需要考虑输入数组长度不够(小于2)或者不存在这样的两个点的情况呢? 由于原题中说了存在确切一组解, 所以可以不用考虑.
提交
结果我并不是一次AC :
- 第一次出错的原因是, 我把--right写成了++right, 导致数组出现InvalidIndex异常. 这个是具体实现上马虎了.
- 第二次出错的原因是, 我在从原数组中找这两个数的真正索引的时候,用了这样的代码 :
for(int i = 0; i < nums.length; ++i){
if(temp[left] == nums[i]) re[0] = i;
if(temp[right] == nums[i]){
re[1] = i;
break;
}
}
+ 这里其实有两个错误, 第一个是如果所找到的两个元素值相同, 那么两个if在同一次循环中执行完毕, 导致结果数组中找到的两个索引是相同的, 这显然是不对的, 出现这个错误的原因是我没有考虑到所查到的元素值相同这个corner case.
+ 第二个是如果temp[right]出现的原数组的前面, 那么索引还没有寻找完全, 就退出了循环. 这里主要是我没有理清原数组是乱序数组这一性质.
代码
import java.util.Arrays;
public class Solution {
public int[] twoSum(int[] nums, int target) {
int[] re = new int[2];
int[] temp = nums.clone();
Arrays.sort(temp);
int left = 0;
int right = temp.length - 1;
while(true){
int sum = temp[left] + temp[right];
if(sum == target) break;
else if(sum < target) ++left;
else --right;
}
for(int i = 0, j = 0; i < nums.length; ++i){
if(temp[left] == nums[i] || temp[right] == nums[i]){
re[j++] = i;
if(j == 3){
break;
}
}
}
return re;
}
}
最佳实现
最佳实现是用哈希表, 说起来就很简单, 但是我就是没想到.