kSum-Leetcode Summary I

Leetcode Summary I


  • Leetcode Summary I
      • kSum
        • Two Sum
        • Two Sum II - Input array is sorted
        • 3Sum
        • 3Sum Closest
        • 4Sum


kSum

大神的总结:http://blog.csdn.net/linhuanmars/article/details/38555885
划重点:
1. 如果求出所有的结果,这个时候会涉及到重复 pair 的处理。
2. 如果重复的元素太多,用哈希表就不是很方便。所以后面的 3Sum 和4Sum 都没有选择用哈希表。

基本来说,主要是用双指针法。
- 首先判断边界条件。注意nums == null一定要在nums.length < 2的前面。
- 接着对原数组排序。
- 然后在循环体中,使用夹逼的方法找到合适的元素,如果题目要求有且只有一个解,那么直接输出;如果有多个解,那么要去重。去重的主要思想是:如果遇到了相邻元素相等的情况,就让指针的移动大于 1。

注意:下面的笔记中第一个 big O 是时间复杂度,第二个是空间复杂度。


Two Sum

https://leetcode.com/problems/two-sum/

解题思路:
solution 1 : O(n) + O(n)
- 在循环体中,查找是否有满足要求的数,如果有直接输出(因为题目说了有且只有一个答案)。

solution 2 : O(nlogn) + 取决于排序算法
- 需要注意的是:这里先对数组排了序,这将打乱原来的 index 顺序。因此要做一下处理。
- 这里处理的方式为:首先将未排序的数组保存起来,接着在循环中如果发现了符合条件的数,将它们保存在变量中,然后退出循环。最后通过两次正序和逆序的遍历,找到数值原来的 index。

solution 1 : HashMap

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map map = new HashMap<>();
        for(int i=nums.length-1; i>=0; i--) {
            if(map.containsKey(target - nums[i]))
                return new int[] {i, map.get(target - nums[i])};
            map.put(nums[i], i);
        }
        return null;
    }
}

solution 2 : two pointers

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] numsCopy = nums.clone();
        if(nums == null || nums.length < 2)
            return null;
        Arrays.sort(nums);
        int tmp1 = 0, tmp2 = 0;
        int low = 0, high = nums.length - 1;
        while(low < high) {
            if(nums[low] + nums[high] == target) {
                tmp1 = nums[low];
                tmp2 = nums[high];
                break;
            } else if(nums[low] + nums[high] < target) {
                low++;
            } else {
                high--;
            }
        }
        int res1 = 0, res2 = 0;
        for(int i=0; iif(numsCopy[i] == tmp1 ) {
                res1 = i;
                break;
            }
        }
        for(int j=numsCopy.length-1; j>=0; j--) {
            if(numsCopy[j] == tmp2) {
                res2 = j;
                break;
            }
        }
        return new int[] {res1, res2};
    }
}

Two Sum II - Input array is sorted

https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/

解题思路:
solution 1 : O(nlogn)
- 上面那道题的简单版,不用考虑 index 乱序的问题。

solution 1 : two pointers

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        if(nums == null || nums.length < 2)
            return null;
        int low = 0, high = nums.length - 1;
        while(low < high) {
            if(nums[low] + nums[high] == target) {
                return new int[] {low+1, high+1};
            } else if(nums[low] + nums[high] < target) {
                low++;
            } else {
                high--;
            }
        }
        return null;
    }
}

3Sum

https://leetcode.com/problems/3sum/

解题思路:
solution 1 : O(n^2) + O(n)
- 使用 Two Sum 的双指针思想,只是要多一个元素的 for 循环。并且,要滤过重复元素,避免重复操作。
- 去重的具体的做法是:在 for 循环下的 if(i == 0 || nums[i] > nums[i-1]),以及两个 while:while(j < k && nums[j] == nums[j-1])。如果两个 i( j / k ) 所指的元素是相同的,那么后者所要遍历的结果在前者已经经历过了,因此可以去掉这部分操作。

public class Solution {
    public List> threeSum(int[] nums) {
        List> result = new ArrayList<>();
        if(nums == null || nums.length < 3)
            return result;

        Arrays.sort(nums);
        for(int i=0; i2; i++) {
            if(i == 0 || nums[i] > nums[i-1]) {
                int j = i + 1;
                int k = nums.length - 1;

                while(j < k) {
                    if(nums[i] + nums[j] + nums[k] == 0) {
                        List list = new ArrayList<>();
                        list.add(nums[i]); list.add(nums[j]); list.add(nums[k]);
                        result.add(list);
                        j++; k--;

                        while(j < k && nums[j] == nums[j-1])
                            j++;
                        while(j < k && nums[k] == nums[k+1])
                            k--;
                    } else if(nums[i] + nums[j] + nums[k] > 0) {
                        k--;
                    } else {
                        j++;
                    }
                }
            }
        }
        return result;
    }
}

3Sum Closest

https://leetcode.com/problems/3sum-closest/

解题思路:
solution 1 : O(n^2) + O(n)
- 和 3Sum 以及 Two Sum 都很类似。不过这里需要维护一个变量 diff,根据 diff 来找到与 target 最相近的 sum。
- 但是,为什么这里不用去重?

public class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int min = Integer.MAX_VALUE, result = 0;
        if(nums == null || nums.length < 3)
            return 0;

        Arrays.sort(nums);
        for(int i=0; i2; i++) {
            int j = i + 1;
            int k = nums.length - 1;

            while(j < k) {
                int sum = nums[i] + nums[j] + nums[k];
                int diff = Math.abs(target - sum);
                if(diff == 0) {
                    return sum;
                } else if(diff < min){
                    min = diff;
                    result = sum;
                }

                if(sum < target) {
                    j++;
                } else {
                    k--;
                }
            }
        }
        return result;
    }
}

4Sum

https://leetcode.com/problems/4sum/

解题思路:
solution 1 :
- 和之前的思路一样,只是多了一层循环。

public class Solution {
    public List> fourSum(int[] nums, int target) {
        List> result = new ArrayList<>();
        if(nums == null || nums.length < 4)
            return result;

        Arrays.sort(nums);
        for(int i=0; i3; i++) {
            if(i == 0 || nums[i] > nums[i-1]) {
                for(int j=i+1; j2; j++) {
                    if(j == i+1 || nums[j] > nums[j-1]) {
                        int k = j+1;
                        int l = nums.length - 1;

                        while(k < l) {
                            if(nums[i] + nums[j] + nums[k] + nums[l] == target) {
                                List list = new ArrayList<>();
                                list.add(nums[i]); list.add(nums[j]);
                                list.add(nums[k]); list.add(nums[l]);
                                result.add(list);
                                k++; l--;

                                while(k < l && nums[k] == nums[k-1]) 
                                    k++;
                                while(k < l && nums[l] == nums[l+1])
                                    l--;
                            } else if(nums[i] + nums[j] + nums[k] + nums[l] < target) {
                                k++;
                            } else {
                                l--;
                            }
                        }
                    }
                }
            }
        }
        return result;
    }
}

你可能感兴趣的:(Leetcode)