zoukankan      html  css  js  c++  java
  • 【LeetCode】Two Sum

    Two Sum

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

    The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

    You may assume that each input would have exactly one solution.

    Input: numbers={2, 7, 11, 15}, target=9
    Output: index1=1, index2=2

     

    Solution:

    如果只是简单的:

    1 class Solution:
    2     # @return a tuple, (index1, index2)
    3     def twoSum(self, num, target):
    4         for i in range(len(num)):
    5             numJ = target-num[i]
    6             if numJ in num:
    7                 return (i+1, num.index(numJ)+1)
    8         

    肯定是会超时的。这个Python程序应该是O(n^3)的(for, 查找numJ, index(numJ)),一般的O(n^2)(用for将查找值和索引合成一个循环)也会超时。

    于是很快可以想到另外一种解法:QuickSort + BinarySearch。这是一般的想法,是可以AC的(O(nlogn))。

    代码如下:

     1 void sort(int a[], int b[], int l, int r)
     2 {
     3     int i, j, x, t;
     4     i = l; j = r; x = a[i + ((j - i) >> 1)];
     5     do
     6     {
     7         while (x > a[i]) i++;
     8         while (x < a[j]) j--;
     9         if (i <= j)
    10         {
    11             t = a[i]; a[i] = a[j]; a[j] = t;
    12             t = b[i]; b[i] = b[j]; b[j] = t;
    13             i++; j--;
    14         }
    15     } while (i <= j);
    16     if (i < r) sort(a, b, i, r);
    17     if (j > l) sort(a, b, l, j);
    18 }
    19 
    20 int binSearch(int a[], int e, int lo, int hi)
    21 {
    22     int mi;
    23     while (lo < hi)
    24     {
    25         mi = (lo + hi) >> 1;
    26         if (e < a[mi]) hi = mi;
    27         else lo = mi + 1;
    28     }
    29     return --lo;
    30 }
    31 
    32 int *twoSum(int numbers[], int n, int target) {
    33     int *index = (int *)malloc(n * sizeof(int));
    34     int i, indexLook;
    35     int *ans = (int *)malloc(2 * sizeof(int));
    36     for (i = 0; i<n; i++) index[i] = i;
    37     sort(numbers, index, 0, n-1);
    38     for (i = 0; i<n; i++)
    39     {
    40         indexLook = binSearch(numbers, target - numbers[i], 0, n);
    41         if (numbers[indexLook] == target - numbers[i])
    42         {
    43             if (index[i] < index[indexLook])
    44             {
    45                 ans[0] = index[i]+1;
    46                 ans[1] = index[indexLook]+1;
    47             }
    48             else
    49             {
    50                 ans[1] = index[i]+1;
    51                 ans[0] = index[indexLook]+1;
    52             }
    53             return ans;
    54         }
    55     }
    56 }

    这里,还有一种也比较常规的解法:HashTable。(O(n))

    可以在边建立哈希表的同时也进行查找(按先后顺序,查找第二个时第一个肯定已经入表)。将num中的值映射到其下标,对于每一个num中的值e,在HashTable中查找target-e对应的下标。如果能找到直接返回结果;如果不能找到则把e和其下标也加入哈希表中。

    Java解法如下:

     1 import java.util.HashMap;
     2 import java.util.Map;
     3 
     4 public class Solution {
     5     public int[] twoSum(int[] numbers, int target) {
     6         Map<Integer, Integer> map=new HashMap<>(numbers.length*2);
     7         for(int i=0;i<numbers.length;i++){
     8             Integer company=map.get(target-numbers[i]);
     9             if(company==null)
    10                 map.put(numbers[i], i);
    11             else
    12                 return new int[]{company+1,i+1};
    13         }
    14         return null;
    15     }
    16 }

    另外,其实这道题的本质就是找one pair numbers使得其和等于target。我们可以从整体上来看待这个问题,并且根据找到的pair与target之间的关系调整位置继续找,直到找到符合条件的唯一解。

    当num排完序后,我们考虑从第一个数(i=0)和最后一个数(j=len-1)开始,如果它们的和比target大,说明此时和需要调整得更小,那么把j指针向前调;如果当前的和比target小,则把i指针向后调。直到找到这样的pair使得和正好等于target。这样就可以避免对于每一个元素e都要对target-e进行二分查找,效率肯定更高。(因为如果当前i一定是最后结果(i, j)中的一个值,那么比当前j下标大的数一定使得当前和比target大,所以j会不断减小直到到正确解,正确性可以得到证明。)

    AC代码如下(Python):O(nlogn)

     1 class Solution:
     2     # @return a tuple, (index1, index2)
     3     def twoSum(self, num, target):
     4         copyNum = num[:]
     5         copyNum.sort()
     6         firstIndex = 0
     7         lastIndex = len(copyNum) - 1
     8         while True:
     9             if copyNum[firstIndex] + copyNum[lastIndex] == target:
    10                 break
    11             elif copyNum[firstIndex] + copyNum[lastIndex] > target:
    12                 lastIndex -= 1
    13             else:
    14                 firstIndex += 1
    15         
    16         fIndex = num.index(copyNum[firstIndex])+1
    17         num.reverse()
    18         lIndex = len(num) - num.index(copyNum[lastIndex])
    19         
    20         if fIndex > lIndex:
    21             fIndex, lIndex = lIndex, fIndex
    22         return (fIndex, lIndex)
    23         

    (因为index只能找到第一个等于该值得下标,当两个加数相等时,就必需从后往前找,所以要num.reverse(),或者自己写一个function从后往前找。)

    参考:

    1、https://leetcode.com/discuss/27316/java-solution-space-using-binarysearch-time-space-using-hash

    2、https://leetcode.com/discuss/26760/python-solution-with-52ms-cost

  • 相关阅读:
    一个int类型究竟占多少个字节
    TCMalloc 安装与使用
    [创意标题] spoj 11354 Amusing numbers
    如何更好地理解和使用Github
    一天JavaScript示例-点击图片显示大图片添加鼠标
    php方法综述除去换行符(PHP_EOL使用变量)
    使用jQuery和css3实现了仿淘宝ued博客左边的菜单切换动画
    【软件使用技巧】PL/SQL Developer实现双击table询
    newlisp 接受jenkins带空格的参数
    Oracle listener lsnrctl
  • 原文地址:https://www.cnblogs.com/maples7/p/4356066.html
Copyright © 2011-2022 走看看