代码随想录算法训练营19期第1天| 二分查找,双指针 (二刷)

[二分:704二分查找, 35找插入位置, 34寻找target段头尾, 69x sqrt,  367 perfect square]

难点可能在:插入位置,寻找左/右边界,处理超出int大小

代码随想录算法训练营第1天 | 704二分查找,27移除元素_weixin_51674457的博客-CSDN博客

代码随想录额外题目| 数组03 ●34排序数组查首尾位置 ●922按奇偶排序数组II●35搜索插入位置_weixin_51674457的博客-CSDN博客

[双指针:27移除元素, 26.删除排序重复, 283.移动零, 844.比较含退格str, 977.有序数组的平方]

难点可能在:写满足[slow++]的条件,巧妙的遍历顺序(两头向中间)

代码随想录算法训练营第1天 | 704二分查找,27移除元素_weixin_51674457的博客-CSDN博客

代码随想录算法训练营第2天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,总结_weixin_51674457的博客-CSDN博客

69,367 第一次做,其他二刷

704二分查找 很快, 用(start+end)/2 不容易错

35找插入位置,很快,巧妙,没找到直接return end-1或者start(最终结果只会剩下一个元素:即mid=start=end,要是target<[start], 答案就是start,要是target>[start] 我们需要插入在start+1,而start确实会变成mid+1=start+1,所以又只用return start了)

34 寻找target段头尾,略微变体为寻找左右边界(大于小于情况不变,等于时找左边界那我们还是要改变end往左移动,找右边界还是要改变start往右边移动,并且要不断更新border为mid)因为我第一次不是这样做的,是先找到target再不断左右移动,其实也没差,所以我不太会用二分找左右边界,这回思路理顺后应该会了

vector<int> searchRange(vector<int>& nums, int target) {
        int start=0; int end=nums.size()-1;
        int right_idx=-1;
        int left_idx=-1;

        //find right
        
        while(start<=end){
            int mid=(start+end)/2;
            if(target<nums[mid]) end=mid-1;
            else if (target>nums[mid]) start=mid+1;
            else{//equal case
                right_idx=mid;
                start=mid+1;
            }
        }

        //find left
        
        start=0; end=nums.size()-1;
        while(start<=end){
            int mid=(start+end)/2;
            if(target<nums[mid]) end=mid-1;
            else if (target>nums[mid]) start=mid+1;
            else{//equal case
                left_idx=mid;
                end=mid-1;
                
            }
        }

        return {left_idx,right_idx};
    }

69 x sqrt

有点像35插入位置,mid*mid数值会过大,需要处理用size_t 或者 改用x/mid,两种都在下面

    int mySqrt(int x) {
        int start=0; int end=x;
        while(start<=end){
            size_t mid=(start+end)/2;
            if(mid*mid==x) return mid;
            else if(mid*mid<x) start=mid+1;
            else end=mid-1;
        }
        return start-1;
    }

    int mySqrt(int x) {
        if(x==0) return 0;
        int start=1; int end=x;
        while(start<=end){
            int mid=start+(end-start)/2;
            if(mid==x/mid) return mid;
            else if(mid<x/mid) start=mid+1;
            else end=mid-1;
        }
        return start-1;
    }

367 perfect sqrt 和 69 sqrt几乎一样,就是不能用除法,一定要用mid*mid

bool isPerfectSquare(int num) {
        int start=1;
        int end=num;
        while(start<=end){
            size_t mid=start+(end-start)/2;
            if(mid*mid==num) return true;
            else if (mid*mid<num) start=mid+1;
            else end=mid-1;
        }
        return false;
    }

[双指针:27移除元素, 26.删除排序重复, 283.移动零, 844.比较含退格str, 977.有序数组的平方]

27移除元素 标准双指针 slow fast,fast作主itr,只有符合要求才从头放起[slow++]

26删除排序重复 一模一样,只有判断条件变了

int removeDuplicates(vector<int>& nums) {
        int slow=0;
        int fast=0;
        while(fast<nums.size()){
            if(fast==0 || nums[fast]!=nums[fast-1]){
                nums[slow++]=nums[fast];
            }
            fast++;
        }
        return slow;
    }

844.比较含退格的字符串 

我一刷想的特别复杂,其实跟前面也类似,就是从头看起,符合要求就加入,符合另一个要求,就把str 尾巴去掉一个,这里注意 str也有pop_back的操作的

 string helper(string str){
        string ans="";
        for(char &c:str){
            if(c!='#') ans+=c;
            else if(ans.size()) ans.pop_back();
        }
        return ans;
    }
    bool backspaceCompare(string s, string t) {
        return helper(s)==helper(t); 
    }

977.有序数组的平方  双指针从尾巴开始,有点巧

我从中间分开向两头做,代码和逻辑会很复杂,随想录是从头尾向中间收拢,逻辑简单太多

从中间往两头写特别麻烦(我写的)这时候就应该想到从两头往中间写(随想录)

my code 中间到两头

vector<int> sortedSquares(vector<int>& nums) {
        vector<int> res;

        int mid=0;
        if(nums[0]>=0) mid=0;
        else if(nums[nums.size()-1]<0) mid=nums.size()-1;
        for(int i=1;i<nums.size();i++){
            if(nums[i-1]<0 && nums[i]>=0) mid=i;
        }
        int i=mid-1; int j=mid; 
        while(i>=0 || j<nums.size()){
            if(i<0){
                res.push_back(nums[j]*nums[j]);
                j++;
            }
            else if (j>=nums.size()){
                res.push_back(nums[i]*nums[i]);
                i--;
            }
            else if(nums[i]*nums[i]<=nums[j]*nums[j]){
                res.push_back(nums[i]*nums[i]);
                i--;
            }
            else if(nums[i]*nums[i]>nums[j]*nums[j]){
                res.push_back(nums[j]*nums[j]);
                j++;
            }
        }
        return res;
        
    }

my code 两头往中间

    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> res(nums.size(),0);
        int start=0; 
        int end=nums.size()-1;
        int idx=nums.size()-1;
        while(start<=end){
            if(nums[start]*nums[start]>nums[end]*nums[end]){
                res[idx--]=nums[start]*nums[start];
                start++;
            }
            else{
                res[idx--]=nums[end]*nums[end];
                end--;
            }
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值