Leetcode 数组

1.二分查找

题目链接:LeetCode 704.二分查找

题目状态:AC

 思路:

通过一个示例来讲解本题思路,示例如下:

输入: nums = [-1,0,3,5,9,12], target = 9     
输出: 4       
解释: 9 出现在 nums 中并且下标为 4  

初始化start = -1 , end = nums.size()。(注:如果集合中为空,end则为0,此时不满足循环条件start+1!=end,不会进入循环体,也就不会计算mid的值导致边界问题)图中将start指针和end分别用蓝色和红色表示,蓝色代表小于target的元素,红色代表大于target的元素。初始下数组中的元素没有任何颜色。

1.判断start与end是否满足start + 1 != end。不满足退出循环,满足进入2.

2.计算mid的值。

3.判断mid索引的值与target的大小关系。

对于任一数组中的元素,与target的大小关系只有三种

  • nums[mid] == target, 此时mid索引对应的值就要查找的对象,直接返回mid退出循环。
  • nums[mid] > target, 此时mid索引及右侧的值大于target全部染为红色,并且将mid索引交给end,继续步骤1. 
  • nums[mid] < target, 此时mid索引及坐左侧的值小于target全部染为蓝色,并且将mid索引交给start,继续步骤1.

注意:上述结论成立的前提条件是给定的nums是升序的。

对应本例,mid = (-1+6)/2,取下界mid = 2,nums[mid] =3小于target的值9,于是mid左侧(包括自身)所有的元素都小于target,因此将他们扩散为蓝色。

继续计算mid,并判断

此时mid对应的就是目标值,返回mid。

其实整体上的思路就是循环体内,每次计算出一个mid值,判断nums[mid]与target的大小关系,从而决定蓝色(start)的扩散或者是红色(end)扩散,直到找到了对应的target(此时mid索引指向它,返回mid,退出循环)或者数组内的元素已全部判断完毕(此时start+1==end,不满足循环条件退出循环,返回-1)

1.其实这个例子不是很好,没能完全展现蓝色与红色的扩散过程,可以自己举个例子做一遍,或者有空我补上(懒)。

2.正确性:

        mid的最小值为(start_min + end_min ) / 2 = -1 + 1 = 0, end最小值不会取到0,因为此时start+1==0不满足循环条件,不会进入循环体。对应的,最大值为(nums.size()-2 + nums.size())/2 = nums.size() -1。于是mid的取值范围为[0, nums.size()-1],始终保持在数组的范围内。

3. 能不能将start初始化为0或者end初始化为nums.size()-1?

        不能。因为蓝色和红色分别代表小于或大于target的元素,如果直接初始化到数组内的下标,假设给定的数组元素全部小于target或者全部大于target,就会出错。

题解:

class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        int start = -1, end = nums.size();
        int mid;
        while(start + 1 != end)
        {
            mid = (start + end) / 2;
            if(target > nums[mid])
                start = mid;
            else if(target < nums[mid]) 
                end = mid;
            else
                return mid;
        }
        return -1;
    }
};

 更加详细的讲解请参考:https://www.bilibili.com/video/BV1d54y1q7k7/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click&vd_source=31e182bfac174aac0fe25f67b024e3c4

2. 移除元素

题目链接:LeetCode 27.移除元素

题目状态:AC

文档参考:代码随想录

思路:

示例:

给定 nums = [0,1,2,2,3,0,4,2], val = 2, 

函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

本题要求必须进行原地操作修改数组,可以先借助一个辅助数组B来理解,假设创建一个大小与给定集合同等的数组,并用slowIndex指向首部。

fastIndex遍历数组,当索引到的值不是val时,执行B[slowIndex]=A[fastIndex] ,同时slowIndex++,直到fastIndex遇到 val:

此时,fastIndex仍然满足循环条件fastIndex < nums.size(),fasterIndex++。而循环体内判断语句不成立,slowIndex和B数组不做任何操作,结果如下所示:

于是不断进行循环判断直到fastIndex不满足循环条件,最终情况如下:

观察可以发现,slowIndex始终指向即将插入元素的位置,fastIndex则遍历数组进行判断,如果对应元素为val,则做出相应操作。slowIndex最终的索引值正好就是我们想要的元素个数,所以直接返回slowIndex。

然而本题要求必须进行原地操作,不能采用辅助数组。

因为fastIndex是先移动再判断的,始终大于等于slowIndex,并不会受到slowIndex修改元素的影响(灾难始终慢我一步!),所以可以省去辅助数组,进行原地操作。

题解:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for(int fastIndex = 0; fastIndex < nums.size(); fastIndex++)
        {
            if(nums[fastIndex] != val)
            {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }    
        }
        return slowIndex;
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值