1.两数之和--输入有序数组(三种解法)
【题目】
【分析】
由于之前的是输入无序数组,暴力法参考:打卡刷题leetcode第1天_zcyst的博客-CSDN博客
利用输入数组有序的性质,可以得到时间复杂度和空间复杂度更优的解法。
【法1 二分法+暴力法】
【代码】C
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{
int * returnNums = (int *)malloc(sizeof(int) * numbersSize);
//二分查找
//时间复杂度是 logn
//题目假设一定有结果
int i;
int indexLeft;
int indexRight ;
int indexMiddle;
int temp;
*returnSize = 2;
for(int i = 0; i < numbersSize; i++)
{
temp = target - numbers[i];
//每次都是一个二分法
indexLeft = i + 1;
indexRight = numbersSize - 1;
while(indexLeft <= indexRight)
{
indexMiddle = (indexRight - indexLeft)/2 + indexLeft;
if(numbers[indexMiddle] == temp)
{
returnNums[0] = i + 1;
returnNums[1] = indexMiddle + 1;
return returnNums;
}
if(numbers[indexMiddle] > temp)
{
indexRight = indexMiddle - 1;
}
else
{
indexLeft = indexMiddle + 1;
}
}
}
//扩展没有结果怎么处理
*returnSize = 0;
return returnNums;
}
参考的这个代码比我手敲一遍的时间短很多,咱也不知道为啥
【法2 双指针法】
【代码】C
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{
int * returnNums = (int *)malloc(sizeof(int) * numbersSize);
//指针查找
//时间复杂度是 n
//题目假设一定有结果
int indexLeft = 0;
int indexRight = numbersSize - 1;
*returnSize = 2;
while(indexLeft <= indexRight)
{
if(target == (numbers[indexLeft] + numbers[indexRight] ))
{
returnNums[0] = indexLeft + 1;
returnNums[1] = indexRight + 1;
return returnNums;
}
else if(target <= (numbers[indexLeft] + numbers[indexRight] ))
{
indexRight--;
}
else
{
indexLeft++;
}
}
//扩展没有结果怎么处理
*returnSize = 0;
return returnNums;
}
速度稍快一些
【法3 二分+双指针】
【代码】C
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{
int * returnNums = (int *)malloc(sizeof(int) * numbersSize);
//二分查找 + 双指针
//时间复杂度是 logn
//题目假设一定有结果
int i;
int indexLeft;
int indexRight ;
int indexMiddle;
int temp;
*returnSize = 2;
indexLeft = 0;
indexRight = numbersSize - 1;
while (indexLeft <= indexRight)
{
int temp = numbers[indexLeft] + numbers[indexRight];
if (temp == target)
{
break;
}
else if (temp < target)
{
indexLeft++;
}
else
{
indexRight--;
}
}
returnNums[0] = indexLeft + 1;
returnNums[1] = indexRight + 1;
*returnSize = 2;
return returnNums;
}
这个效率跟上一个差不多,大部分是双指针的思想
2.三数之和
【题目】
【分析】
【代码】C
int cmp(const void *a,const void *b)
{
return *(int*)a - *(int*)b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
{
*returnSize = 0;
if(numsSize < 3)
return NULL;
qsort(nums,numsSize,sizeof(int),cmp);//快排函数
int **ans = (int **)malloc(sizeof(int *) * numsSize *numsSize);
*returnColumnSizes = (int *)malloc(sizeof(int) * numsSize * numsSize);
int i,j,k,sum;
int indexLeft = 0;
int indexMiddle = 0;
int indexRight = 0;
//快排过后,使用三指针 遍历
//左边遍历到倒数第三位即可
for(indexLeft = 0; indexLeft< numsSize - 2; indexLeft++)
{
if(nums[indexLeft] > 0)
{
//因为是快排的结果,所以如果出现大零的
//后面的值都是大于0的
return ans;
}
//如果值相同 则不需要遍历
if(indexLeft > 0 && nums[indexLeft] == nums[indexLeft-1])
continue;
indexMiddle = indexLeft + 1;
indexRight = numsSize - 1;
//双指遍历 找到所有的可能
while(indexMiddle < indexRight)
{
sum = nums[indexLeft] + nums[indexMiddle] + nums[indexRight];
if(sum == 0)
{
ans[*returnSize] = (int*)malloc(sizeof(int)*3);
(*returnColumnSizes)[*returnSize] = 3;
ans[*returnSize][0] = nums[indexLeft];
ans[*returnSize][1] = nums[indexMiddle];
ans[*returnSize][2] = nums[indexRight];
*returnSize += 1;
//过滤相等的值
while(indexMiddle < indexRight && nums[indexMiddle] == nums[++indexMiddle]);
while(indexMiddle < indexRight && nums[indexRight] == nums[--indexRight]);
}
else if(sum > 0)
{
//左边递减
indexRight--;
}
else
{
//右边递增
indexMiddle++;
}
}
}
return ans;
}
注:qsort()函数
还有其他的比较方式(浮点型)见C语言qsort函数用法_小赵的博客-CSDN博客_qsort函数c语言
3.四数之和
【题目】
【解析】
【代码】C
int compareFunc(void* a, void* b)
{
if (*(int*)a >= *(int*)b)
{
return 1;
}
return -1;
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes)
{
//4数之和转为三数之和的问题。
//使用双指针
*returnSize = 0;
if (numsSize < 4)
return NULL;
int **returnNums = (int**)malloc(sizeof(int*) * numsSize * numsSize);
*returnColumnSizes = (int*)malloc(sizeof(int) * numsSize * numsSize);
qsort(nums, numsSize, sizeof(int), cmp);
int a , b, c, d;
long long sum;
int indexLeft = 0;
int indexRight = 0;
for (a = 0; a < numsSize - 3; a++)
{
if ((nums[a] > 0) && (nums[a] > target))
{
//剪枝 因为存在负数 会越加 越小,所以这里需要判断nums[a] > 0
//因为是快排的结果,所以如果出现大target的
//后面的值都是大于target的
break;
}
if (a > 0 && nums[a] == nums[a - 1])
{
continue; //去重
}
for (b = a + 1; b < numsSize; b++)
{
if (( b > a + 1) && (nums[b] == nums[b - 1]) )
{
continue; //去重
}
if (((nums[a] + nums[b]) > target) && (nums[b] > 0) )
{
//因为是快排的结果,所以如果出现a + b 大于零的
//后面的b值都是大于target的
//剪枝
break;
}
//双指针 移动
indexLeft = b + 1;
indexRight = numsSize - 1;
while (indexLeft < indexRight)
{
sum = (long)nums[a] + nums[b] + nums[indexLeft] + nums[indexRight];
if (sum == target)
{
//找到目标
(*returnColumnSizes)[*returnSize] = 4;
returnNums[*returnSize] = (int*)malloc(sizeof(int) * 4);
returnNums[*returnSize][0] = nums[a];
returnNums[*returnSize][1] = nums[b];
returnNums[*returnSize][2] = nums[indexLeft];
returnNums[*returnSize][3] = nums[indexRight];
*returnSize = *returnSize + 1;
//跳过相同的值
while ((indexLeft < indexRight) && nums[indexLeft] == nums[indexLeft + 1])
{
indexLeft++;
}
while ((indexLeft < indexRight) && nums[indexRight] == nums[indexRight - 1])
{
indexRight--;
}
indexLeft++;
indexRight--;
}
else if (sum < target)
{
indexLeft++;
}
else if (sum > target)
{
indexRight--;
}
}
}
}
return returnNums;
}
另一种代码,觉得写的也很好,把快排写进去了
int partition(int *nums,int low,int high){
int pivot=nums[low];
while (low<high){
while (nums[high]>=pivot&&low<high)
high--;
nums[low]=nums[high];
while (nums[low]<=pivot&&low<high)
low++;
nums[high]=nums[low];
}
nums[low]=pivot;
return low;
}
void quick_sort(int *nums,int low,int high){
int pivot;
if (low<high){
pivot=partition(nums,low,high);
quick_sort(nums,low,pivot-1);
quick_sort(nums,pivot+1,high);
}
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes){
quick_sort(nums,0,numsSize-1);
int **ans=(int **)malloc(sizeof(int *)*numsSize*6);
int key1,key2,i,j;
*returnColumnSizes =(int *)malloc(sizeof(int) *numsSize*6);
*returnSize=0;
for(key1=0;key1<numsSize;key1++){
if (key1>0&&nums[key1]==nums[key1-1])//key1去重
continue;
for(key2=key1+1;key2<numsSize;key2++){
if (key2>key1+1&&nums[key2]==nums[key2-1])//key2去重
continue;
i=key2+1;
j=numsSize-1;
while(i<j){
if(nums[key1]+nums[key2] + nums[i] + nums[j]==target){
ans[*returnSize]=(int *)malloc(sizeof(int)*4);
ans[*returnSize][0]=nums[key1];
ans[*returnSize][1]=nums[key2];
ans[*returnSize][2]=nums[i];
ans[*returnSize][3]=nums[j];
returnColumnSizes[0][*returnSize]=4;
(*returnSize)++;//*returnSize别忘了加括号
while(i<j&&nums[i]==nums[i+1])
i++;//去重
while(i<j&&nums[j]==nums[j-1])
j--;//去重
i++;
j--;
}
else if(nums[key1]+nums[key2] + nums[i] + nums[j]>target)
j--;
else
i++;
}
}
}
return ans;
}
参考:力扣