数组理论基础
数组是存放在连续内存空间上的相同类型数据的集合。
数组下标从0开始
数组内存空间的地址是连续的
c++中vector和array的区别
1、vector是顺序容器,其利用连续的内存空间来存储元素,但是其内存空间大小是能够改变的。
2、array是顺序容器,其也是利用连续的内存空间来存储元素,但它的内存空间是固定大小的,申请之后就无法改变。
3、vector的底层是array实现的
二维数组
二维数组在内存的空间地址是连续的
704|二分查找
思路
1、把整个数组一分为二;
2、判断目标值在左区间还是右区间,若在左区间,则修改右区间指针的位置;若在右区间,则修改新区间的左区间位置
3、重复上述过程,直到left>(=)right
二分查找的前提条件:
1、数组是有序数组
2、数组中无重复元素
二分法的区间定义
循环不变量规则:在二分查找的过程中,需要保持不变量,在while寻找中每一次边界的处理都要坚持根据区间的定义来操作
二分法区间定义:
1、左闭右闭【left,right】
2、左闭右开【left,right)
【left,right】
- while(left<=right),left==right是有意义的
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1,如果写middle的话,已知不是却又检查了一次
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;//区间是左闭右闭
while(left<=right){//左闭右闭,则left==right
int mid=left+((right-left)/2);
if(nums[mid]>target){//目标值在左区间,则修改右边界
right=mid-1;
}else if(nums[mid]<target){//目标值在右区间,修改左边界
left=mid+1;
}else
return mid;
}
return -1;
}
};
【left,right)
- while (left < right)
- if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle],已知不是但是也不会去检查
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;//区间是左闭右闭
while(left<right){//左闭右开,则left!=right
int mid=left+((right-left)/2);
if(nums[mid]>target){//目标值在左区间,则修改右边界
right=mid;
}else if(nums[mid]<target){//目标值在右区间,修改左边界
left=mid+1;
}else
return mid;
}
return -1;
}
};
35|搜索插入位置
二分法可以查找数组内外的元素
思路
在于分清target可能位置的几种情况
1、 目标值在数组所有元素之前 [0, -1]
2、目标值等于数组中某一个元素 return middle;
3、目标值插入数组中的位置 [left, right],return right + 1
4、目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return right + 1
左闭右闭条件下,情况1、3、4返回的位置都是right+1
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n - 1; // 定义target在左闭右闭的区间里,[left, right]
while (left <= right) { // 当left==right,区间[left, right]依然有效
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,所以[middle + 1, right]
} else { // nums[middle] == target
return middle;
}
}
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0, -1]
// 目标值等于数组中某一个元素 return middle;
// 目标值插入数组中的位置 [left, right],return right + 1
// 目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return right + 1
return right + 1;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
二分法寻找目标值所在的区间
思路
1、分开寻找左右边界
2、分开情况处理
情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
如果左右边界全部被移动了;说明目标值在数组里
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 情况一
if (leftBorder == -2 || rightBorder == -2) return {-1, -1};
// 情况三
if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1};
// 情况二
return {-1, -1};
}
private:
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
}
return leftBorder;
}
};
27. 移除元素
通过一个快指针和慢指针在一个 for 循环下完成两个 for 循环工作
快指针可以理解成在旧数组中找非目标元素,然后赋值给慢指针指向的新数组,虽然都指向一个数组
定义快慢指针
- 快指针:寻找新数组的元素,新数组就是不包含要删除元素的数组
- 慢指针:更新新数组
思路
-
快指针移动,如果不是目标元素,快指针指向就赋值给慢指针指向,慢指针移动
-
如果是目标元素,则慢指针不操作,快指针继续移动。文章来源:https://www.toymoban.com/news/detail-454362.html
-
慢指针最后指向的下标,就是新数组中的大小文章来源地址https://www.toymoban.com/news/detail-454362.html
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
到了这里,关于day1-数组part01| 704. 二分查找、27. 移除元素的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!