代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素

704.二分查找

题目链接: 704.二分查找
方法一:直接遍历


for( i = 0; i <= nums.length-1; i++){
 if(nums[i] == target){
      return i;
 }
}
return -1;
}

方法二:二分查找
适用前提:
1.数组内部已经是有序序列
2.数组中无重复元素,因为有重复元素的情况下,二分法所返回的元素下标不唯一
二分法还需要注意的一点是target所在区间两端是闭还是开,区别主要在于while寻找中每一次边界的处理,即循环不变量原则
首先是左闭右闭区间(即**[left,right]**)的写法。

int search(int* nums, int numsSize, int target){
    int left = 0, right = numsSize-1, middle = 0;
    while(left <= right){ //定义target在左闭右闭区间,即[left,right]
        middle = ( left + right )/2;//这里应该可以改进为middle = left + ((right - left)) / 2 可以防止溢出
        if ( nums[middle]  < target ){
            left = middle + 1; //target位于右区间,更新left,即查询[middle+1,right]
        }else if( nums[middle]  > target ){
            right = middle - 1;//target位于左区间,更新right,即查询[left,middle-1]
        }else{//nums[middle] == target
            return middle;//返回下标
        }
    }
    //未找到目标值
    return -1;
}

再给出左闭右开(即**[left,right)**)的写法,需要注意的是,由于区间是[left,right),则二分法的边界处理方式会有所不同。
具体体现在如下两点:

  • while(left < right),这里只能用<,因为对该区间而言left==right是毫无意义的。
  • if(nums[middle] > target)的情况下,right更新为middle,因为当前的nums[middle]不等于target,要到middle的左边区间寻找,因为寻找的区间是左闭右开区间,所以right需要更新为middle,也就是使得下一个查询区间不会比较nums[middle]的值。
int search(int* nums, int numsSize, int target){
    int left = 0, right = numsSize-1, middle = 0;
    while(left < right){//定义target在左闭右开区间,即[left,right)
        middle = left +(( right - left )/2);
        if ( nums[middle]  < target ){
            left = middle + 1;//target位于右区间,更新left,即查询[middle+1,right]
        }else if( nums[middle]  > target ){
            right = middle;//target位于左区间,更新right,即查询[left,middle]
        }else{//nums[middle] == target直接返回下标
            return middle;
        }
    }
    //未找到目标值
    return -1;
}

题目链接: 27.移除元素

方法一:暴力解法
使用两个for循环,第一个用来循环遍历数组元素,第二个则负责循环更新数组。显然暴力解法的时间复杂度伟O(n^2)
代码如下

int removeElement(int* nums, int numsSize, int val){
    int size = numsSize;
    for(int i = 0; i < size; i++){
        if(nums[i] == val){
            for(int j = i; j < numsSize-1; j ++){//若j初值赋为i+1,则判断条件要改为j<size,移动元素语句改为nums[j-1] = nums[j];
                nums[j] = nums[j+1];
            }
            i--;
            size--;   
        }
    }
    return size;
}

方法二:双指针法
即快慢指针法:通过一快一慢两个指针,在一个for循环下完成暴力解法中两个for循环的工作。

int removeElement(int* nums, int numsSize, int val){
    int size = numsSize;
    int fast = 0, slow = 0;//定义快慢两个指针,快指针用于遍历数组找出新数组所需元素,满指针用于存放新数组元素
    for(fast = 0; fast < size; fast ++){
        if(nums[fast] != val){//新数组所需元素
        nums[slow] = nums[fast];//将新数组所需元素放到新数组中
        slow++;//元素存入新数组后慢指针向后移
        }
        
    }
    return slow;//slow恰好是新数组的长度
    }

双指针法的时间复杂度为O(n)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值