twoSum算法:如何改进?

时间:2012-10-24 03:54:58

标签: java

我觉得做算法并在leetcode

上发现了这个问题
  

给定一个整数数组,找到两个数字,使它们相加到一个特定的目标数。

     

函数twoSum应返回两个数字的索引,以便它们相加到目标,其中index1必须小于index2。请注意,您返回的答案(index1和index2)不是从零开始的。

     

您可以假设每个输入都只有一个解决方案。

     

输入:数字= {2,7,11,15},目标= 9

     

输出:index1 = 1,index2 = 2

我的解决方案是O(n ^ 2)。我想知道是否有更好的方法吗?像O(n)或O(nlogn)

import java.util.Arrays;
public class ReturnIndex {
    public int[] twoSum(int[] numbers, int target) {
        int tail = numbers.length-1;
        int[] n = new int[2];
        for (int i=0;i<tail;i++) {
            for(int j=i+1;j<tail;j++) {
                if(target ==(numbers[i]+numbers[j])) {
                    n[0] = i+1;
                    n[1] = j+1;
                }
            }
        }
        return n;
    }

    public static void main(String[] args) {
        int[] s = {150,24,79,50,88,345,3};
        int value = 200;
        ReturnIndex r = new ReturnIndex();
        int[] a = r.twoSum(s,value);
        System.out.println(Arrays.toString(a));
    }
}

24 个答案:

答案 0 :(得分:9)

对数组进行排序。首先指向两个指针并指向最后一个(x和X)。在循环中运行:

if      (a[X]+a[x] >  N) then X-- 
else if (a[X]+a[x] <  N) then x++
else if (a[X]+a[x] == N) then found.

if (x > X) then no numbers exist.

O(nlogn)时间,O(1)记忆

答案 1 :(得分:8)

O(n log n)时间,O(1)内存(不包括列表):

  1. 首先,对列表进行排序。这应该花费O(n log n)时间,就像大多数排序函数一样。

  2. 遍历列表,这应该在外部循环中花费O(n)时间。此时,您可以对已排序的子列表中最接近的匹配整数进行二进制搜索,这应该花费O(log n)时间。这个阶段最终需要花费O(n log n)

  3. 编辑:查看以下Max的答案。它仍然是O(n log n)时间和O(1)内存,但他通过从列表的每一端走一个指针来避免二进制搜索。

    O(n)时间,O(n)记忆:

    构建一个哈希表,其中应插入O(1)并包含O(1)。然后,在O(n)外部循环中,对于每个数字i,检查哈希表中是否total - i。如果没有,请添加;如果是的话,那你就得到了两个号码。

    无论哪种方式,您都需要通过数组进行额外扫描才能获得索引,但这没有问题 - 只需O(n)次。如果你想避免它,你可以根据需要将原始索引保留在排序列表或哈希表中,但是它有内存占用而不是时间占用。

答案 2 :(得分:2)

您可以在下面找到一个解决方案,其中可以在 O(n log n) 时间找到这两个数字:

1- Sort the numbers in ascending (or descending) order             // O(n log n)

2- Compute diff = target - item for each item                      // O(n) 

3- For each calculated diff, look up the calculated value in the sorted items 
   using the Binary search algorithm                               // O(n log n) 

Java中一个完整的,有效的实现:

import java.util.ArrayList;

public class NumbersFinder {

    class Item{
        private int value;
        private int index;

        public Item(int value, int index){
            this.value = value;
            this.index = index;
        }

        public int getValue(){
            return value;
        }

        public int getIndex(){
            return index;
        }
    }

    public ArrayList<Item> find(int[] values, int target){      
        ArrayList<Item> items = new ArrayList<Item>();
        for(int i = 0; i < values.length; i++)
            items.add(new Item(values[i], i));

        items = quicksort(items);
        ArrayList<Integer> diffs = computeDiffs(items, target);

        Item item1 = null;
        Item item2 = null;

        boolean found = false;

        for(int i = 0; i < diffs.get(i) && !found; i++){
            item1 = items.get(i);
            item2 = searchSortedItems(items, diffs.get(i), 0, items.size());
            found = item2 != null;
        }
        if(found){
            ArrayList<Item> result = new ArrayList<Item>();
            result.add(item1);
            result.add(item2);
            return result;
        }
        else
            return null;
    }

