zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    灰姑娘的水晶鞋(NOIP模拟赛Round 7)
    小红帽的画笔(NOIP模拟赛Round 7)
    YYH的球盒游戏(NOIP模拟赛Round 6)
    YYH的营救计划(NOIP模拟赛Round 6)
    imrersize函数
    数字图像基础知识之灰度图像,彩色图像和矩阵
    灰度变换之彩色变灰色
    数字图像基础知识
    灰度变换之灰度线性拉伸(算法1)
    C结构体变量2种运算(比如链表的结点)(区别与java)
  • 原文地址:https://www.cnblogs.com/zhishoumuguinian/p/10624867.html
Copyright © 2011-2022 走看看