一、704 二分查找
定义:
折半查找也称二分查找,是一种高效的查找算法.但折半查找要求有数据必须采用顺序存储(顺序表或数组,不能使用链表),表中数据必须有序(假设递增有序)。
算法:
需要和中间的数(middle)作对比,如果目标数值(target)小于中间值,则将在中间值的左边范围进行查找,如果目标数值大于中间值,则将在中间值得右边范围进行查找,重复操作,直到目标值等于中间值即为查找成功,若没有找到则查找失败。
题目:
代码:
int search(int* nums, int numsSize, int target) {
//采用左闭右闭区间
int left = 0;
int right = numsSize - 1;
while (left <= right)
{
int middle = (left + right) / 2;
if (nums[middle] > target)
right = middle - 1;
else if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] == target)
return middle;
}
return -1;
//采用左闭右开区间
int left = 0;
int right = numsSize;
while (left < right)
{
int middle = (left + right) / 2;
if (nums[middle] > target)
right = middle;
else if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] == target)
return middle;
}
return -1;
}
代码理解(细节):
在这里,我使用了两种方法来完成二分查找,一个是左闭右闭,即[ ],另一个是左闭右开,即[ )。
两种方法的区别在于边界不同,这也导致了两种代码对于边界的处理不一样。
左闭右闭区间 | 原因 | 左闭右开区间 | 原因 | |
right的取值 | middle-1 | middle | ||
left</<=right | <= | 是出于合法区间内 | < | 右值不能取 |
更新right值 | right=middle-1 | middle已经判断过,不需要在判断 | right=middle | 右值不能取,所以middle还没判断 |
二、27 移除元素
题目:
代码:
int removeElement(int* nums, int numsSize, int val) {
//暴力解法(双循环)
int size = numsSize;
for (int i = 0; i < size; i++)
{
if (nums[i] == val)
{
for (int j = i + 1; j < size; j++)
{
nums[j - 1] = nums[j];
}
i--;
size--;
}
}
return size;
//双指针(一个循环)
int fast;//快指针
int slow=0;//慢指针
for(fast=0;fast<numsSize;fast++)
{
if(nums[fast]!=val)
{
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}
代码理解(细节):
在这个,我使用了两种解法。
第一种是暴力法,它是通过双层循环实现。在第一层循环遍历数组时,如果出现等于val的情况,那么,第二层循环将把val的后一个数赋值到当前位置,即覆盖掉val。
第二种方法是双指针,它则是通过在一层循环内的两个指针实现。第一个指针为快指针,第二个指针慢指针。两个指针一起出发,当遇到val时,慢指针不懂,快指针向后移动,然后将非val的值赋值给慢指针所在位置,实现覆盖(删除)val的操作。
三、997 有序数组的平方
题目:
代码:
int* sortedSquares(int* nums, int numsSize, int* returnSize) {
*returnSize = numsSize;
int left = 0;
int right = numsSize -1;
int *ans = (int *)malloc(sizeof(int)*numsSize);
int k = numsSize-1;
for(int i =0 ,j=numsSize-1;i<=j;)
{
if(nums[i]*nums[i]>nums[j]*nums[j])
{
ans[k] = nums[i]*nums[i];
k--;
i++;
}
else{
ans[k] = nums[j]*nums[j];
k--;
j--;
}
}
return ans;
}
代码理解(细节):
关于这道题,小编主要学习了两种思路,一种是暴力法,一种是双指针解法。
首先,我来简单说一下暴力解法,首先将数组内的所有数字直接平方,然后利用快速排序的方法变成递增数组,这种方法的时间复杂度取决于快速排序的时间复杂度,为O(nlogn)。
因此,我又学习了第二种方法,也就是代码所展示的方法,双指针解法。这个方法是采用两个指针指向原数组,一个指针在最前,一个指针在最后(因为不管数组内是否有负数,平方后的最大值一定都在两边,不可能在最中间)。通过比较两个指针指向数字平方后的结果,哪个指针指向的数字平方大,就把该指针指向的数字平方存入新数组,并且该指针进行移动(若为前指针则向后移动,若为后指针则向前移动)。在这里,我们要注意,为了保证新数组是递增数组,我们要把数字从后向前保存,即k=numsSize - 1;和k--;这样就保证了每来一个新平方数都是放在后面的。
【小编有话说】
欢迎来到小编新开的栏目~
可能会有朋友觉得这个第一篇文章为什么感觉水水的,其实它不水,只是小编是在第二天的时候进的训练营,本身已经落了一天,小编还不远放弃这篇文章以及天数,只好浓缩一下了。但是,浓缩的都是精华(觉得不是也请口下留情)。
有种计划赶不上变化的感觉,前两天小编还在思考新增数据结构或者C++,今天就新开了一个意想不到的栏目!但是,小编的目标始终不变,那就是和大家一起学习,一起进步!!!