Leetcode-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, and you may not use the same element twice.

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

问题分析:

  • 此题可以看做是 另一篇博客Two Sum II - Input array is sorted的升级版问题。原问题数组是已经排好序的,所以可以按照排序的相关性质进行解题。而该题中的数组是一个未排序数组。故有两大思路:
    • 方法一:用Two Sum II - Input array is sorted中的hashmap的方法来做。
    • 方法二:因为最终返回的是索引,所以先用一个数组indices[i]用来存储nums[i]在原数组的索引,然后对数组进行排序,排序过程中两元素会发生交换,相应索引数组中对应的值也要发生交换;如原nums[3] = {2,3,1},indices[3] = {0,1,2},排序后 nums[3] = {1,2,3},indices[3] = {2,0,1},然后对排序后的数组用Two Sum II - Input array is sorted 提到的双指针做法,注意,若最终找到了等于target的情况,返回的是索引数组indices[]相应的值。

经验教训:

  • 只分析时间复杂度,方法一是O(N),方法二仅排序便需要O(nlogN),但最终在leetcode运行时,确是方法二效率高,击败了98.68%的答案,这说明什么?
  • 说明由于hash函数计算比较耗时,增大了常数项,导致hashmap方法不如方法二

代码实现:

  • 方法二:用改进版的堆排序进行排序
public int[] twoSum(int[] nums, int target) {
        if (nums == null || nums.length == 0 || nums.length == 1) {
            return new int[] {0,0};
        }
        //indices[i]用来存储nums[i]的原索引
        int[] indices = new int[nums.length];
        for (int i = 0; i < indices.length; i++) {
            indices[i] = i;
        }
        //排序,同时也调整索引数组
        sort(nums,indices);
        int l = 0;
        int r = nums.length - 1;
        int sum = 0;
        while (l < r) {
            sum = nums[l] + nums[r];
            if (sum == target) {
                return new int[] {indices[l], indices[r]};
            }else if (sum < target) {
                l++;
            }else {
                r--;
            }
        }
        return new int[] {-1, -1};
    }


    public void sort(int[] nums, int[] indices ) {

        //插入的方法建大根堆(从小到大排序):O(nlogn)效率不高
        /*for (int i = 0 ; i < nums.length; i++) {
            heapInsert(nums, indices, i);
        }*/

        //借助于heapify建大根堆(从小到大排序):O(N)
        int end = nums.length - 1;
        for (int i = ((end - 1) >> 1); i >= 0; i--) {
            heapify(nums, indices, i, end);
        }
        //建堆完毕,每次交换首尾,然后调整堆
        swap(nums, indices, 0, end);
        for (int i = end - 1; i > 0 ; i--) {
            heapify(nums, indices, 0, i);
            swap(nums, indices, 0, i);
        }
    }

    //heapInsert:
    public void heapInsert(int[] nums , int[] indices, int i) {
        while (i > 0) {
            int p = (i - 1) / 2;
            if (nums[i] >= nums[p]) {
                return;
            }
            swap (nums, indices, i ,p);
            i = p;
        }
    }

    //heapify:表示i+1~end都已经满足堆的特性,然后来了个i,将i~end调整成堆
    public void heapify(int[] nums, int[] indices, int i, int end) {
        for (int j = 2 * i + 1; j <= end; j = 2 * i + 1) {
            if (j < end && nums[j] < nums[j + 1]) {
                j++;
            }
            if (nums[i] >= nums[j]) {
                return;
            }
            swap (nums, indices, i, j);
            i = j;
        }
    }

    //交换:注意索引数组同样交换
    public void swap (int[] nums, int[] indices, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
        temp  = indices[i];
        indices[i] = indices[j];
        indices[j] = temp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值