LeetCode 1 Two Sum

题目







分析


看完题目首先可以考虑直接暴力破解,不过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循环就能解决。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值