Brush question - bis pointer (2)

Two Sum class

The first is the basic problem solution Two Sum

Hashmap with time complexity O (n), the spatial complexity of O (n), each first hashmap find there is no target - nums [i], without the nums [i] into the map

Double pointer method, time complexity of O (n + nlogn), the spatial complexity is O (1) must first be sorted, if desired the two returns the index number, then this method can not be used

例 lintcode  56. Two Sum https://www.lintcode.com/problem/two-sum/description

 

Therefore, when the array is already sorted, the method of two points better.

Involving data design class of problems, such as designing a Two Sum class, because this is a online algorithm, which function the user is not clear, so the analysis of the time complexity should be based on every little function.

例 lintcode 607 Two Sum III - Data structure design  https://www.lintcode.com/problem/two-sum-iii-data-structure-design/description

This question is if you are using arraylist, then add () operation can go to the O (1) time, added directly on the line, but the find () must first sort, the time complexity of O (nlogn), how to improve it, add it at the time of insertion sorting, is a time complexity of O (n), when looking directly at the double pointer lookup time O (n), there is no more space on the whole better than hashmap

    private ArrayList<Integer> array = new ArrayList<>();
    
    public void add(int number) {
        array.add(number);
        if(array.size() > 1)    
            insertSort(number);
    }
    
    public void insertSort(int number){
        int index = array.size() - 1;
        for(int i = array.size() - 2;i >= 0 ;i--){
            if(number < array.get(i)){
                int tmp = array.get(i);
                array.set(i, number);
                array.set(index, tmp);
                index = i;
            }
        }
    }

    /**
     * @param value: An integer
     * @return: Find if there exists any pair of numbers which sum is equal to the value.
     */
    public boolean find(int value) {
        if(array.size() == 0){
            return false;
        }
        
        int left = 0, right = array.size() - 1;
        while(left < right){
            int sum = array.get(left) + array.get(right);
            if(sum == value)return true;
            else if(sum < value){
                left++;
            }else{
                right --;
            }
        }
        
        return false;
    }
}

On lintcode run directly out of memory of.

With hashmap, add time is O (1), find the time is O (n), a point of attention is not hashmap hashset is to record the number of occurrences. offline the two sum is a digital one and target poor do not find another place hashset, the same number it will not be counted twice. online and find the add is separate, hashset not know whether the same digital input once or twice.

    HashMap<Integer, Integer> map = new HashMap<>();
    
    public void add(int number) {
        if(!map.containsKey(number)){
            map.put(number, 1);
        }else{
            map.put(number,map.get(number)+1);
        }
    }
    
    public boolean find(int value) {
        for(int key:map.keySet()){
            if(value == key * 2 && map.get(key) > 1){
                return true;
            }else if(value == key * 2 && map.get(key) == 1){
                continue;
            }
            
            if(map.containsKey(value - key)){
                return true;
            }
        }
        
        return false;
    }

 

follow up: If you find a large number of operations, add a few operations, how to optimize?

To two hashset, which store two numbers. That is, every time the add operation complexity is On, each adding a number, and it will be all the storage, find operation to find and there is no direct line, O1 time complexity.

On lintcode beyond the time limit, because this is a special follow up

    HashSet<Integer> nums = new HashSet<>();
    HashSet<Integer> sums = new HashSet<>();
    
    public void add(int number) {
        
        for(int num : nums){
            sums.add(number + num);
        }
        nums.add(number);
    }
    
    public boolean find(int value) {
        return sums.contains(value);
    }

 

two sum -- unique pair

lintcode 587. Two Sum - Unique pairs  https://www.lintcode.com/problem/two-sum-unique-pairs/description

Solution two sum double pointer class of problems, the pointer continues to move left and right as a pair, when found, until all duplicate entries skipped.

    public int twoSum6(int[] nums, int target) {
        if(nums == null || nums.length == 0)return 0;
        
        int left = 0, right = nums.length - 1;
        
        int res = 0;
        Arrays.sort(nums);
        
        while(left < right){
            int sum = nums[left] + nums[right];
            if(sum == target){
                res++;
                while(left < right && nums[left] == nums[++left]);
                //System.out.println("left" + left);
                while(left < right && nums[right] == nums[--right]);
                //System.out.println("right" + right);
            }else if(sum < target){
                left++;
            }else{
                right--;
            }
        }
        
        return res;
    }

 

