数组基础理论
数组是存放在连续内存空间上的相同类型数据的集合。
数组下标都是从0开始的。
数组内存空间的地址是连续的
正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。
数组的元素是不能删的,只能覆盖。
所以可以看出在C++中二维数组在地址空间上是连续的。
704. 二分查找
力扣题目链接(opens new window)
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
对于左闭右闭即[left, right]的写法,需要考虑左右都是可以获取的情况
对于二分法这里while(left<=right)是有效的,因为可以取到right的值,所以left==right是有意义的
对于if (nums[middle] > target) 因为对于中间值,已经大于目标值了,所以对于middle不需要取了,直接更新right=middle-1就可以了。
c语言写法如下:
int search(int* nums, int numsSize, int target){
int l = 0; //左区间从0开始
int r = numsSize -1;//因为数组是从0开始的,所以最右边的值是长度-1
while(l <= r) //进行判断 当l 小于r的时候一直循环,且还会有l=r的情况
{
int mid = (l+r)/2;//更新中间值
if(nums[mid] > target) //比目标值大更新r
{
r = mid - 1;
}
else if(nums[mid] < target)//比目标值小更新l
{
l = mid + 1;
}
else
{
return mid; //如果不属于上述两种情况就是找到目标值,之间返回下表mid
}
}
return -1;//当上述循环退出还没找到则返回-1
}
闭右开即[left, right)
这种写法就是不取最右边的值,直接选取长度就可以了,对于左边写法同上,但是对于右边的话,因为最右边的值是不可选取的。
int search(int* nums, int numsSize, int target){
int l = 0; //左边值
int r = numsSize ; //因为数组是从0开始的,所以长度的位置是不可选取的
while(l < r) //所以这里的话l是不能等于r的
{
//int mid = (l+r)/2;//这里对于直接l+r的话可能会存在大于int范围出现溢出,所以改为下面的最好
int mid = l +( (r - l)/2);//这里经过简单的数学运算,l+(r/2-l/2)=r/2+l/2=(r+l)/2,但是这样的话就很好的避免了溢出,没有l+r。
if(nums[mid] > target) //对于
{
r = mid ;
}
else if(nums[mid] < target)
{
l = mid +1;
}
else
{
return mid;
}
}
return -1;
}
27. 移除元素
力扣题目链接
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
双指针法
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
主要就是两个指针,快指针进行判断,慢指针存储元素
int removeElement(int* nums, int numsSize, int val){
int q = 0, p = 0;
for(p; p < numsSize; p++)
{
if(nums[p] != val)
{
nums[q] = nums[p];
q++;
}
}
return q;
}
上述代码例子讲解:
对于数组nums[4]={3 2 2 3} val =3
最开始定义q和p都为0指向位置 q[0] = p[0] = 3
下面开始进入for循环,for循环中只有一个判断p【0】不等于val,这里p的值等于val,所以p向前移动,q不动,因为q的位置需要用不等于val的值来覆盖,当p【1】的时候,p【1】等于2不等于val的时候,这时候q就需要移动了,用p的值来更新q的值,同时q往后移动等待下一次更新。