    // find "value" in the sorted array of "items" using Binary search in O(log n)
    private Item searchSortedItems(ArrayList<Item> items, Integer value, int lower, int upper) {
        if(lower > upper)
            return null;
        int middle = (lower + upper)/2;
        Item middleItem = items.get(middle);
        if(middleItem.getValue() == value)
            return middleItem;
        else if(middleItem.getValue() < value)
            return searchSortedItems(items, value, middle+1, upper);
        else
            return searchSortedItems(items, value, lower, middle-1);
    }

    // Simply calculates difference between the target value and each item in the array; O(n)
    private ArrayList<Integer> computeDiffs(ArrayList<Item> items, int target) {
        ArrayList<Integer> diffs = new ArrayList<Integer>();
        for(int i = 0; i < items.size(); i++)
            diffs.add(target - items.get(i).getValue());
        return diffs;
    }

    // Sorts items using QuickSort algorithm in O(n Log n)
    private ArrayList<Item> quicksort(ArrayList<Item> items) {
        if (items.size() <= 1)
            return items;
        int pivot = items.size() / 2;
        ArrayList<Item> lesser = new ArrayList<Item>();
        ArrayList<Item> greater = new ArrayList<Item>();
        int sameAsPivot = 0;
        for (Item item : items) {
            if (item.getValue() > items.get(pivot).getValue())
                greater.add(item);
            else if (item.getValue() < items.get(pivot).getValue())
                lesser.add(item);
            else
                sameAsPivot++;
        }
        lesser = quicksort(lesser);
        for (int i = 0; i < sameAsPivot; i++)
            lesser.add(items.get(pivot));
        greater = quicksort(greater);
        ArrayList<Item> sorted = new ArrayList<Item>();
        for (Item item : lesser)
            sorted.add(item);
        for (Item item: greater)
            sorted.add(item);
        return sorted;
    }


    public static void main(String[] args){
        int[] s = {150,24,79,50,88,345,3};
        int value = 200;

        NumbersFinder finder = new NumbersFinder();
        ArrayList<Item> numbers = finder.find(s, value);

        if(numbers != null){
            System.out.println("First Number Found = " + numbers.get(0).getValue() + " ; Index = " + + numbers.get(0).getIndex());
            System.out.println("Second Number Found = " + numbers.get(1).getValue() + " ; Index = " + + numbers.get(1).getIndex());
        }
        else{
            System.out.println("No such two numbers found in the array!");
        }
    }
}

输出:

First Number Found = 50 ; Index = 3
Second Number Found = 150 ; Index = 0

答案 3 :(得分:0)

class Solution {
public int[] twoSum(int[] nums, int target) {
    int[] sortedNums = Arrays.copyOf(nums, nums.length);
    Arrays.sort(sortedNums);
            
    int leftSortedIndex = 0;
    int rightSortedIndex = sortedNums.length - 1;
    
    while(leftSortedIndex < rightSortedIndex) {
        int sum = sortedNums[leftSortedIndex] + sortedNums[rightSortedIndex];
        if(sum == target) {
            break;
        } else if(sum < target) {
            leftSortedIndex++;
        } else {
            rightSortedIndex--;
        }
    }
            
    int leftIndex = -1;
    int rightIndex = -1;
    for(int index=0; index < nums.length; index++) {
        if(leftIndex == -1 && nums[index] == sortedNums[leftSortedIndex]) {
            leftIndex = index;
        } else if(rightIndex == -1 && nums[index] == sortedNums[rightSortedIndex]) {
            rightIndex = index;
        }
    }
    
    
    return (new int[] {leftIndex, rightIndex});
}

}

答案 4 :(得分:0)

