代码随想录(Day 1)

今日任务

1.二分查找
2.移除

1.二分查找

LeetCode链接

此题虽然从思路上较为简单,但是对于边界条件,很容易混淆,本质上是对元素的交并不够清晰,例如快速抛出几个问题
1.在使用while循环中,有时是left <= right,有时却是left < right,这其中肯定是有区别的。
2.在更新左/右边界上,方式不一样,有时是right = middle - 1,有时却是 right = middle

首先此类问题可以大致分为左闭右闭区间和左闭右开区间。

1.左闭右闭区间和左闭右开区间的区别

例如在数组1,2,3,4,7,9,10中,如果使用左闭右闭区间,则用图直观表示为

其中left边界设置为0,right边界设置为6,因为在数组arr[left]或者arr[right]上都能取到元素,故此为左闭右闭区间

如果使用左闭右开区间,则用图直观表示为

同上分析,右边界无法取到元素,故此为左闭右开区间

注意这两种方式,同为左闭,这为后来理解可以提供些许方便之处。 

开始对其进行具体分析,首先我们应该能熟练二分法思想,本质上就是不断更新左右边界而能更快查找到元素,所以对其思路的分析便不再续写,我们的重点是边界条件的分析。

1.对于while中条件的分析

在左闭右闭区间中,当我们使用while循环时,应该使用left < right还是left <= right呢?我们首先应该关注while的用法,只要不满足while语句的条件时,便会自动跳出循环,由此,当left < right时,即当left = right时或者left > right时,就会跳出循环了。而left = right值得我们再去思索思索。

首先我们应该考虑,存不存在left = right时,我们仍能在区间内取到一个元素,不然啥元素都取不到,连比较都没法进行比较了。

我们可以举个例子

当left = 1,right = 1,在区间上可以表示为[1,1],根据数学知识,我们能成功取得元素1。所以left = right应该完美嵌合左闭右闭区间的合法区间。所以要是在while循环中直接写left < right,当left = right时,明明这是满足题意的合法条件,但是在该循环的条件中被判定为不合法,就会提前跳出循环。

而在左闭右开区间呢?
我们同样进行考虑while循环中的条件写法。
牢牢记住,我无论left和right怎么变,我一定要能在left和right的区间中取到元素。

再举个例子

还是当left = 1,right = 1,在左闭右开区间就表示为[1,1),这能取到元素吗,显然不行,故left = right这种写法肯定不能满足。

2.对于middle的更新

首先对左闭右闭区间进行分析,我们先给出代码
 

​
 if(nums[middle] > target) {
            right = middle-1;
        } 

​ else if(nums[middle] < target) {
            left = middle+1;
        } 

先对右边界的更新进行分析。注意看if的条件,里面的nums[middle]是不是已经被拿来和target目标值比较了,已经比它大了,我后续更新我的right时还有必要取到它吗?注意,是左闭右闭区间,所以右边是可以取到元素的,所以没必要啊,我都已经证明了。

左边界我们可以不急,因为左闭右闭区间和左闭右开区间都有个左闭,这也是共同点,我们可以最后一次性全部分析。

再对左闭右开区间进行分析,我们给出代码

if(nums[middle] < target){
            left = middle + 1;
}
else if(nums[middle] > target){
            right = middle ;
}

我们可以看到right直接赋值为middle了。注意这是左闭右开区间,我们nums[middle]是不是已经分析过了,它大于target目标值没问题,他的索引也为middle也没问题,关键是我们是左闭右开区间,我哪怕直接使right = middle,我右边反正也取不到元素我也不怕你重复了,故条件可直接写为right = middle。

最后,对左边条件的分析,我感觉可以忽略了,就和左闭右闭区间的右闭分析思路是一样的。

2.移除数组中元素

LeetCode链接

这题仍然是一道较为简单的题目,因为题意足够浅显,通过暴力可求解,但这题精髓是双指针法,接下来对双指针法进行分析。暴力法代码会贴在后面,可供参考。

目前我的理解是双指针法,不是真的是要使用两个指针来进行求解,在数组中,我们都是可以使用index (索引)来代替指针的作用的。

我们先对总体思路提一下,首先,我们可以知道,数组中的元素删除本质不是删除,只是对其进行覆盖,就像老师叫你擦黑板,你为了胡弄这份差事,你可以直接拿一张大黑纸覆盖。所以我们就能知道,数组在进行删除中,并未涉及到真正意义上的擦除,而我们拥有索引这个利器。

引入Slow指针和Fast指针, 其实,我们也可以写作read指针和write指针,read指针只负责对这个数组进行遍历和条件判断,真正的更改这个数组元素是依靠write指针来写入的。

首先,我们可以使用循环,用read指针对这个数组进行遍历,因为这个数组本来就是有元素的,我们进行遍历的时候,也可以顺便进行条件判断,

当read指针指向的元素不等于我们需要删除的元素时,也就意味啥事不干,直接进行赋值语句arr[write] = arr[read]

而当read指针指向的元素等于我们需要删除的元素时,我就选择视而不见,直接跳过赋值语句。

我们可以使用图像来辅助理解


最后我们贴出暴力求解的方法

for (int i = 0; i < size; i++) {
            if (nums[i] == val) { 
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--; 
                size--; 
            }
        }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值