leetcode 1. 两数之和(暴力解法,二分优化,双指针)

LeetCode 1. 两数之和(C语言,三种解法)

题目链接:leetcode 1. 两数之和
题目描述:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

1.暴力解法:(穷举)

int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int i=0,j=0;
    int *ans=(int*)malloc(sizeof(int)*2);
    for(i=0;i<numsSize-1;i++)
    for(j=i+1;j<numsSize;j++)
    {
        if(nums[i]+nums[j]==target)
        {
            ans[0]=i;
            ans[1]=j;
            *returnSize=2;
            return ans;
        }
    }
    return 0;
}

思路:

穷举所有可能判断是否满足最后的条件:

for(i=0;i<numsSize-1;i++)
for(j=i+1;j<numsSize;j++)  j只要从i的后一位到最后就行并不用从0开始

有两个需要注意的地方:
1.最后一定要有return 0;防止nums为空的情况。(即输入为空)
2.这里返回的是一个指针,所以不能在函数里面直接

int  ans[2];

如果用这样定义的ans数组来储存结果的话,那么并不能得到预期的结果,因为在此函数结束后,返回的指针所指向的内存(即ans数组)已经被释放掉了。 文章最后有对这里的更详细的解释。
对于函数返回的是指针,我们可以用两种方式来定义 ans:

1.static int ans[2];
2.int *ans=(int*)malloc(sizeof(int)*2);

2.qsort函数(快速排序)+ 二分优化

简单的一道题,相对于暴力解法,这么长的代码可能会显得大材小用,但是这也是一种降低时间复杂度的思路。

typedef struct node    //定义结构体
 {
     int pos;
     int data;
 }strnode;
 int cmp(strnode*a,strnode*b)    //qsort函数需要的比较函数
 {
     return a->data-b->data;
 }
 int erfen(strnode* node,int left,int right,int key)   //二分查找
 {
     while(left<=right)
     {
         int mid=left+(right-left)/2;
         if(key==node[mid].data)
         return node[mid].pos;
         else
         {
             if(key>node[mid].data)
             left=mid+1;
             else
             right=mid-1;
         }
     }
     return -1;
 }
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    if(nums==NULL)
    return 0;
    int i=0,j=0;
    strnode *x=(strnode*)malloc(sizeof(strnode)*numsSize);
    int *ans=(int *)malloc(sizeof(int)*2);
    for(i=0;i<numsSize;i++){
        x[i].data=nums[i];
        x[i].pos=i;
    }
    qsort(x,numsSize,sizeof(strnode),cmp);  //stdio.h中的qsort函数
    for(i=0;i<numsSize-1;i++){
        ans[0]=x[i].pos;
        *returnSize=2;
        if(erfen(x,i+1,numsSize-1,target-x[i].data)!=-1){
        ans[1]=erfen(x,i+1,numsSize-1,target-x[i].data);
        break;}
    }
    free(x);
    return ans;
}


二分优化的思路:

for(i=0;i<numsSize-1;i++)

在暴力穷举的前提下进行改进,我们不妨假设穷举只先进行到这一步,即穷举第一个数,然后二分优化的思路是把穷举第二个数通过二分查找的方式找出来,这样的时间复杂度将被降低。

在这道题,在用二分优化的前提是数据要有序,那么就设计排序,在这么多排序算法中,如果我们选择时间复杂度为O(n2)的排序算法,那么二分优化就没什么意义了,因为暴力算法的时间复杂度也是O(n2),那么要优化算法,即必须用小于O(n2)的排序算法,我就选择用快速排序。
可以选择自己编写一个快速排序函数,或者是用C语言stdio.h库里面的qsort函数。

3.qsort函数+双指针

typedef struct node
 {
     int pos;
     int data;
 }strnode;
 int cmp(strnode*a,strnode*b)
 {
     return a->data-b->data;
 }
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    if(nums==NULL)
    return 0;
    int i=0,j=0;
    strnode *x=(strnode*)malloc(sizeof(strnode)*numsSize);
    int *ans=(int *)malloc(sizeof(int)*2);
    for(i=0;i<numsSize;i++)
    {
        x[i].data=nums[i];
        x[i].pos=i;
    }
    qsort(x,numsSize,sizeof(strnode),cmp);
    i=0;
    j=numsSize-1;
    while(i<j)
    {
        if(x[i].data+x[j].data<target)
        i++;
        else
        if(x[i].data+x[j].data>target)
        j--;
        else
        {
            ans[0]=x[i].pos;
            ans[1]=x[j].pos;
            *returnSize=2;
            break;
        }
    }
    free(x);
    return ans;
}


相对于二分优化,双指针的思路更加简单。
设置双指针,这里的指针并不等同于C语言中的指针。
定义两个变量i,j,分别从有序数组的两端向中间逼近,假定数据是从小到大排列。

//假设数组是从小到大排列的
if(两数之和>target(目标值))
j--;
if(两数之和<target)
i++;
if(两数之和==target)
{记录结果;}

—————————————————————————————————————————————————
以下内容转载于:C语言、内存管理、堆、栈、动态分配
C语言函数返回值实现机制
我们知道,在子函数中返回局部变量的值是不会出什么问题的,但是,返回一个局部变量的指针或者引用时,在后续解引用这个指针时就得不到理想的结果,原因在于:子函数中的自动变量(栈内存中的变量)会在子函数返回后被释放掉,但是返回值会被保存在cpu的寄存器中,因此,在返回子函数后,返回值能从寄存器中将返回值赋值给调用函数中的变量,如果返回值是一个指针,那么该指针所指的内存地址会被保存在寄存器中,但是,指针指向的内存却被释放掉了(即值未定义)。因此,在编写代码时一般不会返回指向局部变量的指针,除非一下三种情况:

1)子函数中定义了静态局部变量,函数可以返回指向该静态局部变量的指针。因为该变量分布在内存的静态区(在函数编译时就将被初始化),所以在子函数返回时该变量仍然存在。

char * func1()
{
    static char name[]="Jack";
    return nema;
}

这里“Jack”存储在只读存储区,不能更改,将其赋值给name数组,即复制到静态存储区,因此name中保存的字符串不是常量字符串,可以通过数组下表进行更改。

2)子函数返回一个常量的指针,比如字符串常量,整形常量等。因为常量是定义在只读存储区,所以该常量也不会在子函数返回时被释放。

char * func2()
{
    char *name="Jack";
    return nema;
}

3)子函数返回一个指向动态分配内存的指针。动态内存是在堆内存中分配的,需要程序员手动释放,否则造成内存泄漏,所以在手动释放该指针之前都可以返回该指针。

char * func3()
{
    char *name = (char *)malloc(20);
    return nema;
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值