我会这样接近:

  1. 从较小值到较低值订购数组

  2. 按照你的方式循环遍历数组,但只要

    ,就提前退出循环

    目标&lt;(数字[i] +数字[j])

  3. 一旦你得到了两个元素的值,使得n [0] + n [1] = target,请回顾原始数组以找到它们的索引。

答案 5 :(得分:0)

class Solution {
public int[] twoSum(int[] nums, int target) {
    int[] sortedNums = Arrays.copyOf(nums, nums.length);
    Arrays.sort(sortedNums);
            
    int leftSortedIndex = 0;
    int rightSortedIndex = sortedNums.length - 1;
    
    while(leftSortedIndex < rightSortedIndex) {
        int sum = sortedNums[leftSortedIndex] + sortedNums[rightSortedIndex];
        if(sum == target) {
            break;
        } else if(sum < target) {
            leftSortedIndex++;
        } else {
            rightSortedIndex--;
        }
    }
            
    int leftIndex = -1;
    int rightIndex = -1;
    for(int index=0; index < nums.length; index++) {
        if(leftIndex == -1 && nums[index] == sortedNums[leftSortedIndex]) {
            leftIndex = index;
            continue;
        }
        
        if(rightIndex == -1 && nums[index] == sortedNums[rightSortedIndex]) {
            rightIndex = index;
        } 
    }
    
    
    return (new int[] {leftIndex, rightIndex});
}

}

答案 6 :(得分:0)

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        out_list=[] 
        for i in range(len(nums)):
            for j in range(len(nums)):
                if(target-nums[i]) == nums[j] and i != j:
                    out_list.append(i)
        return out_list

答案 7 :(得分:0)

我对这个问题的解决办法是

public int[] twoSums(int[] unsortedNum, int target) {
        int[] nums = Arrays.copyOf(unsortedNum, unsortedNum.length);
        Arrays.sort(nums);
        boolean isResultFound = false;
        int start = 0;
        int end = nums.length-1;
        while(!(start > end)) {
            if(nums[start]+nums[end] > target){
                end--;
            } else if (nums[start]+nums[end] < target){
                start++;
            } else if(nums[start] + nums[end] == target){
                isResultFound = true;
                break;
            }
        }
        if(isResultFound){
            int s = -1;
            int e = -1;
            for(int i = 0; i< unsortedNum.length; i++){
                if(s != -1 && e != -1){
                    break;
                }
                if(s == -1 && unsortedNum[i] == nums[start]){
                    s = i;
                } else if(e == -1 && unsortedNum[i] == nums[end]) {
                    e = i;
                }
            }
            return new int[] {s,e};
        }
        // for element not found
        return new int[]{-1,-1};
    }

最后,如果您得到-1,-1作为索引,那么您可以说未找到的元素可以累加到目标元素。

答案 8 :(得分:0)

这里是O(n):

public int[] findSumMatched(int[] numbers, int target) {
    Map<Integer, Integer> mapOfNumbers = new HashMap<Integer, Integer>();
    for (int i = 0; i<numbers.length; i++) {
        int secondNumber = target - numbers[i];
        if (mapOfNumbers.get(secondNumber) != null){
            return new int[] {mapOfNumbers.get(secondNumber), i};
        }
        mapOfNumbers.put(numbers[i], i);
    }
    throw new IllegalArgumentException();
}

答案 9 :(得分:0)

只是好奇,但是这个O(n)解决方案怎么了?

public int[] twoSum(int[] nums, int target) {
    for (int i = 0; i < nums.length - 1; i++){
        if (nums[i] + nums[i+1] == target)
            return new int[] {i, i+1};
    }
    return null;
}

答案 10 :(得分:0)

使用HashMap,如果 HashMap中搜索的复杂性以O(logn)的顺序进行,那么这也是一种解决方案,那么在最坏的情况下,复杂度将为 O(nlogn)

    public int[] twoSum(int[] nums, int target) {
        
        int [] resultIndex = null;
        
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        
        for(int i=0;i<nums.length;i++){
            int temp = target - nums[i];
            
            if(map.containsKey(temp)){
                resultIndex = new int[2];
                resultIndex[0]=map.get(temp);
                resultIndex[1]=i;
            }else{
                map.put(nums[i],i);
            }
        }
        return resultIndex;
    }

