Day1 704. 二分查找,27. 移除元素
今日学习时长:3h
数组理论知识
vector是容器,不是数组
cpp在二维数组的地址空间上是连续的
java不对程序员暴露元素的地址,寻址操作完全交给虚拟机,所以看不到每个元素的地址情况
704 二分查找
vector的片段截取
初始化创建
vector<int>::const_iterator beg = nums.begin();
vector<int>::const_iterator mid = nums.begin() + nums.size()/2;
vector<int>::const_iterator end = nums.end();
std::vector<int> left(beg, mid);
std::vector<int> right(mid, end);
void assign(const_iterator first,const_iterator last); //两个指针,分别指向开始和结束的地方
思路
递归(最初的构思)
先和middle比较,然后再递归查找
class Solution {
public:
int search(vector<int>& nums, int target) {
if(nums.size() <= 0) return -1;
if(nums.size() == 1){
return nums[0] == target? 0 : -1;
}
for(auto& item: nums){
cout << item << ' ';
}
cout << endl;
vector<int>::const_iterator beg = nums.begin();
vector<int>::const_iterator mid = nums.begin() + nums.size()/2;
vector<int>::const_iterator end = nums.end();
std::vector<int> left(beg, mid);
std::vector<int> right(mid, end);
if(*(mid) == target){
return nums.size()/2;
}else if(*(mid) > target){
return search(left, target);
}else{
int rightRet = search(right, target);
if(rightRet == -1){
return -1;
}else{
return nums.size()/2 + rightRet;
}
}
}
};
不要用递归,看清题目是否有重复元素,是否是已经排过序的数组
左闭右闭的区间
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
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(target == nums[middle]){
return middle;
}else if(target < nums[middle]){
right = middle - 1;
}else{
left = middle + 1;
}
}
return -1;
}
};
左闭右开的区间
- while (left < right),这里使用 < ,因为left == right在区间[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;
int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
int middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle; // target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,在[middle + 1, right)中
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
// 未找到目标值
return -1;
}
};
27 移出元素
初始解法
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int count = 0;
int len = nums.size();
for(int i = 0; i < len - count; i++){
if(nums[i] == val){
while(nums[len - 1 - count] == val){
count ++;
if(len - 1 - count < 0) return 0; //[1], val = 5
}
if(i >= len - count) break;//[4, 5], val = 5
int tmp = nums[len - 1 - count];
nums[i] = tmp;
nums[len - 1 - count ] = val;
count ++;
}
}
return nums.size() - count ;
}
};
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
双指针解法
// 时间复杂度: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++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};