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;
}