LeetCode1

 

1. 两数之和

思路如下

假入给定数组里边最大数是19,而且都是正数,我们可以再写一个数组,弄一个如下的对应关系。不妨假设上边数组叫a数组,下边数组叫b数组。b存储数据的位置是a的值对应的位置,b的值是a的位置。例如,a[1]=7,所以,在b7】中存1.

经过上方的对应关系,得出以下结果

 

如果我给b数组都在没有数值的地方都赋值为-1,

 

那么在b数组中,就可以很方便找到,a中的某个数m是否存在,如果存在,这个数在b数组相应位置的值,就是m的位置。例如,a中的11存在不,我只需要在b中看b11】是否等于-1,如果等于-1,那就不存在,不等于就存在,而且11的位置在a中是2,即

a2==11。如果我要看,a12存在不,就在b中看b12】是不是等于-1,我们一看,b[12]=-1,所以a中不存在这个数。

 

接下来我们回到这个题上,对于这组测试用例,target=9

我们就可以遍历a数组,从头到尾找那个可以配对的数,看对于,ai】来说,我需要知道9-a[i]a中存不存在。那么我们只需要看b9-a[i]】是不是等于-1,如果不等于,那么这两个数的位置我们就找到了,一个是i,另一个是b9-a[i]】。

在这个测试用例中,当我们遍历到a[0]时,我们需要知道9-a[0]=9-2=7,也就是7这个值是否存在,我们看b数组,发现b7】不是-1,所以我们就找到了这两个值,一个是0,一个是b[7]的值,1

接下来我么分析一下时间。加入a数组有1000个数字,即numsSize=1000,按照你的写法

 

1 for(i=0; i<numsSize;i++){
2     for(j=i+1; j<numsSize; i++){
3         .....
4     }
5 }

 

 

这大概算了1000000次。

 

如果按照我这种写法,将a数组中的值对应到b中,运算1000次,遍历a数组,在b中找等不等-1,又运算1000次。总共是2000次。速度是你的500倍。这样写的好处,就是当我知道a[i]了,想要找到他配对的数,就不用在从头到尾找一遍,看看能不能找到那个配对了。你从头到尾找,还不一定能找到,白白浪费了时间。加了b数组之后,一下子就知道配对的存不存在,如果存在,位置也一下子就知道。

 

先假设所有的数都是大于0的,基于以上思想得出以下代码。

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int* twoSum(int* nums, int numsSize, int target){
 6     int i;
 7     int *re = (int *)malloc(2*sizeof(int));//用来存结果的
 8     int b[100];     //    将b全部置位-1
 9 
10     /**
11     *讲一下这个函数
12     * void *memset(void *str, int c, size_t n)
13     *   第一个参数:str,你要赋值的首地址,
14     *   第二个参数:你想要赋的值,只能是一个值。这个值会充满整个地址空间
15     *   第三个参数:值所占的字节数,你就写sizeof(类型)
16     *
17     */
18     memset(b, -1, sizeof(int));
19 
20 
21     for(i=0; i<numsSize; i++){ //   先做一个对应,以便可以快速找到某个数是否存在
22         b[nums[i]] = i;
23     }
24 
25     for(i=0; i<numsSize; i++){
26         if(b[ target-nums[i] ] != -1){//判断另外一个数存不存在
27             re[0] = i;
28             re[1] = b[ target-nums[i] ];
29             break;//找到了另外一个数就退出循环
30         }
31     }
32     return re;
33 }
34 
35 
36 //主函数用来测试我的函数
37 
38 int main()
39 {
40     int a[]={1,2,4,9};
41     int *r = twoSum(a, 4, 3);
42     printf("%d,%d", r[0], r[1]);
43     return 0;
44 }
View Code

 

在判断另外一个数是否存在的代码中

