代码随想录算法训练营第1天 | 704.二分查找、27.移除元素、977.有序数组的平方
文章目录
704.二分查找
解题思路
该题的前提的是数组为有序数组,同时数组中无重复元素,一旦有重复元素,那么使用二分法返回的元素下标可能不是唯一的。以上条件是使用二分法的前提。
数组元素为有序排列,需要确定搜索的左右边界,该题中存在两种右边界的选择:
- right = nums.size()-1
在这种情况下,搜索区间为 [left,right] 左闭右闭区间,left 和 right 相等的情况在此区间下是有意义的,所以此时对应的循环条件为 while(left<=right)。
若 nums[mid] 大于 target,更新搜索范围右下标 right 为 mid-1。
- right = nums.size()
搜索区间为 [left,right) 左闭右开区间, left和 right 相等的情况在此区间下无意义,对应的循环条件为while(left<right)。
若 nums[mid] 大于 target,更新搜索范围右下标 right 为 mid。
代码实现
左闭右闭区间
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
};
左闭右开区间
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
};
题目总结
二分查找中最基础的一种类型,即查找某一个数,需要处理好搜索区间问题
27.移除元素
解题思路
题目要求空间复杂度为 O(1),即不能使用额外的辅助空间,所有不能 new 一个新的数组,只能在原数组中进行操作,最后返回数组size。
- 暴力解法
使用两个 for 循环,一个 for 循环遍历数组元素,一个 for 循环更新数组。通过嵌套循环将数组内为 val 的元素覆盖
- 快慢双指针解法
通过一个快指针和慢指针在一个 for 循环内完成两个 for 循环的工作。快指针遇到值为 val 的元素,直接跳过,等待慢指针将其覆盖,若快指针遇到值不等于 val 的元素,将其赋值给慢指针,慢指针前进一步。
代码实现
暴力解法
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;
}
};
快慢指针
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.size(); fast++) {
if (nums[fast] != val) {
nums[slow++] = nums[fast];
}
}
return slow;
}
};
题目总结
双指针法在数组和链表的操作中很常见,双指针主要分为两类:左右指针和快慢指针,本题主要使用了快慢指针。
977.有序数组的平方
解题思路
由于数组中可能存在负数元素,在平方后可能会变成较大的值,如何对平方后的数组进行排序是重点。
- 暴力解法
遍历原数组,对数组中每个元素进行平方,再调用 sort() 对平方后的数组进行排序
- 双指针解法
因为数组是升序排列,需要考虑的就是在前面的负数在平方后是否会比后面正数平方后值大。使用双指针,分别指向数组起始位置和数组末尾位置,比较二者平方后数值的大小,将较大的值放入新数组的末尾,并将对应的指针向数组中心移动一位。
代码实现
暴力解法
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for (int i = 0; i < nums.size(); i++) {
nums[i] *= nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
双指针解法
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res(nums.size(), 0);
int k = nums.size() - 1;
for (int i = 0, j = nums.size() - 1; i <= j;) {
if (nums[i] * nums[i] < nums[j] * nums[j]) {
res[k--] = nums[j] * nums[j];
j--;
} else {
res[k--] = nums[i] * nums[i];
i++;
}
}
return res;
}
};
题目总结
首尾双指针比较指向数的平方值大小,定义新数组存储比较后的值。