3sum find three sum for the number zero. Such as a + b + c = 0, then there -a = b + c, the minimum value into the side of the equation, n cycles performed, to the right to find the minimum value is 2sum double pointer. Similarly, also going to weight of the first layer and the inner loop cycle to be heavy.

lintcode 57 3sum   https://www.lintcode.com/problem/3sum/description

    public List<List<Integer>> threeSum(int[] numbers) {
        List<List<Integer>> res = new LinkedList<>();
        if(numbers == null || numbers.length <= 2) return res;
        
        Arrays.sort(numbers);
        
        for(int i = 0;i <= numbers.length - 3;i++){
            int left = i + 1, right = numbers.length - 1;
            int target = -numbers[i];
            while(left < right){
                //System.out.println(target);
                int sum = numbers[left] + numbers[right];
                if(sum == target){
                    List<Integer> ans = Arrays.asList(numbers[i], numbers[left], numbers[right]);
                    res.add(ans);
                    while(left < right && numbers[left] == numbers[++left]);
                    while(left < right && numbers[right] == numbers[--right]);
                }else if(sum < target){
                    left++;
                }else{
                    right--;
                }
            }
            while(i <= numbers.length - 3 && numbers[i] == numbers[++i]);
            //System.out.println(i);
            i--;
        }
        
        return res;
    }

 

 

triangle count has not been able to find the array constituting the three sides of the triangle, the number may return configuration. a + b> c is greater than the sum of the two small sides of the third side, it is possible to find the cycle starts from the maximum array. Example 02 234, if 2, 3, 4 is greater than the sum, all of three numbers between 2 and 3 and greater than 4. That is, from the beginning of the largest side, each side should only take a maximum cycle On, On during each cycle, a two-time move the pointer always is On ^ 2. If the output of all three sides, such as 111,111,111, then the time complexity is On ^ 3. Because every possibility would walk again.

lintcode 382. Triangle Count       https://www.lintcode.com/problem/triangle-count/description

    public int triangleCount(int[] S) {
        if(S == null || S.length < 3) return 0;
        
        Arrays.sort(S);
        int res = 0;
        
        for(int i = S.length - 1;i > 1;i--){
            int left = 0, right = i - 1;
            while(left < right){
                int sum = S[left] + S[right];
                if(sum > S[i]){
                    res += right - left;
                    right--;
                }else{
                    left++;
                }
            }
        }
        
        return res;
    }

 

To find two numbers and each number is greater than or less than a number of the same methods and ideas

lintcode 609 Two Sum - Less than or equal to target https://www.lintcode.com/problem/two-sum-less-than-or-equal-to-target/description

lintcode 443 Two Sum - Greater than target   https://www.lintcode.com/problem/two-sum-greater-than-target/description

 

Two numbers and closest to the target number

lintcode 533. Two Sum - Closest to target  https://www.lintcode.com/problem/two-sum-closest-to-target/description

And the general idea and the two numbers are the same, double-pointer, and a time to find a value on the number of target and the target to make the difference, a variable used to record each time the minimum. The last return is minimal difference

public int twoSumClosest(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        
        Arrays.sort(nums);
        int res = Integer.MAX_VALUE;
        int left = 0, right = nums.length - 1;
        
        while(left < right){
            int sum = nums[left] + nums[right];
            if(sum < target){
                res = Math.min(res, target - sum);
                left++;
            }else if(sum > target){
                res = Math.min(res, sum - target);
                right--;
            }else{
                return 0;
            }
        }
        
        return res;
        
    }

 

Three and the number of the nearest target

lintcode 59. 3Sum Closest  https://www.lintcode.com/problem/3sum-closest/description

