LeetCode 1 Two Sum

来源:互联网 发布:口才训练软件下载 编辑:程序博客网 时间:2024/04/26 13:53

题目







分析


看完题目首先可以考虑直接暴力破解,不过O(n*2)的时间复杂度会超时,需要降低时间复杂度。

1.先进行一个快排,两个指针分别指向首(i)尾(j),若和大于要求值则 j--,否则i++

2.先进行一个快排,再在数组中通过二分查找另一个数。



题解


1.


void swap(int *x, int *y){    int temp;    temp = *x;    *x = *y;    *y = temp;    return;}

void sort(int arr[],int ind[],int left,int right){    if(left>right)        return;    int i=left;    int j=right;    int mid=(left+right)/2;    swap(&arr[mid],&arr[left]);    swap(&ind[mid],&ind[left]);    int temp=arr[left];    while(i!=j)    {        while(arr[j]>=temp && i<j)            j--;        while(arr[i]<=temp && i<j)            i++;                    if(i<j)        {            swap(&arr[i],&arr[j]);            swap(&ind[i],&ind[j]);        }    }    swap(&arr[i],&arr[left]);    swap(&ind[i],&ind[left]);        sort(arr,ind,left,i-1);    sort(arr,ind,i+1,right);    }

另外一个数组是为了在交换的时候将下标号也跟着交换。


int *twoSum(int numbers[], int n, int target) {    int *a=(int *)malloc(2*sizeof(int));    int *index=(int *)malloc(n*sizeof(int));    for(int i=0;i<n;i++)        index[i]=i+1;    a[0]=a[1]=-1;    sort(numbers,index,0,n-1);    int i=0;    int j=n-1;    while (i!=j) {        if(numbers[i]+numbers[j]==target)        {            if(index[i]>index[j])            {                a[0]=index[j];                a[1]=index[i];            }            else            {                a[0]=index[i];                a[1]=index[j];            }            break;        }        else if(numbers[i]+numbers[j]<target)            i++;        else            j--;    }    return a;}



2.

int search(int arr[],int value,int left,int right){    if(left>right)        return -1;    int mid=(left+right)/2;    if(arr[mid]==value)        return mid;    else if (arr[mid]>value)        return search(arr,value,left,mid-1);    else        return search(arr,value,mid+1,right);    }

swap函数和sort函数同解1.


int *twoSum(int numbers[], int n, int target) {    int *a=(int *)malloc(2*sizeof(int));    int *index=(int *)malloc(n*sizeof(int));    for(int i=0;i<n;i++)        index[i]=i+1;    a[0]=a[1]=-1;    sort(numbers,index,0,n-1);    for(int i=0;i<n;i++)     {        int j=search(numbers,target-numbers[i],i+1,n-1);        if(j!=-1)        {            if(index[i]>index[j])            {                a[0]=index[j];                a[1]=index[i];            }            else            {                a[0]=index[i];                a[1]=index[j];            }            break;        }    }    return a;}





再说说快排


 int mid=(left+right)/2; swap(&arr[mid],&arr[left]); swap(&ind[mid],&ind[left]);

快排里面有这神奇的三句,是因为再没加之前是超时的,错误的例子是一个递增的长序列。

在这个递增的长序列中,不论是以最左边为参照还是以最右边为参照都会全部进行比较,时间复杂度为O(N*2)

这样还是过不去的(如果这样都能过,不如直接写两层for循环)

于是投机的把最中间的值先换到了左边,再也左边为参照,一次全部交换完毕才通过了测试。

不仅能写出算法,还    知道它最适合的情景和最不适合的情景    也是很重要的。






再试试桶排序


int *twoSum(int numbers[], int n, int target) {    int *a=(int *)malloc(2*sizeof(int));    int *index=(int *)malloc(40000*sizeof(int)); //定义40000个桶 默认值为-1    for(int i=0;i<40000;i++)        index[i]=-1;    for(int i=0;i<n;i++)                 //将元素的索引存在 值+1000 的地桶里    {        index[numbers[i]+1000]=i;    }    int temp,j;    for(int j=0;j<n;j++)    {        temp=index[target-numbers[j]+1000];     // 查找另一个数时,查找该数值+1000的桶里有没有不为-1的排号        if(temp!=-1 && temp!=j)                 // 不为-1的排号 且与第一个数索引不同 则为另一个值的索引        {            if(j>temp)            {                a[0]=temp+1;                a[1]=j+1;            }            else            {                a[0]=j+1;                a[1]=temp+1;            }            return a;        }    }    }

加1000是为了使得下标值都为正数




试试C++


class Solution {public:    vector<int> twoSum(vector<int> &numbers, int target) {        vector<int> results;        multimap<int, int> iimmap;        for(int i=0; i<numbers.size(); i++){            iimmap.insert(pair<int, int>(numbers[i], i));        }        for(int i=0;i<numbers.size();i++)        {            if(iimmap.count(target-numbers[i]))            {                int n=iimmap.find(target-numbers[i])->second;                if(n<i)                 {                    results.push_back(n+1);                    results.push_back(i+1);                    return results;                 }                 else if(n>i)                 {                    results.push_back(i+1);                    results.push_back(n+1);                    return results;                 }                            }        }    }};

思路同桶排序一样,不过更简单,不用考虑数组下标为负时需要做的偏移。用到了:

1.multimap的插入,直接插入pair<int,int>类型的数据

2.通过multimap.count(key)来统计是否有key主键存入

3.multimap.find(key)得到指向key的iterator  iterator->second获得了key对应的value值,也就是我们需要的索引值。


简单点

class Solution {public:    vector<int> twoSum(vector<int> &numbers, int target) {        map<int, int> iimmap;        vector<int> results;        for(int i=0; i<numbers.size(); i++){            if(iimmap.count(target-numbers[i])){                int n=iimmap.find(target-numbers[i])->second;                    results.push_back(n+1);                    results.push_back(i+1);                    return results;            }            iimmap.insert(pair<int, int>(numbers[i], i));        }        return results;    }};





用JAVA的Hashmap


public class Solution {   public int[] twoSum(int[] numbers, int target) {   Map<Integer, Integer> map = new HashMap<>();   for (int i = 0; i < numbers.length; i++) {      if (map.containsKey(target - numbers[i])) {         return new int[] { map.get(target - numbers[i]) + 1, i + 1 };      }      map.put(numbers[i], i);   }   throw new IllegalArgumentException("No two sum solution"); }}

其实上面的两次for循环只是为了看起来理解更方便,实际上一次for循环就能解决。




0 0
原创粉丝点击