今天我们来讲一个比较简单的题目,这是一个好玩的题目,希望大家可以思考一下。
原题:
有 一个队列,这个队列有n个元素,并且这个队列单调上升,现在我们进行这么一个操作,把前面若干个元素剪切下来,粘到队列后面。例如 (1,2,3,4,5,6,7 我们把前3个进行这个操作,变成4,5,6,7,1,2,3;如果是4个,变成5,6,7,1,2,3,4;如果是0个,原队列不变)。现在给一个操作后 的队列,求队列中最小的元素是多少?(用越快的算法越好)
思考:
这个题目,99%的人可以用O(n)的算法来解决。但是,这是最优的么?
我们来想一想有没有更优的解法,既然比O(n)更优,那么有可能是O(logn)。我们朝这个方向思考,我们想起来我们以前学过二分查找。我们来回想一下二分查找的特性。
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好。但使用二分查找必须满足下面条件,
必须采用顺序存储结构
2.必须按关键字大小有序排列。
这个题好像并不满足是一个有序的队列,但是至少有可能是两个有序的队列。
再进一步思考,难道我们就走投无路了么?
我们先不要慌,我们来想一想这个序列长什么样子。
如果我们随机截取这个中间某一段,那么有两种情况。
橙色部分是一个两段上升序列,而黄色的部分是一段连续上升的序列。
我们再来进一步思考,如果是黄色的情况,最小的一定是出现在最左边的。如果是橙色的情况,那么最小的出现在中间的断层。
再继续思考,假设这段线段的索引是[l,r],那么当我们取中间的mid,当我们发现a[l] < mid 的时候,是有可能是下面的情况。
或者
我们用findMin(l, r)来表示这两种情况。当a[i] < a[mid]的时候,[l,mid]一定是上面黄色的框,[mid + 1, r] 可能是黄色的,也可能是橙色的。
findMin(l,r) = min(a[l], find(mid + 1, r));
我们来想另外一种情况, a[i] > a[mid],那么情况如下:
区间[mid,r]一定是上面黄色的框框,而[l, mid-1]则是橙色的框框,最小的可能是a[mid], 或者findMin(l, mid-1)。表达式为
findMin(l,r) = min(a[mid], find(l, mid - 1));
总结:
我们发现这个题目也是可以用二分法来解决的.这是最优的做法,好友说一年面试几十个人,每次都问这个,只有两三个可以短时间内想到结果。
欢迎大家关注我的头条号,也可以关注我的微信公众号(ddpcyh),会提供算法学习资料,一起来学习算法吧。