🌵数组中的重复元素
🌵思路一:遍历数组 时间复杂度O(N^2)
相信大家看到这一道题目的第一个思路就是进行数组遍历,只要我们将每一个数据都挨个和数组中的元素进行比较,那么要是有相同的数据就一定能比较出来并返回。但是我们会发现这样的算法执行的效率很低,时间复杂度为O(N^2)。所以我们得想办法优化我们的代码,毕竟n^2的代码并不是那么容易让人接受。
🌵思路二:向前查找 时间复杂度O(N^2)
之后我想到的是将我们的数据一个个拿下来放到一个新的数组当中,再将要像数组当中放数据的时候向已经放入数据的数组进行检查,如果存在相同的数据就直接返回。 但是我们会发现我们数据的总检查的次数为1+2+...+(n-1)+n我们的时间复杂度还是O(N^2),我们所进行的效果很小,算法的时间复杂度还是属于N^2级别的,所以我们还需要思考其他的方法。
🌵思路三:构建“哈希表” 时间复杂度O(N)
大家看到这个思路标题的时候不要紧张,我们这里的构建哈希表仅仅是一个和哈希表很类似的思路。我们仅仅是创建一个数组,之后将我们的数据“挂到”数组的指定位置而已。
对于上面数据的检测我们只需要将数组当中的数据全部初始化为0,之后第一次向其中挂入数据的时候将相应位置的数据更改为1,第二次想要挂入数据的时候就将目标数据返回即可。我们根据上述思路编写出来的代码如下:
int findRepeatNumber(int* nums, int numsSize)
{
//开辟一个大小为numsSize的数组
int *ret=(int*)calloc(numsSize,sizeof(int));
if(ret==NULL)
{
perror("malloc fail");
return 0;
}
int i=0;
for(i=0;i<numsSize;i++)
{
if(ret[nums[i]]!=0)
{
free(ret);
return nums[i];
}
else
{
ret[nums[i]]++;
}
}
return 0;
}
运行效果:
我们可以分析一下上面思路的时间复杂度:我们总共就是开辟了一个数组,进行了一次数组遍历,所以我们的时间复杂度为O(N),相比于N^2的算法来说,这算是一个质的飞跃了。
🌵 二维数组中的查找
🌵思路一:遍历数组 时间复杂度O(N*M)
同样的看到这道题之后我们的第一个思路肯定也是遍历整个数组,进而查找指定的元素。但是我们从时间复杂度的角度进行分析存在两个数组。第一个数组当中放置的是一系列的数组首地址,第二个数组当中存储的是每一个数组当中的元素个数。所以我们总的时间复杂度为O(N*M)也就是对数组当中的全部的元素进行遍历。假如是针对于无序的数组来说这个算法或许来说已经足够好了,但是我们本题目中给的是有序的二维数组。所以我们就可以对于我们的数组查找进行优化,得出更优的结果。
🌵思路二:二分查找法 时间复杂度O(N*logM)
仔细阅读题目要求我们可以得出在每一个单独的数组当中我们的数据都是有序的。所以对于单独的数组来说我们就可以使用二分查找对我们的代码进行优化。使用二分查找之后我们对于数组当中的数据查找操作时间复杂度就变为logM。再加上我们一共有N行,所以我们该算法的时间复杂度为O(N*logM)。
实现二分查找思路的代码:
//二分查找代码
bool BinarySearch(int *arr,int size,int target)
{
int left=0;
int right=size-1;
while(left<=right)
{
int mid=left+(right-left)/2;
//数据属于右边
if(arr[mid]<target)
{
left=mid+1;
}
//数据属于左边
else if(arr[mid]>target)
{
right=mid-1;
}
else{
return true;
}
}
return false;
}
bool findNumberIn2DArray(int** matrix, int matrixSize, int* matrixColSize, int target){
//一个O(N)的算法
int i=0;
for(i=0;i<matrixSize;i++)
{
bool ret=BinarySearch(matrix[i],matrixColSize[i],target);
if(ret)
{
return true;
}
}
return false;
}
运行效果如下:
🌵行列递减法 时间复杂度O(N+M)
为了优化我们的程序,我们在这里向大家介绍一个方法:对于有序的二维数组我们可以将右上角的元素作为标记元素,将我们目标元素和他作比较,如果右上角的元素小于我们的目标元素就可以删除一行的元素,(右上角的元素是本行最大的元素)。如果右上角的元素大于我们的目标元素就可以删除一列的元素,(右上角的元素是本列最小的元素)。我们按照这个思路依次进行比较,假如我们元素不存在的时候需要比较的次数最多,最多也只是我们行数加上列数。所以我们按照此思路优化代码后的时间复杂度为O(N+M)。
按照上面的思路我们可以编写如下的代码:
bool findNumberIn2DArray(int** matrix, int matrixSize, int* matrixColSize, int target){
//将我们要查找的数据和右上角的数据进行比较,
//每次删除一行或者一列的数据,直到找到指定的数据
if(matrixSize==0||matrixColSize[0]==0)
{
return false;
}
int i=0;
int j=matrixColSize[i]-1;
while(i<matrixSize&&j>=0)
{
//如果target比右上角的数据大那么删除一行的数据
if(target>matrix[i][j])
{
i++;
}
//如果target比右上角的数据小那么删除一列的数据
else if(target<matrix[i][j])
{
j--;
}
else{
return true;
}
}
return false;
}
运行效果如下: