代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素
一、数组理论基础
Tips:
- 数组是存放在连续内存空间上的相同类型数据的集合
- 没有方括号和下标的数组名称实际上代表数组的起始地址,这意味着数组名称实际上就是一个指针
- 由于数组的内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址,且数组的元素不能删除只能覆盖。
- C++中二维数组在地址空间上是连续的
二、704 二分查找
二分查找一个最重要的前提是有序数组、无重复元素。我的理解是对于有序数组容易采用判断语句不断缩小查找范围,而无重复元素则是容易判断是否相等确定对于元素。
如果题目改成存在重复元素,是否可以通过二分查找找到对应目标的第一个元素?
// 左闭右闭,边界的值已经判断过了,应该左移或者右移一位判断
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right){
int middle = left + (right - left) / 2;
if(nums[middle] < target)
left = middle + 1;
else if(nums[middle] > target)
right = middle - 1;
else
return middle;
}
return -1;
}
};
// 左闭右开,左边界的值已经判断过了,右移一位判断;右边界的值是开的,应当继续保持它开着;
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while(left < right){
int middle = left + (right - left) / 2;
if(nums[middle] < target)
left = middle + 1;
else if(nums[middle] > target)
right = middle;
else
return middle;
}
return -1;
}
};
总结:
重要的是对于边界的判断和处理,对于边界的处理应该让最开始定义的区间保持一致。其次是对不同情况下的边界应该怎么处理继续练习和考虑。
相关题
35.搜索插入位置
题目链接
该题相比于二分查找的难点在于添加了一个对于循环结束边界位置的判断,当设置**[left,right)时,循环的判断条件时left < right**,则循环结束是一定是left = right,则上一次循环时一定是left = middle = right - 1,则最后插入的位置为left;当设置[left,right]时,循环结束时,left = right +1,插入位置仍然时left;
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right){
int middle = left + ((right - left) / 2);
if(nums[middle] < target)
left = middle + 1;
else if(nums[middle] > target)
right = middle - 1;
else
return middle;
}
return left;
}
};
三、 27 移除元素
题目链接
由于对于数组的操作只能覆盖,不能删除。因此在删除元素的时候,就要移动其他元素的位置。
// 暴力解法,找到一个val就将后面的值前移覆盖一次
// 需要注意删除一位元素,对于循环的数组长度就要减少一位!
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int i = 0;
while(i < n){
if(nums[i] == val){
for(int j = i+1; j < n; j++){
nums[j-1] = nums[j];
}
n--;
}
else
i++;
}
return n;
}
};
快慢指针:
// 快指针用于查找元素,慢指针对元素进行处理
// 在一定条件下其实数组就相当于指针,则该解法相当于遍历目标数组将符合条件的数组保存到“另外一个数组”里,只不过是“另外一个数组”的储存空间和目标数组的储存空间起始位置相同。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.size(); fastIndex++){
if(nums[fastIndex] != val){
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
四、总结
第一次写博客,有些想法还是不能只在脑海里想,必须把它理顺转化为文字才能进一步理解掌握,每天写文字的习惯必须保持下去,包括做科研也是。虽然这些题目之前做过一遍,但是理解仍然不透彻,需要进一步深化。今天时间有点赶,额外题目周末补充进去。