twoSum Algorithm : How to improve this?

前端 未结 22 2118
礼貌的吻别
礼貌的吻别 2021-02-06 01:38

I felt like doing an algorithm and found this problem on leetcode

Given an array of integers, find two numbers such that they add up to a specific target num

相关标签:
22条回答
  • 2021-02-06 01:48

    The naïve solution to the two-sum problem is O(n^2), s.t. n is the length of the array of numbers provided.

    However, we can do better by using a hash-map of the values seen so far (key=number, value=index) and checking if the complement is already there (O(1)) as we iterate over the numbers. This approach is optimal for an unsorted array:

    • Runtime complexity: O(n)
    • Space complexity: O(n) -- though if there is a solution, in practice this would be O(n/2)

    Given the OP's question:

    • does not specify whether the input array is sorted or not (it is, therefore, safe to assume the input array can be anything), and
    • specifically asks for indexes of the provided array, as opposed to the actual numbers, any kind of solution sorting the array would need to copy it beforehand, keep a mapping of indexes between the sorted array and the unsorted one, or iterate over the original array, hence costing memory (O(n)) or time (O(n)), depending on the approach chosen. Therefore, the 1st part of the (currently) accepted solution is, strictly speaking, incorrect.

    Optimal solution:

    • In Python:
    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
            seen = {}
            for j, num in enumerate(nums):
                i = seen.get(target-num, -1)
                if i != -1:
                    return [i+1, j+1]
                seen[num] = j
            return [-1, -1]
    
    • In Java:
    import java.util.Map;
    import java.util.HashMap;
    
    public class Solution {
        public int[] twoSum(int[] nums, int target) {
            final Map<Integer, Integer> seen = new HashMap<>();
            for (int j = 0; j < nums.length; ++j) {
                final Integer i = seen.get(target - nums[j]); // One hash-map access v.s. two when using contains beforehand.
                if (i != null) {
                    return new int[]{ i+1, j+1 };
                }
                numbers.put(nums[j], j);
            }
            return new int[]{-1, -1};
        }
    }
    

    Note that by construction, if the complement is present in the map/dictionary, then the index stored will always be lower than the current index. Hence the following proposition is verified:

    index1 must be less than index2

    Also note that the OP's question needed 1-based indexes, which is what I've provided above, but the Leetcode question referred to seems to have been updated since then, and now is 0-based: https://leetcode.com/problems/two-sum.

    I hope this helps.

    0 讨论(0)
  • 2021-02-06 01:48

    Here is an Efficient Solution.

    Time Complexity - O(n) and Space Complexity - O(1)

    Sol: Will take two-pointer(start_pointer and end_pointer). Initially start_pointer point at the first index and end_pointer point to the last.

    Add both the element (sum = array[start_pointer] + array[last_pointer]. After that check, if the sum > target element or not. If yes decrease the end_pointer else increase start_pointer. If sum = target, means you got the indexes.

    public int[] twoSum(int[] numbers, int target) {
    
        int[] arr = new int[2]; // to store result
        int sum=0;
    
        int start_pointer=0;     
        int end_pointer = (numbers.length)-1;
    
        while(start_pointer<=end_pointer){
    
            sum=numbers[start_pointer]+numbers[end_pointer]; 
    
            if(sum>target)
                end_pointer-=1;
            else if(sum<target)
                start_pointer+=1;
            else{
                arr[0]=start_pointer;
                arr[1]=end_pointer;
                break;
            }       
        }       
        return arr;
    }
    
    0 讨论(0)
  • 2021-02-06 01:49
     public static int[] twoSum(int[] nums, int target) {
            int []resultarray=new int[2];
            for (int i=0;i<nums.length-1;i++){
                for(int k=1;k<nums.length;k++)
                {
                     if(target==nums[i]+nums[k])
                     {
                         resultarray[0]=nums[i];
                         resultarray[1]=nums[k];
                     }
                }
            }
     return resultarray;
        }
    
    0 讨论(0)
  • 2021-02-06 01:50

    This is my python solution

    class Solution:
        def twoSum(self, nums, target):
            """
            :type nums: List[int]
            :type target: int
            :rtype: List[int]
            """
    
            copy_dict = {}
            for pos in range(0, len(nums)):
                if nums[pos] not in copy_dict.keys():
                    copy_dict[nums[pos]] = [pos]
                else:
                    copy_dict[nums[pos]].append(pos)
    
            def get_sum_indexes(sorted_array, target):
                right_pointer = len(sorted_array) - 1
                left_pointer = 0
                while left_pointer < len(sorted_array) or right_pointer > 0:
                    if sorted_array[right_pointer] + sorted_array[left_pointer] == target:
                        return [sorted_array[left_pointer], sorted_array[right_pointer]]
                    elif sorted_array[right_pointer] + sorted_array[left_pointer] > target:
                        right_pointer -= 1
                    elif sorted_array[right_pointer] + sorted_array[left_pointer] < target:
                        left_pointer += 1
                return None
            sum_numbers = get_sum_indexes(sorted(nums), target)
            if len(copy_dict[sum_numbers[0]]) == 1:
                answer_1 = copy_dict[sum_numbers[0]][0]
            else:
                answer_1 = copy_dict[sum_numbers[0]][0]
    
            if len(copy_dict[sum_numbers[1]]) == 1:
                answer_2 = copy_dict[sum_numbers[1]][0]
            else:
                answer_2 = copy_dict[sum_numbers[1]][1]
            return sorted([answer_1, answer_2])
    
    print(Solution().twoSum(nums=[-1, -2, -3, -4, -5], target=-8))
    print(Solution().twoSum(nums=[-3, -3], target=-6))
    
    0 讨论(0)
  • 2021-02-06 01:51

    Swift code with Time Complexity O(n) and Space complexity O(n):

    import UIKit
    
    class Solution{
        func twoSum(_ nums: [Int], _ target: Int) -> [Int]{
            var finalArray = [Int]()
            var newDictionary = [Int:Int]()
            for i in 0..<nums.count{
                let complement = target - nums[i]
                if newDictionary[complement] != nil && newDictionary[complement] != i{
    
                    finalArray.append(newDictionary[complement]!)
                    finalArray.append(i)
                    return finalArray
                }
                newDictionary[nums[i]] = i
    
            }
            return []
        }
    }
    
    func main(){
    
        let solution = Solution()
        print("All Good" ,solution.twoSum([1, 3, 4 , 5], 6))
    }
    
    main()
    
    0 讨论(0)
  • 2021-02-06 01:51

    I tried most of the answers and they don't seem to handle the edge cases properly. Hence, throwing my two cents for python3 solution that handles the edge cases. I used Max's algorithm to implement it:

       def twoSum(nums, target):
        output=[]
        arr=sorted(nums)
        x=0
        y=-1
        X=len(nums)-1
        while x<X:
            if (arr[X]+arr[x] >  target):
                X-=1 
            elif (arr[X]+arr[x] <  target):
                x+=1
            elif (arr[X]+arr[x] == target):
                #print("Found",arr[X],arr[x])
                num1=arr[x]
                num2=arr[X]
                x+=1
                X-=1 
        for i in range(len(nums)):
            if num1 == nums[i] and y==-1:
                index1=i
                y=i
            elif num2 == nums[i]:
                index2=i         
        return [index1, index2]
    

    N.B. It's important to consider edge cases and inputs like the following

    print(twoSum([3,2,4],  6)) # [1,2]
    print(twoSum([3,3],  6))  # [0,1]
    
    0 讨论(0)
提交回复
热议问题