时间复杂度
O是什么:大O用来表示上界的,当用它作为算法的最坏情况运行时间的上界,就是对任意数据输入的运行时间的上界。
数组
数组是存放在连续内存空间上的相同类型数据的集合。正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。
使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。
数组的元素是不能删的,只能覆盖。
二分查找
满足有序就可想到二分
题目:
![](https://img-blog.csdnimg.cn/img_convert/2ffeee94226152f7b0b0aa7306df0402.png)
到底是 while(left < right) 还是 while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?
写二分法,区间的定义一般为两种,左闭右闭即[left, right](主要),或者左闭右开即[left, right)。
while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
Leecode出错
![](https://img-blog.csdnimg.cn/img_convert/41cb31847fcec48ffd8bab3cc8835f4b.png)
AddressSanitizer 被用来检查内存的非法访问,在 leetcode 中出现 AddressSanitizer: heap-buffer-overflow on address 类似报错,主要原因可能是存在数组越界。
移除元素
![](https://img-blog.csdnimg.cn/img_convert/a408bd0b08b9a7c277731ce758c0cfcd.png)
这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
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--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
size--; // 此时数组的大小-1
}
}
return size;
}
};
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {//快指针有序递增,与此同时若val与快指针的内容不同时(及不用删除时),慢指针也在有序递增,且指向同一位置,覆盖语句不起作用,当val与快指针相同时快指针增加,慢指针不变,产生错位,下次循环时,覆盖语句起作用。
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};