And ideas before three numbers coincide, a number from which to start the cycle, the number of additional double two pointers, and return values ​​are the closest target. Note that point and is not the same as the previous question, where the record is variable and value, so the very beginning must be equal to the first sum.

    public int threeSumClosest(int[] numbers, int target) {
        if(numbers == null || numbers.length == 0)return 0;
        
        Arrays.sort(numbers);
        int res = Integer.MAX_VALUE;
        
        for(int i = 0;i < numbers.length - 2;i++){
        
            int left = i + 1, right = numbers.length - 1;
            while(left < right){
                int sum = numbers[i] + numbers[left] + numbers[right];
            
                if(sum == target){
                    return sum;
                }
            
                if(res == Integer.MAX_VALUE || Math.abs(sum - target) <     Math.abs(res - target)){
                    res = sum;
                }
            
                if(sum < target){
                    left ++;
                }else{
                    right --;
                }
            }
        }
        
        return res;
    }
}

 

The difference between two numbers

lintcode 610. Two Sum - Difference equals to target  https://www.lintcode.com/problem/two-sum-difference-equals-to-target/my-submissions?_from=ladder&&fromId=1

The first is the hashmap solutions, ideas and the same two numbers, first find the map there is no such target - nums [i] values, any direct return, if not the nums [i], i put the map. Different point is that the difference between two numbers, there are two cases, to find the target + nums [i] and nums [i] - target.

Double pointer arithmetic. Because eventually need to return to the index, and sometimes disorderly array of input, get the original order to ensure the index after ordering, you need to pair the new class, override both the comparator interfaces (two pits, one of their own java Pair class Why not build the array, two Compare rewrite the interface), and two-pointer after thinking the same.

class Pair{
    int value;
    int index;
    public Pair(int v, int i){
        this.value = v;
        this.index = i;
    }
}


public class Solution {
    /**
     * @param nums: an array of Integer
     * @param target: an integer
     * @return: [index1 + 1, index2 + 1] (index1 < index2)
     */
    /*
    hashmap. In the two sum question, we just check int diff = target - nums[i], if we get the the ans, return it, otherwise, we put (nums[i], i) in the map;
    In this question, we need to consider two conditions because it is difference, otherthings are same.
    */ 
     
    // public int[] twoSum7(int[] nums, int target) {
    //     int[] res = new int[2];
    //     if(nums == null || nums.length == 0)return res;
        
    //     HashMap<Integer, Integer> map = new HashMap<>();
        
    //     for(int i = 0;i < nums.length;i++){
    //         int sum = nums[i] + target;
    //         if(map.containsKey(sum)){
    //             int index1 = map.get(sum);
    //             int index2 = i;
    //             if(index2 < index1){
    //                 int temp = index1;
    //                 index1 = index2;
    //                 index2 = index1;
    //             }
    //             res[0] = index1 + 1;
    //             res[1] = index2 + 1;
    //             return res;
    //         }
            
    //         int diff = nums[i] - target;
    //         if(map.containsKey(diff)){
    //             int index1 = map.get(diff);
    //             int index2 = i;
    //             if(index2 < index1){
    //                 int temp = index1;
    //                 index1 = index2;
    //                 index2 = index1;
    //             }
    //             res[0] = index1 + 1;
    //             res[1] = index2 + 1;
    //             return res;
    //         }
            
    //         map.put(nums[i], i);
    //     }
        
    //     return res;
    // }
    
    
    public int[] twoSum7(int[] nums, int target) {
        int[] res = new int[2];
        if(nums == null || nums.length == 0)return res;
        
        Pair[] pairs = new Pair[nums.length]; 
        
        if(target < 0) target = -target;
        
        for(int i = 0;i < nums.length;i++){
            pairs[i] = new Pair(nums[i], i);
        }
        
        Arrays.sort(pairs, new Comparator<Pair>(){
            public int compare(Pair p1, Pair p2){
                return p1.value - p2.value;
            }
        }
        );
        
        int j = 0;
        for(int i = 0;i < nums.length - 1;i++){
            if(i == j){
                j++;
            }
            
            while(j < nums.length && pairs[j].value - pairs[i].value < target){
                j++;
            }
            
            if(pairs[j].value - pairs[i].value == target){
                int index1 = pairs[i].index + 1;
                int index2 = pairs[j].index + 1;
                if(index2 < index1){
                    int tmp = index1;
                    index1 = index2;
                    index2 = tmp;
                }
                res[0] = index1;
                res[1] = index2;
                return res;
            }
        }
        
        return res;
    }
}

 

Guess you like

Origin www.cnblogs.com/2333wzl/p/12283149.html