Day01_数组
1. 数组理论基础
地址连续,利用下标访问
访问时间
O
(
1
)
O(1)
O(1)
删除元素需要将后面的元素依次前移
O
(
n
)
O(n)
O(n)
2. 二分查找
思路:
由于数组有序,每次寻找区间中间的元素,将目标值与其做对比,即可通过大小关系将查询区间折半。
代码随想录给出了二分查找的两种写法,全闭区间和半开区间
写法一:
区间全闭
[
l
e
f
t
,
r
i
g
h
t
]
[left, right]
[left,right]
结束条件为
l
e
f
t
>
r
i
g
h
t
left > right
left>right ,因为
l
e
f
t
=
=
r
i
g
h
t
left == right
left==right 时取值有意义
区间折半时,要把中间值去掉,因为已经访问过了
class Solution {
public:
int search(vector<int>& nums, int target) {
int nums_size = nums.size();
int left = 0, right = nums_size - 1; // 右闭
while (left <= right) {
int mid = left + ((right - left) >> 1); // 防止溢出
if (nums[mid] == target) return mid;
else if (nums[mid] > target) right = mid - 1; // 找到的数字大了,在较小数字区间(左半区间)找
else left = mid + 1; // 找到的数字小了,去右半区间找
}
return -1;
}
};
写法二:
区间左闭右开
[
l
e
f
t
,
r
i
g
h
t
)
[left, right)
[left,right)
结束条件为
l
e
f
t
>
=
r
i
g
h
t
left >= right
left>=right ,因为
l
e
f
t
=
=
r
i
g
h
t
left == right
left==right 时取值已经超出了数据范围
区间折半时,要把右边界置为中间值,因为已经右边界为开区间,不会造成重复访问
class Solution {
public:
int search(vector<int>& nums, int target) {
int nums_size = nums.size();
int left = 0, right = nums_size; // 右开
while (left < right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid; // 右开
}
return -1;
}
};
3. 移除元素(双指针)
27. 移除元素
简单的小题,美妙的思想,双指针来啦!
思路:
思路一:
暴力解,删除一个元素将其后所有元素依次前移,最坏情况需要调整 n n n 次,时间复杂度 O ( n 2 ) O(n^2) O(n2)
思路二:
双指针,设置两个指针向前遍历数组,一个快指针向前遍历数组,[0, 慢指针]存放的是[0, 快指针]中删除val
之后剩余的元素。
遍历过程:
- 快指针向前移动一下,如果
nums[fast_index] == val
,需要删除该元素,则慢指针不需要动,因为需要保留的元素个数不需要扩充。- 快指针向前移动一下,如果
nums[fast_index] != val
,需要保留该元素,则慢指针向前移动一位,扩充数组空间来存放nums[fast_index]
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int nums_size = nums.size();
int fast_index = 0, slow_index = 0;
for (fast_index = 0; fast_index < nums_size; ++fast_index) {
if (nums[fast_index] != val) { // 扩充答案数组,保留该元素
nums[slow_index] = nums[fast_index];
slow_index++; // 保留新元素后,慢指针要移动到下一个空的位置,方便下次保存元素
}
}
return slow_index; // [0, slow_index)是最终的答案数组
}
};
由于slow_index++
是先运算,再自增1,所以可以将上面扩充新数组的代码部分简化
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int nums_size = nums.size();
int fast_index = 0, slow_index = 0;
for (fast_index = 0; fast_index < nums_size; ++fast_index) {
if (nums[fast_index] != val) { // 扩充答案数组,保留该元素
nums[slow_index++] = nums[fast_index];
}
}
return slow_index; // [0, slow_index)是最终的答案数组
}
};