代码随想录算法训练营day1 | 704.二分查找、27.移除元素、977.有序数组的平方
704.二分查找
点击查看代码
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 >> 1); //加减法优先级大于移位
if(nums[mid] < target)
left = mid + 1;
else if(nums[mid] > target)
right = mid - 1;
else return mid;
}
return -1;
}
};
使用左闭右闭区间写法[left,right],影响以下两个地方:
1、while(left <= right)中应该使用<=而不是<,因为left = right的时候是有意义的
2、nums[mid] > target时,right = mid - 1而不是right = mid,因为此时mid处的值不为target,应该排除在闭区间外
右移1位比/2更快,但要注意加减法的优先级大于移位
采用left + (right - left >> 1)而不是(left + right) / 2是因为left + right可能产生溢出
27、移除元素
解法一:双重循环,移动元素O(n + logn)
点击查看代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) { //暴力解法O(n + logn)
int size = nums.size();
//注意i和j是< size而不是< nums.size(),因为移除元素后size会改变
for(int i = 0; i < size;){
if(nums[i] == val) {
for(int j = i + 1; j < size; ++j) {
nums[j-1] = nums[j];
}
--size;
//i值不变,因为此时i处的元素需要在下一轮外循环中检查
}
else
++i;
}
return size;
}
};
解法二:快慢指针法O(n)
点击查看代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) { //O(n)
int size = 0; //不等于val的元素个数
int slow = 0, fast = 0;
while(fast < nums.size()) {
//快指针寻找要留下的元素,忽略待移除元素
if(nums[fast] != val) {
nums[slow++] = nums[fast++];
++size;
}
else
++fast;
}
return size;
}
};
快指针fast用于寻找要留下的元素,即不等于val的元素,跳过等于val的元素
慢指针slow用于存放快指针fast找到的元素
解法二直接忽略val元素,不想着如何覆盖掉val元素,而是直接找出要留下的元素往前放即可
977、有序数组的平方
解法一:平方后快排O(logn)
点击查看代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) { //O(logn)
for(int i = 0; i < nums.size(); ++i) {
nums[i] *= nums[i];
}
sort(nums.begin(), nums.end()); //快速排序
return nums;
}
};
解法二:头尾双指针O(n)
点击查看代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) { O(n)
vector<int> result(nums.size()); //空间复杂度O(n)
int left = 0, right = nums.size() - 1;
int i = result.size() - 1; //从最后最大的元素开始存放
while(left <= right) {
if(nums[left] * nums[left] > nums[right] * nums[right]) {
result[i--] = nums[left] * nums[left];
++left;
}
else {
result[i--] = nums[right] * nums[right];
--right;
}
}
return result;
}
};
一开始的想法是找到0元素,再从0的左右延申处双指针,靠近0元素的平方数最小,但不是所有的测试数据都能找到0元素,此种方法不具有一般性。
换一种想法,不要从小到大找,而是从大到小找,nums首尾两端的元素的平方必然是最大的(充分利用初始数组有序的条件),故可设首尾指针,从大到小找平方数。
注意使用双指针法时,空间复杂度为O(n),但时间复杂度为O(n),解法一中虽然空间复杂度为O(1),但时间复杂度为O(logn),而一般时间复杂度更重要,故解法二更优。
2025/02/12
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验