《LeetCode》:Two Sum

《LeetCode》:Two Sum

昨天刚说的准备去刷《程序员面试金典》上面的题,但是看了下那本书上面的题,感觉都没有什么意思,因此也就打算来刷了leetCode上面的题了。

刷题的顺序选择了按照顺序来刷。

今天开始了第一题: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 

意思就是:在一个整型数组中,寻找两个数等于一个定值,返回这个数在数组中的下标,要注意的是:下标不是从0开始的。

《剑指Offer》上也有类似的题:和为定值的两个数,见此博文:http://blog.csdn.net/u010412719/article/details/49208709
这篇博文中介绍了三种方法。

由于题目中说是一个整型数组并没有考虑为负数的情况,因此,我想到的第一种方法:利用哈希

可以用哈希数组,开辟一个长度为sum的bool数组B[sum],并全部初始化为-1,
对数组A进行一次遍历,如果当前的元素A[i]大于sum,则直接跳过,
否则,继续作如下判断,如果B[A[i]]为-1,则将B[sum-A[i]]置为i,这样当继续向后遍历时,
如果有B[A[i]]不等于-1,则有符合条件的两个数,下标分别为A[i]和i。

具体代码如下:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
int* twoSum(int* nums, int numsSize, int target) {

    //下面采用的方法是:借助一个长度为target的int  temp[target+1]数组来保存结果,初始化为-1。
    //if nums[i]>target,则跳过此数字,否则进行如下判断
    //if temp[nums[i]]为-1,则将temp[target-num[i]]设置为i。if temp[num[i]]不等于-1,则说明找到了一种复合条件的情况。下标分别为temp[nums[i]]和i。
    //实现如下
    int *result=(int *)malloc(2*sizeof(int));
    if(result==NULL)
        exit(EXIT_FAILURE); 
    memset(result,0,2*sizeof(int));
    if(nums==NULL||numsSize<2){
        return result;
    }
    //借组一个中间数组
    int *temp=(int *)malloc((target+1)*sizeof(int));
    if(temp==NULL){
        exit(EXIT_FAILURE);

    }
    //初始化为 -1 
    memset(temp,-1,(target+1)*sizeof(int));
    int index=0; 
    while(index<numsSize){
        if(nums[index]>target){
            index++;
            continue; 
        } 
        else if(temp[nums[index]]==-1){//如果 temp[nums[index]为false,则标记temp[target-nums[index]]为  index
             temp[target-nums[index]]=index+1; 
        }
        else{//找到第二个数的下标 
            result[1]=index+1;
            result[0]=temp[nums[index]];
            return result;
        }

        index++; 
    }
    return result;

}
//上面的代码虽然能够正常运行,但是在leetcode中不能提交,还是报“超时”错误。  [0,4,3,0]   0

int main(void){
    int len;
    int target;
    while(scanf("%d %d",&len,&target)!=EOF&&len>1){
        int *nums=(int *)malloc(len*sizeof(int));
        if(nums==NULL){
            exit(EXIT_FAILURE);
        }
        for(int i=0;i<len;i++){
            scanf("%d",nums+i);
        }
        int *result=twoSum(nums, len, target);
        printf("%d , %d\n",result[0],result[1]);
    }
}

上面的代码在如下的输入是不可行的,即定值为负数不行的。

[-1 ,-2 ,-3,-4] -5

因此,就立刻明白了要考虑所有的情况。第一反应是考虑先将数组排序,然后利用两个指针前后一起遍历得到,但是考虑到时间复杂度为O(nlogn),就在想是否还有更好的方法,想了很久,没有想到,最后就将先快排然后遍历试了下,居然AC了。太高兴了,哈哈。

实现代码如下:
与之前《剑指Offer》上面的不同之处在于,这里需要返回的是下标,因此,要小小的注意一下。

/** * Note: The returned array must be malloced, assume caller calls free(). */
 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
int  cmp(const void* a,const void *b){
    return (*(int *)a)-(*(int *)b);
}
void swap(int *a,int *b){
    int temp=*a;
    *a=*b;
    *b=temp;
}
int* twoSum(int* nums, int numsSize, int target) {

// 对于排序过的数组,可以设置头尾指针,如果arr[begin]+arr[end]>target,则end--;如果arr[begin]+arr[end]<target,则begin++;否则返回begin、end
// 实现代码如下


     //先对数组进行排序
     int *arr=(int *)malloc(numsSize*sizeof(int));
     if(arr==NULL){
        exit(EXIT_FAILURE);
     }
     for(int i=0;i<numsSize;i++){
        arr[i]=nums[i];
     }
    qsort(arr,numsSize,sizeof(nums[0]),cmp); 
    //在已排过序的数组arr中找出这两个数 
     int begin=0;
     int end=numsSize-1;
     while(begin<end){
         int tempResult=arr[begin]+arr[end];
         if(tempResult<target){
             begin++;
         }
         else if(tempResult>target){
             end--;
         }
         else{
            break;
         }
     }
     //然后遍历一次找出这两个数在原数组中nums的索引
     int *result=(int *)malloc(2*sizeof(int));
     memset(result,-1,2*sizeof(int));
     if(nums==NULL||numsSize<2){
         return result;
     }
     if(begin<end){
            for(int i=0;i<numsSize;i++){
                if(nums[i]==arr[begin]){
                    if(result[0]==-1){
                        result[0]=i+1;
                        continue;
                     }  
                 }
                 if(nums[i]==arr[end]){
                    if(result[1]==-1){
                        result[1]=i+1;
                     }
                 }
            } 

     }
     //在对负数进行排序后,会导致第一个数的索引大于第二个的索引。 
     //对result进行排序,小的在前,大的在后
     if(result[0]>result[1]){
        swap(result,result+1); 
     }

     free(arr);
     arr=NULL;
     return result;


}


int main(void){
    int len;
    int target;
    while(scanf("%d %d",&len,&target)!=EOF&&len>1){
        int *nums=(int *)malloc(len*sizeof(int));
        if(nums==NULL){
            exit(EXIT_FAILURE);
        }
        for(int i=0;i<len;i++){
            scanf("%d",nums+i);
        }
        int *result=twoSum(nums, len, target);
        printf("%d , %d\n",result[0],result[1]);
    }
}

由于是第一次刷leetCode上面的题,放在一张AC之后的图吧。

《LeetCode》:Two Sum_第1张图片

你可能感兴趣的:(LeetCode,面试,TwoSum)