答案 11 :(得分:0)

我们可以使用HashMap进行操作,时间复杂度为O(n)

public class ReturnIndicesOfElementsAddToSum {

public static void main(String[] args) {
    int[] nums = {2, 7, 11, 15};
    int target = 18;

    if(!getIndices(nums,target)) {
        System.out.println("No such numbers found");
    }

}

static boolean getIndices(int[] nums, int target) {
    Map<Integer,Integer> indexMap = new HashMap<>();
    boolean numFound = false;
    for(int i=0;i<nums.length;i++) {
        int temp = target - nums[i];
        indexMap.put(nums[i], i);
        if(indexMap.containsKey(temp)) {
            System.out.printf("%d and %d adds upto the target value and indices are %d and %d"
                            , nums[i], temp, i, indexMap.get(temp));
            numFound = true;
        }
    }
    return numFound;
}

}

答案 12 :(得分:0)

这是一个有效的解决方案。

时间复杂度-O(n)空间复杂度-O(1)

Sol:需要两个指针(start_pointer和end_pointer)。最初,start_pointer指向第一个索引,end_pointer指向最后一个索引。

添加两个元素( sum = array [start_pointer] + array [last_pointer] 。检查之后,是否 sum> target 个元素。如果是,则减少 end_pointer ,否则增加 start_pointer 。如果 sum = target ,则表示您已获得索引。

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;
}

答案 13 :(得分:0)

两和问题的幼稚解法是O(n^2),s.t。 n是所提供的数字数组的长度。

但是,我们可以通过使用到目前为止所看到的值(键=数字,值=索引)的哈希表并在迭代迭代时检查补码是否已经存在(O(1))来做得更好。数字。这种方法最适合未排序的数组

  • 运行时复杂度:O(n)
  • 空间复杂度:O(n)-尽管有解决方案,但实际上是O(n/2)

考虑到OP的问题:

  • 指定输入数组是否已排序(因此可以安全地假定输入数组可以是任何东西),并且
  • 具体要求提供的数组的索引,而不是实际的数字,对数组进行排序的任何解决方案都需要事先复制它,并在排序后的数组和未排序的数组,或在原始数组上进行迭代,因此,根据选择的方法,会消耗内存(O(n))或时间(O(n))。因此,严格来说,(currently) accepted solution的第一部分是不正确

最佳解决方案:

  • 在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]
  • 在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};
    }
}

请注意,通过构造,如果补码存在于地图/词典中,则存储的索引将始终低于当前索引。因此,以下命题得到了验证:

index1必须小于index2

还要注意,OP的问题需要基于1的索引,这是我上面提供的,但是从那时起,提到的Leetcode问题似乎已经更新,现在是基于0的:https://leetcode.com/problems/two-sum

我希望这会有所帮助。

答案 14 :(得分:0)

我尝试了大多数答案,但它们似乎无法正确处理极端情况。因此,我花了两美分买了处理极端情况的python3解决方案。我使用Max的算法来实现它:

   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]

重要的是要考虑以下情况和输入

print(twoSum([3,2,4],  6)) # [1,2]
print(twoSum([3,3],  6))  # [0,1]

答案 15 :(得分:0)

就像上面提到的@Prayer一样,这是公认的答案。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] resultarray=new int[2];
        for (int i=0;i<nums.length-1;i++){
            for(int k=i+1;k<nums.length;k++)
            {
                 if(target==nums[i]+nums[k])
                 {
                     resultarray[0]=i;
                     resultarray[1]=k;
                 }
            }
        }
        return resultarray;
    }
}

答案 16 :(得分:0)

可以提供O(n)时间解决方案,但他的记忆不能为O(1)