if(b[ target-nums[i] ] != -1){//判断另外一个数存不存在

有一种可能就是target<nums[i] ,这时候就会出现b[负数],这指定是不行的,数组中的索引只能是非负数。方括号里的东西可以叫索引。

从题中来看,因为所有数都是正数,大于targetnums[i]也不可能是解。所以,肯定找不到另外一个数。所以需要加一个条件,target-nums[i]>0 。接下来就出现一个问题,这个条件加在哪里的问题。看这个短路特性(这是个链接),看完你就知道加在哪里了。

 

回头再说说对应的问题。

如果有一个这样的数组{2,2,4}target = 4;我们在对应的时候,数组中的两个2会对应到一个地方。如下:

b数组中b[2]的值为啥是1而不是0,是因为你是从头到尾遍历a数组从而实现对应的。后边对应的时候讲前边覆盖了。当a[i]=第一个2的时候,另外一个数就是target-a[i]=2。而b[2]正好是第二2

 

这个题我们做的假设是所有的数都是正数,那如果正数负数都有会怎么样呢。我们说,在ab对应的时候,是将a的值和位置,互换,然后对应到b中。如果a的值是负数,那不就出现了b[负数],如下图,

这咋能行,数组的索引不可能是负的啊。

那我们就想一个办法,都把它变成正的。一个很好地办法就是把每一个数都加上一个整数,使得加完之后都是正的。

那加这个正数是多少呢?我也不知道。我们可以找到最小的数,然后加上这个最小的数的绝对值。这样最小的数变成0了。其他的数不就都是正的了。

 

这样,上边那个图就变成了

 

都变成正数了,就可以按照我们一开始的想法往下做了。

 

先把上边思路看懂再看代码

 

 1 /**
 2  * Note: The returned array must be malloced, assume caller calls free().
 3  */
 4 int* twoSum(int* nums, int numsSize, int target) {
 5     int i;
 6     int *re = (int *)malloc(2*sizeof(int));
 7     long long b[25536]= {0};//用作对应,类型设为longlong是为了防止数据求和之后范围超出整形表示范围。整形表示范围就是[-25536-25535]
 8                             // 比如,最小数据为-25536,最大数据是25535.求和之后就会出现25535+25536。
 9     long long m=nums[0];//m存储最小值,以便将所有的数都变成正数。m为什么也用long long呢,我们是要对m求绝对值的,如果,m=-25536,求绝对值之后就变成了了25536,超过了整型表达范围。
10     int top=-1;
11     for(i=0; i<numsSize; i++) {
12         if(nums[i]<m) {
13             m=nums[i];//用来找最小值
14         }
15         if(2*nums[i]==target) {//这这么写是因为我发现它数据有一个超过了整型表达范围,而我又无法申请那么多空间。你可以不用管。
16             re[++top]=i;
17         }
18     }
19     if(top==1) {
20         return re;
21     }
22     m = abs(m);
23     for(i=0; i<numsSize; i++) {
24         b[nums[i]+m] = i+1;//做对应,由于无法将空间批量赋值为-1,所以就批量赋值为0了,这样,我们保存位置的时候,就不能从0开始,就加一保存。
25     }
26     for(i=0; i<numsSize; i++) {
27             //往下自己看
28         if(2*(nums[i]) == target || target+m-nums[i]<= 0) {
29             continue;
30         }
31         if(b[target+m-nums[i]]!=0) {
32             re[0] = i;
33             re[1] = b[target+m-nums[i]]-1;
34             break;
35         }
36     }
37     return re;
38 }

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int cmp (const void * a, const void * b)
 5 {
 6    return ( *(int*)a - *(int*)b );
 7 }
 8 
 9 int findb(int* nums, int numsSize,int a){
10     int i;
11     for(i=0; i<numsSize; i++){
12         if(nums[i]==a){
13            break;
14         }
15     }
16     return i;
17 }
18 
19 int finde(int* nums, int numsSize,int a){
20     int i;
21     for(i=numsSize-1; i>=0; i--){
22         if(nums[i]==a){
23            break;
24         }
25     }
26     return i;
27 }
28 
29 int* twoSum(int* nums, int numsSize, int target) {
30     int *sub = (int *)malloc(numsSize*sizeof(int));
31     int i;
32     for(i=0; i<numsSize; i++){
33         sub[i]=nums[i];
34     }
35     int *re = (int *)malloc(2*sizeof(int));
36     qsort(sub, numsSize, sizeof(int), cmp);
37     int end =numsSize-1;
38     while(sub[end]+sub[0] > target){
39         end--;
40     }
41     int f, s;
42     int e;
43     for(i=0; i<end; i++){
44         for(e=end; e>i; e--){
45             if(sub[i]+sub[e]==target){
46                 f=sub[i];
47                 s=sub[e];
48                 break;
49             }
50         }
51         if(e!=i){
52             break;
53         }
54     }
55 
56     re[0]=findb(nums, numsSize,f);
57     re[1]=finde(nums, numsSize,s);
58     if(re[0]>re[1]){
59         int t=re[0];
60         re[0]=re[1];
61         re[1]=t;
62     }
63     return re;
64 }
65 
66 int main()
67 {
68     int a[]= {-1,-2,-3,-5};
69     int *r = twoSum(a, 5, 1-8);
70     printf("%d,%d", r[0], r[1]);
71     return 0;
72 }
View Code

 

posted @ 2019-03-29 23:40  nefuer  阅读(484)  评论(0编辑  收藏  举报