昨天我们讨论了选择问题中的找到最大值或最小值的问题,今天我们讨论一下将两个问题放到一起,考虑同时找到最大值和最小值的情况,看看问题是会更复杂还是反而更简单。
针对这一问题,我们同样非常自然地会想到暴力解法,将数组遍历两次,独立地找出最大值和最小值,根据我们昨天的分析,每一次都需要进行次的比较,共需要次。
但是我们会发现,可能并不需要比较那么多次,其中有些比较得出的信息是无效的。比如有一个数已经是当前最小值,那它还需要跟当前最大值相比较吗?很明显是不需要的,因为当前的最小值是一定会小于等于当前的最大值的,所以这次比较就完全没有必要。那么有什么方法可以让每一次比较都能做到有效呢?
考虑优化的思路,我们会发现,如果比当前最小值小,那么我们不需要再次跟当前最大值相比;反之如果比当前最大值大,那么我们也不需要与当前最小值相比。问题主要出在如果比当前最小值大的情况,那与当前最大值的比较就无法避免,这样的优化实际上并不能很大程度提升效率。那么回到问题,我们要找的是最大值和最小值两个值,那我们是不是可以成对成对地比较,让两个数分别去跟当前的最大值和最小值相比呢?想到这里,我们就可以做出另一种优化的方案。
我们将数组元素两两分组,首先进行组内比较,然后将大的那个与当前最大值相比,小的那个与当前最小值相比,就这样成对处理完所有的元素。这样按照最开始的方案每个数进行两次比较,而现在只需要三次,每一组都可以省去一次比较,就取得了相当程度的优化。我们再考虑初始情况,如何初始化最大值和最小值。如果数组的长度是偶数,那么就将第一组的较大者设为当前最大值,较小者设为当前最小值;如果数组长度为奇数,那么最好是把当前的最大值和最小值都设置为第一个元素,之后数组就可以正好两两分组完全分完。
最后分析一下总的比较次数。如果为偶数,那很简单每组3次,一共是组,但第一组是不需要与当前最大值最小值比较的,也就是少了2次,所以最后的结果为次。如果为奇数,那么第一个元素不需要比较,剩下的每组3次,一共组,结果为次。
实际上我们发现,将两个问题结合在一起考虑,最后的代价是要比两个问题简单独立的叠加要来得更小的,优化了25%左右,这也是给我们的一种启发。