首先,您声明一个键-值对,其中key是整数数组中的值,而value是整数数组中的索引。并且,您需要声明一个哈希表来保存键值对。 然后,您需要遍历整个整数数组, 如果此数组(= sum-array [i])的值在哈希表中,那么恭喜您找到它, 如果没有,它将存储在哈希表中。

因此,花费的全部时间就是插入和查询哈希表的时间。 内存是哈希表的大小。

我的英语不是很好,希望我能为您提供帮助。

public static void main(String args[]) {
    int[] array = {150,24,79,50,88,345,3};
    int sum = 200;


    Map<Integer,Integer> table = new HashMap<>();
    StringBuilder builder = new StringBuilder();
    for(int i=0;i<array.length;i++){
        int key = sum - array[i];
        if(table.containsKey(key)){
            builder.append("index1=").append(table.get(key)).
                    append(" index2=").append(i);
        }else{
            table.put(array[i],i);
        }
    }
    System.out.println(builder);
}

答案 17 :(得分:0)

使用哈希映射的c ++中的O(n)解决方案仅利用实数中的加法运算规则

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> my_map;
          for ( int i = 0 ; i < nums.size(); i++ ){
                if(my_map.find(target - nums[i]) != my_map.end()){
                    return vector<int> {my_map[target - nums[i]], i};
                }  
                my_map[nums[i]] = i ;
          }
    }
};

答案 18 :(得分:0)

时间复杂度为O(n)和空间复杂度为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()

答案 19 :(得分:0)

这是我的python解决方案

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))

答案 20 :(得分:0)

typedef struct arg_struct {
struct GPU_FFT *fft;
struct GPU_FFT_COMPLEX *base;
float **input;
float *output;
int number;
} arg_struct;

...

arguments[0].input = **Queue;
arguments[1].input = *(*(Queue)+QueueSize[0]);

答案 21 :(得分:0)

这是使用HashMap在java中进行两次传递的答案。假设数组中没有重复的元素,并且只存在一个解决方案。

import java.util.HashMap;

public class TwoSum {

    int[] index = new int[2];
    public int[] twoSum(int[] nums, int target)
    {
        int length = nums.length;
        //initialize return values assuming that pair for the given target
        //doesn't exist
        index[0]=-1;
        index[1]=-1;
        //sanity check
        if(length<1) return index;

        HashMap<Integer, Integer> numHash = new HashMap<>(length);
        //get the values from array into HashMap assuming that there aren't duplicate values
        for(int i=0; i<length;i++)
        {
            numHash.put(nums[i],i);
        }

        //check for the value in the array and the difference between target and it. Assume that only
        //one such pair exists
        for(int i=0;i<length;i++)
        {
            int val1 = nums[i];
            int val2=target-val1;
            //make sure that it doesn't return the index of the first number in the pait you are searching for
            if( numHash.containsKey(val2) && numHash.get(val2)!=i){
                index[0]=i;
                index[1] =numHash.get(target-nums[i]);
                break;
            }
        }
        return index;
    }
}

答案 22 :(得分:0)

这是我的带有O(nlog(n))的cpp解决方案:

String teamSide;
int displayYardLine;
if(yardLine < opponentsYardLine) {
    displayYardLine = yardLine;
    teamSide = "our"; // or our team name
} else if(yardLine == opponentsYardLine) {
    displayYardLine = yardLine;
    teamSide = "the";
} else if(yardLine > opponentsYardLine) {
    displayYardLine = opponentsYardLine;
    teamSide = "the opponent's" // or their team name
}

System.out.println(down + "st and " + yards + " on " + teamSide + " " +    
displayYardLine + " yard line.");

查看我的博客,了解详细说明。 https://algorithm.pingzhang.io/Array/two_sum_problem.html

答案 23 :(得分:0)

python中的一行解决方案:

class Solution(object):
    """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
    """
    def twoSum(self, nums, target):            
        x = [[i, nums.index(target-j)] for i,j in enumerate(nums) if nums.count(target-j) > 0 and nums.index(target-j)!=i]

        return x.pop()