文章链接:
数组理论基础
数组是存放在连续内存空间上的相同类型的数据的集合;
数组下标都是从0开始的;
数组内存空间的地址是连续的;
数组的元素是不能删除的,只能覆盖;
704.二分查找
使用条件:数组为有序数组,且无重复元素
需要考虑:1、左闭右闭还是左闭右开;2、循环时,是小于还是小于等于;3、right等于middle还是等于middle-1
写二分法,区间的定义一般分为两种,左闭右闭即[left,right](一般用这种多一些),左闭右开[left,right)
第一种:
·while(left<=right)要用<=,因为left==right是有意义的([1,1]是合法的,左右可以相等)
·if(nums[middle]>targrt),right要赋值给middle-1,因为当前这个nums[middle]一定不是target
//left=0; right=size-1;while循环,取等于号时[left,right]区间是有意义的,
//比较时,nums[middle]已经比较过了
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1;
while(left<=right){
int middle = left + ((right-left)/2);
if(nums[middle]>target){
right = middle-1; //targt在左区间
}else if(nums[middle]<target){
left = middle+1; //targt在右区间
}else{
return middle;
}
}
return -1;
}
};
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
第二种:
·while(left<right)要用<,因为left==right是没有意义的([1,1)是不合法的,所以相等没有意义)
·if(nums[middle]>targrt),right要赋值给middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while(left<right){
int middle = left + ((right-left)/2);
if(nums[middle]>target){
right = middle; //targt在左区间,在[left,right)中
}else if(nums[middle]<target){
left = middle+1; //targt在右区间,在[middle+1,right)中
}else{
return middle;
}
}
return -1;
}
};
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
27.移除元素
暴力解法
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
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;
}
};
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
双指针法:
快指针:寻找新数组的元素
慢指针:更新新数组
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow_index = 0;
int fast_index = 0;
for(fast_index;fast_index<nums.size();fast_index++){
if(nums[fast_index]!=val){
nums[slow_index]=nums[fast_index];
slow_index++;
}
}
return slow_index;
}
};
- 注意这些实现方法并没有改变元素的相对位置
- 时间复杂度:O(n)
- 空间复杂度:O(1)