思路

先想解题的大致思路再根据解题思路来实现, 在实现的过程中考虑corner case :

  1. 首先当然是在原数组的基础上, 暴力搜索, 比如先固定第一个点, 然后从其余的元素中寻找第二个点, 不过这样做的话, 时间复杂度是平方级别, 所以我很快放弃了.
  2. 然后我就想能不能让数组先排序, 然后再在排序数组的基础上, 设两个游标, 一左一右, 通过移动游标来实现寻找目标点, 这样的话, 排序只需要O(nlogn)然后在排序数组的基础上寻找目标点只需要O(n), 这也是我最终实现的方式.

实现

一些具体的情况以及corner case的考虑 :

  1. 我感觉原数组应该是不可变的, 所以我使用一个临时数组对原数组进行了拷贝(其实这里的拷贝挺耗时的, 不过还是O(n)), 然后对临时数组进行排序, 在临时数组中找出这之后再到原数组中找出这两个点.
  2. 需不需要考虑输入数组长度不够(小于2)或者不存在这样的两个点的情况呢? 由于原题中说了存在确切一组解, 所以可以不用考虑.

提交

结果我并不是一次AC :

  1. 第一次出错的原因是, 我把--right写成了++right, 导致数组出现InvalidIndex异常. 这个是具体实现上马虎了.
  2. 第二次出错的原因是, 我在从原数组中找这两个数的真正索引的时候,用了这样的代码 :
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;
    }
}

最佳实现

最佳实现是用哈希表, 说起来就很简单, 但是我就是没想到.

posted on 2016-12-17 06:16  内脏坏了  阅读(148)  评论(0编辑  收藏  举报