算法训练Day01|数组part01(LeetCode704. 二分查找、LeetCode27. 移除元素)

文章目录

    • 数组理论基础
    • 704. 二分查找
      • 重点
      • 代码
    • 27. 移除元素
      • 重点
      • 代码

文章讲解
视频讲解

数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合。内存上的地址空间是连续的,所以添加或删除元素的时候需要移动其他元素,覆盖原有的元素,而不能直接删除。

704. 二分查找

题目链接
二分查找的一个前提条件就是,有序且不重复的数组,在这样的数据中找到某一个满足条件的元素。二分查找的时间复杂度是O(logn)。

重点

区间的定义是循环不变量,从始至终边界的处理都要根据循环不变量。

一个特别好的讲解

  • 区间边界问题

    • 左闭右闭
      定义target在[left, right]中,循环条件就是 while (left <= right),if (nums[middle] > target) ,right值应该为middle-1。

    • 左闭右开
      定义target在[left, right)中,循环条件就是 while (left < right),if (nums[middle] > target) ,right值应该为middle。

  • middle的表示问题
    middle不能表示为(right + left) / 2,会溢出,而应该表示为left + (right - left) /2。

代码

  • 左闭右闭
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;    
        while(left<=right){
            int middle=left+(right-left)/2;//这里当时做错了,写到循环外了,导致时间超时
            if(nums[middle]>target){
                right=middle-1;
            }
            else if(nums[middle]<target){
                left=middle+1;
            }
            else{
                return middle;
            }
        }
        return -1;
    }
};
  • 左闭右开
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size(); //right取不到   
        while(left<right){
            int middle=left+(right-left)/2;
            if(nums[middle]>target){
                right=middle;
            }
            else if(nums[middle]<target){
                left=middle+1;
            }
            else{
                return middle;
            }
        }
        return -1;
    }
};

27. 移除元素

题目链接
数组中没有真正的删除,只有覆盖。

重点

有两种解法,最容易想到的是暴力解法,两层for循环,一层查找,一层移动后面的元素,时间复杂度O(n^2)。
但重点要掌握的是双指针的思想,即快慢指针法,快指针在前面探路,慢指针在后面接收新的数组元素,在一个for循环下完成两个for循环的工作,时间复杂度O(n)。

代码

  • 暴力解法
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size=nums.size();
        for(int i=0;i<size;i++){//这里是size,不是nums.size()
            if(nums[i]==val){           
                for(int j=i+1;j<size;j++){
                    nums[j-1]=nums[j];//覆盖操作,注意j的边界范围     
                }
                i--;//超容易想不到
                size--;//size的位置,两个for循环都结束后再减减
            }
        }
        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];
                slow++;
            }
        }
        return slow;//不用nums.size()了,这个slow就是新数组的大小
    }
};

之前这两道题都刷过,二刷随稍微轻松一些,但由于算法水平不好,总是在各种各样的问题上出错,甚至我清楚地记得上次也是这么错的,所以我把出过问题的地方标了注释,以后再看也是一个提醒。这是我第一次写博客,也是第一次尝试使用markdown编写文档,废了不少时间,但是很有收获。

你可能感兴趣的:(算法,算法,c++,数据结构)