动漫算法梳理
2021-03-13 10:37
标签:++ 数组下标 位置 疑问 特殊 链接 tps problem font 【写在前言】 最近关注了好几个好友专门讲算法的公主号,赶脚还不错,本着“分享”、“共进”的初心,在征得本人的同意之下,特此将原内容经原作者本人同意授权后,重新编辑、排版、整理到此处。 在此,特别感谢小夕学算法,袁厨的算法小屋等原创作者大牛。 好了,话不多说,我要开启学习,和大家共同进步了,嘻嘻~~~ 【正文开始】 本文摘自【小夕】,点击可看原文 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 来源:力扣(LeetCode)、剑指offer11 有人说,像我下面这样一个循环不就A了吗?而且击败率100%,还有什么知识点? 如果你也这样想,那就大错特错了。且听我慢慢道来~~~ 那么疑问来了,为什么这样写不是最优的呢? 因为这就涉及到了复杂度的问题,一般情况下,单独一个for循环的复杂度是O(n),但是明显地,这道题不是让你去循环整个数组的。 在有序数组中查找某个元素,一般较好的方法是二分法,因为二分法可以将复杂度降为logN; 那么在二分法中,一般会有比较基准值,也就是target,有规定的话,就按照规定来取,没有的话一般按照最左侧或最右侧(也可称为左右端值)取为target,这在左神的算法课里讲过; 在这道题目中是没有目标值的,那么用中间值和低高位(左右端值)进行比较,看处于前半部分的是递增序列还是后半部分的是递增序列(旋转数组,比如说 在这里我添加一个小栗子,方便大家阅读: 比如:数组[4,5,6,7,8,1,2,3],数组长度为7,中间元素是数组长,7/2=3,所在位置的元素为7。那么,就该数组就被分为两部分[4,5,6,7],[8,1,2,3],前面的数组为递增,不用管,后面的为非递增,所以下一次就在右侧数组里继续查找,那么左端值元素就变为8,右端值元素不变还是3。这种情况就是在右侧查找; 同样的还有在左侧数组查找: 比如数组[7,8,1,2,3,4,5,6],数组长度为7,中间元素是数组长,7/2=3,所在位置的元素为2。那么,就该数组就被分为两部分[7,8,1,2],[3,4,5,6],前面的数组为非递增,后面的为递增,不用管,所以下一次就在左侧数组里继续查找,那么右端元素值就变为2,左端值元素不变还是7。 这里我们把target 看作是左端点,来进行分析,那就要分析以下三种情况,看是否可以达到上述的目标, 情况4, 如果上述还没看懂,请看下面的解析图: 以array = [4,5,6,7,8,1,2,3]为例:声明:下图中的high 和right一样的意思。 array[mid] = 7 > array[left] = 4是第二种情况,由于递增最小值只可能在mid的右侧区间,故新的参数: left = mid+1 = 3+1 =4;mid = (left + high)/2 = (4+7)/2 = 5 。新的图画如下: array[mid] = 5 第三种题目:
[3,4,5,1,2]
为[1,2,3,4,5]
的一个旋转,该数组的最小值为1。示例1:
输入:[3,4,5,1,2]
输出:1
示例2:
输入:[2,2,2,0,1]
输出:0
链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof[4,5,6,7,8,1,2,3]
前半部分是递增序列[4,5,6,7,8]
,后半部分递增序列[1,2,3]
),进行操作缩小范围。然后递归在新的范围内再次利用该思想进行查找。arr[mid] = 7 > arr[left] = 4,
target也就是arr[left]为左端点 4, arr[mid] > target(也就是arr[left])
, 说明[first ... mid] 都是 >= target(也就是arr[left]) 的,因为原始数组是非递减,所以可以确定答案为 [mid+1...last]区间,所以 left= mid + 1;
[5 6 1 2 3 4]
,左端点left的数组下标等于0,右端点数组下标等于5,mid下标是2。arr[mid] = 1 ,arr[mid] 为 1, target为右端点 4,
arr[mid] , 说明答案肯定不在[mid+1...right],但是arr[mid] 有可能是答案,所以答案在[first, mid]区间,所以right
= mid
;arr[mid] 既等于arr[left]又等于arr[right]
,需要特殊处理。进行left++
,如果arr[left] 那么直接返回arr[left]。
新的图画如下:
此时,array[mid] = 8 第四种情况,新的参数如下: left = left + 1 = 4+1 = 5 ,此时,left = high,故找到最小值,也就是array[5] = 1,跳出循环结束。其实新的图,也可如下看待:
第四种情况,单独将left++,目的是为了防止像[2,0,2,2,2]类似于这样的数组出现。
如果像这样的数组,那么,根据前述,一开始array[left] = array[mid] 的,前三种情况都不符合。所以需要特殊处理,就是第四种。
其实好好想一想,第二种是array[left] array[mid] ,所以肯定还有一种是array[left] = array[mid]。但这个时候你就不能判断最小值是在左区间还是右区间。比如:数组[2,0,2,2,2]中,最小值0就是在左区间;数组[2,2,2,2,2,0,2,2]中,最小值0就是在右区间内。所以,为了确定是在哪一个区间内,我们只好将left+1,这样新的数组也缩小了,就可以继续比对,继续判断新的array[left] 和array[mid] 的大小来确定最小值在哪一侧。原文中关于这一点还有图画,我在这里就不重复叙述了,不懂得可以移步,顺带关注一波原博主,哈哈哈~~~
Over。。。
动漫算法梳理
标签:++ 数组下标 位置 疑问 特殊 链接 tps problem font
原文地址:https://www.cnblogs.com/gjmhome/p/14057236.html
上一篇:数据结构与算法——红黑树的实现
下一篇:熟悉编程语言