美文网首页
LintCode 587. 两数之和 - 不同组成

LintCode 587. 两数之和 - 不同组成

作者: Jay_8d33 | 来源:发表于2018-02-03 00:46 被阅读0次

原题

第一步,万年不变的查错。如果给的array是null或不够两个数,直接return 0

    public int twoSum6(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        ...
   }

后面的思路,我的方式和九章上的答案不大一样。九章用的Two Pointer,我用了两个HashSet。大体思路就是,这个题和最简单的TwoSum唯一的区别就是,需要找到所有长度为2的组合,且不能重复。既然要找到所有的且去重,那就用HashSet搞定了。

我们需要创建一个class Pair,用来放这两个数字。在constructor里面,我对比了一下数字的大小,然后小的是a,大的是b,这样就可以保证HashCode不会因为两个数字反过来就不一样了。


  private class Pair {

        int a;

        int b;

        public Pair(int a, int b) {

            if (a <= b) {

                this.a = a;

                this.b = b;

            } else {

                this.a = b;

                this.b = a;

            }

        }



        @Override

        public boolean equals(Object o) {

            if (o instanceof Pair) {

                Pair other = (Pair) o;

                return this.a == other.a && this.b == other.b;

            }



            return false;

        }



        @Override

        public int hashCode() {

            int result = a;

            result = 31 * result + b;

            return result;

        }

    }

然后建一个HashSet用来存放所有找到的Pair和去重

        Set<Pair> pairs = new HashSet<>();

然后这道题继续以TwoSum的解法,建一个HashSet来存放见过的数字,然后遍历整个array,如果之前见过target - currentNumber的数字,就建一个Pair,放到pairs里面。在放的过程中,HashSet会自动的根据hashCodeequals去重,即如果hashCode是一样的,就会呼叫equals,如果返回true,那就不做任何更改(并且return false,不过我们不需要关心它的return)。到最后,只需要return pairs.size()就可以知道有多少个了。如果这道题要变成需要知道具体是哪几个组合,这个做法也直接解决了。

        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (set.contains(target - nums[i])) {
                pairs.add(new Pair(target - nums[i], nums[i]));
            }
            set.add(nums[i]);
        }
        
        return pairs.size();

这里要先建pair,再把当前的数字加到set里面,因为题目要求不能重复用两个数字。如果可以用,那么就把set.add(nums[i])放到for loop的一开始就好了。

完整的code

public class Solution {
    /*
     * @param nums: an array of integer
     * @param target: An integer
     * @return: An integer
     */
    private class Pair {
        int a;
        int b;
        public Pair(int a, int b) {
            if (a <= b) {
                this.a = a;
                this.b = b;
            } else {
                this.a = b;
                this.b = a;
            }
        }
        
        @Override
        public boolean equals(Object o) {
            if (o instanceof Pair) {
                Pair other = (Pair) o;
                return this.a == other.a && this.b == other.b;
            } 
            
            return false;
        }
        
        @Override
        public int hashCode() {
            int result = a;
            result = 31 * result + b;
            return result;
        }
    }
    public int twoSum6(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        
        Set<Pair> pairs = new HashSet<>();
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (set.contains(target - nums[i])) {
                pairs.add(new Pair(target - nums[i], nums[i]));
            }
            set.add(nums[i]);
        }
        
        return pairs.size();
    }
}

九章

九章上答案的思路是,先对array进行排序。

  Arrays.sort(nums);

然后设count为0,两根指针,一左一右,向中间行进。

  int count = 0;
  int left = 0, right = nums.length - 1;
  while (left < right) {
     ...
  }

如果两个数字是一样的,那么count++,然后左边指针往右移,右边指针往左移,并且如果当前数字和上一个数字相同,那么跳过接着移动,当然全程要保持左边的指针不能超过右边的指针。

    int sum = nums[left] + nums[right];
    if (sum == target) {
        count++;
        left++;
        right--;
        while (left < right && nums[left] == nums[left - 1]) {
            left++;
        }
        while (left < right && nums[right] == nums[right + 1]) {
            right--;
        }
    }

如果当前的和大于target,那么就右边往左移,如果当前的和小于target,那么就左边往右移。

    else if (sum > target) {
        right--;
    } else {
        left++;
    }

最后返回count就可以了。
完整的code

public class Solution {
    /**
     * @param nums an array of integer
     * @param target an integer
     * @return an integer
     */
    public int twoSum6(int[] nums, int target) {
        // Write your code here
        if (nums == null || nums.length < 2)
            return 0;

        Arrays.sort(nums);
        int count = 0;
        int left = 0, right = nums.length - 1;
        while (left < right) {
            int sum = nums[left] + nums[right];
            if (sum == target) {
                count ++;
                left ++;
                right --;
                while (left < right && nums[right] == nums[right + 1]) {
                    right --;
                }
                while (left < right && nums[left] == nums[left - 1]) {
                    left ++;
                 }    
            } else if (sum > target) {
                right --;
            } else {
                left ++;
            }
        }
        return count;
    }
}

分析

时间复杂度(time complexity)

我的解法应该是O(n),n为array的长度。因为只遍历的array一次。HashSet的插入和读取皆为O(1)。相较于九章的解法,一开始先sort array,时间复杂度为O(nlogn),这个解法的时间复杂度要低一点。

空间复杂度 (space complexity)

我的解法是O(n),建立了两个HashSet,每个为O(n)。相较于九章的算法,O(1),这个解法的空间复杂度要高一点。

整体来说,九章的解法更短,不过这是因为我的解法需要写一个class。真正的逻辑而言,我的逻辑更为简练。九章的解法是in place,没有用到任何额外的memory,而我的用到了O(n)的额外空间。当与面试官说清楚,两种解法各有利弊,应都熟练掌握。

相关文章

  • LintCode 587. 两数之和 - 不同组成

    原题 解 第一步,万年不变的查错。如果给的array是null或不够两个数,直接return 0 后面的思路,我的...

  • lintcode 两数之和

    给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。你需要实现的函数twoSum需要返回这两个数...

  • LintCode - 两数之和(普通)

    版权声明:本文为博主原创文章,未经博主允许不得转载。 难度:容易 要求: 给一个整数数组,找到两个数使得他们的和等...

  • LintCode三数之和系列问题

    三数之和 LintCode57 三数之和解题思路:先对数组排序,然后开始遍历,对于数组中的每一个元素,用两指针往中...

  • lintcode 三数之和

    给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。注意...

  • lintcode 四数之和

    给一个包含n个数的整数数组S,在S中找到所有使得和为给定整数target的四元组(a, b, c, d)。注意事项...

  • 两数之和(golang)

    原题:两数之和 关联:两数之和 II - 输入有序数组(golang)两数之和 IV - 输入 BST(golang)

  • 两数之和 II - 输入有序数组(golang)

    原题:两数之和 II - 输入有序数组 关联:两数之和(golang)两数之和 IV - 输入 BST(golan...

  • 浅入浅出实现一个异步求和函数

    简化:两数之和 我们先来简单的实现一个异步两数之和函数 加深:多数之和 上面我们实现了两数之和,然后扩展到多数之和...

  • 两数之和,三数之和

    转载:https://www.cnblogs.com/DarrenChan/p/8871495.html 1. 两...

网友评论

      本文标题:LintCode 587. 两数之和 - 不同组成

      本文链接:https://www.haomeiwen.com/subject/aokfnxtx.html