代码随想录算法训练营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

posted @   coder小杰  阅读(620)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示