今日任务:数组理论基础,704.二分查找,27.移除元素
卡哥建议:(1)了解一下数组基础,以及数组的内存空间地址,数组也没那么简单。
(2)把 704 掌握就可以,35.搜索插入位置 和 34. 在排序数组中查找元素的第一个和最后一个位置.
重点:要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。
链接:代码随想录:代码随想录 (programmercarl.com)
补充:35搜索插入位置;34在排序数组中查找元素的第一个和最后一个位置;69.X的平方根;367.有效的完全平方数
数理论基础组
1.数组是存放在连续内存空间上的相同类型数据的集合。
2.数组下标都是从0开始的。
3.数组的内存空间的地址是连续的。
注意事项:因为数组的内存空间地址是连续的,所以我们在删除或者增添元素时,就难免需要移动其他元素的地址。(因此数组的元素不能删除,只能覆盖。)
int arr[2][3] =
{
{0,1,2},
{3,4,5}
};
cout << &arr[0][0] << " " << &arr[0][1] << " "
<< &arr[0][2] << " " << &arr[1][0] << " "
<< &arr[1][1] << " " << &arr[1][2] << " "
<< endl;
地址一般为16进制且连续;A代表10,"ABCDEF0123456789"类推.
704.二分查找
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章链接:代码随想录
视频链接:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili
第一想法第一次写:只想着遍历,没有时间概念,就遍历返回了;
划重点:有序数组--无重复元素--使用二分法
注意:边界条件确定好;[left,right]和[left,right)
class Solution {
public:
int search(vector<int>& nums, int target) {
//设置区间;
int left=0;
int right=nums.size()-1;
//进行二分法算法设计
while(left<=right)
{
//设置二分中间值,注意防溢出;int向下取整
int middle=left+(right-left)/2;
//条件判断--三种情况
//target>middle,上半区间,左边界变化
if(target>nums[middle])
{
left=middle+1;//已经大于了,所以+1;
}
//target<middle,下半区间,右边界变化
else if(target<nums[middle])
{
right=middle-1;
}
//最后就剩相等了
else
{
return middle;
}
}
//如若都不符合,返回-1
return -1;
}
};
第二种写法为边界[left,right)
class Solution {
public:
int search(vector<int>& nums, int target) {
//设置区间;
int left=0;
//注意不能-1;否则少了数组最后一个元素
int right=nums.size();
//进行二分法算法设计
while(left<right)
{
//设置二分中间值,注意防溢出;int向下取整
int middle=left+(right-left)/2;
//条件判断--三种情况
//target>middle,上半区间,左边界变化
if(target>nums[middle])
{
left=middle+1;//已经大于了,所以+1;
}
//target<middle,下半区间,右边界变化
else if(target<nums[middle])
{
right=middle;
}
//最后就剩相等了
else
{
return middle;
}
}
//如若都不符合,返回-1
return -1;
}
};
相关题目:35搜索插入位置;34在排序数组中查找元素的第一个和最后一个位置;69.X的平方根;367.有效的完全平方数
27.移除元素
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章讲解:代码随想录
视频链接:数组中移除元素并不容易! | LeetCode:27. 移除元素_哔哩哔哩_bilibili
注意:要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
此为暴力解法
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//设置数组大小
int size=nums.size();
//遍历数组删除数值val
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;
}
};
while与if区别:
while语句属于循环语句,在判断是,如果条件为true,则会继续判断,直到false为止,即会进行多次判断(除非一开始条件就是错的)
if语句属于条件判断语句,如果条件是true,则继续执行,为false则跳出语句不执行,只会进行单次判断。
while与if语句的最大的相同点是都有至少一步的判断。
最大的不同点是:IF语句运行完毕后,接着运行下面的语句。而While中的执行语句运行完毕后,还要进行继续判断条件是否符合循环条件,根据判断的条件,返回执行语句或继续运行下面的程序。
双指针法
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
- 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
- 慢指针:指向更新新数组下标的位置
其实就是用一个快指针遍历整个数组,当找到需要的数值时,慢指针操作(此题就是慢指针重写数组)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//设置数组大小
int slowIndex=0;
//设置快慢指针在一个for循环里面完成移除元素
for(int fastIndex=0;fastIndex<nums.size();fastIndex++)
{
if(nums[fastIndex]!=val)
{
nums[slowIndex]=nums[fastIndex];
slowIndex++;
//nums[slowIndex++]=nums[fastIndex];慢指针更新在加1(也就是数组的长度)
//快指针遍历,相当于旧数组重新写一遍,=val的不要就好了。
}
}
return slowIndex;
}
};
相向双向指针法
相当于一边从头出发找到不一样的就前进,找到一样的停下替换从后面找到的不一样的,疑惑的是,最后面的一样的咋办,就消失了,确实是有这样,因为左右一起走,这样的话右边不一样的就换全部换到左边,而一样的就被抛弃了,注意要left<=right;这样就全了
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//相向双指针法
//相当于一边从头出发找到不一样的就前进,找到一样的停下替换从后面找到的不一样的
//疑惑的是,最后面的一样的咋办,就消失了
//确实是有这样,因为左右一起走,这样的话右边不一样的就换全部换到左边,
//而一样的就被抛弃了,注意要left<=right;这样就全了
//相向双指针建立
int leftIndex=0;
int rightIndex=nums.size()-1;
//建立循环条件
while(leftIndex<=rightIndex)
{
//左边一直前进,寻找等于val的值
while(leftIndex<=rightIndex && nums[leftIndex]!=val)
{
leftIndex++;
}
//右边寻找不等于val的值,
while(leftIndex<=rightIndex && nums[rightIndex]==val)
{
rightIndex--;
}
//替换---需要添加if(leftIndex < rightIndex),防止=时,最后一个元素重复
//因为=时仍会执行,这样leftIndex就会多加一位(此时leftIndex > rightIndex),等于rightIndex或 rightIndex--的值,这样就会多算一步
if(leftIndex<rightIndex)
{
nums[leftIndex]=nums[rightIndex];
leftIndex++;
rightIndex--;
}
}
return leftIndex;
}
};
相关题目:26.删除排序数组中的重复项;283.移动零;844.比较含退格的字符串;977.有序数组的平方