前面3篇文章介绍了减治法的策略和思想,经典数据结构算法中的几个减治算法,排列,子集的减治算法。这些都是属于减一治的减治策略。
这篇文章来介绍减常因子和减可变规模的减治策略算法,当然,规模递减的越快的算法也就越难找,所以这样的算法并不是很多。目前前面写过的减常因子的有折半查找(减常因子的减治策略的可以看做分治的变种,前面说过),减可变规模的减治策略有欧几里得最大公约数算法。
---------------------------------------------------------------------------------------------------------------------------------------------------
1.减常因子策略
1)假币问题
或者说是坏苹果问题,很老的微软面试题了。在n个外观相同的硬币中,有一个是假币(重量与别的硬币不同,较轻),只有一架天枰,怎么找出假币?
这或许是个小学生都会的问题:
a, 每次若为偶数,分成两半,假币肯定在较轻的那一半中
b, 若为奇数,拿一个出来然后把剩下的分两半,若两半相等则拿出的一个是假币,否则同步骤a
这样每次都将问题的规模缩减为原来规模的1/2,其时间复杂度和折半查找一样。
看上去,现在这个问题似乎是很低级无聊,问题是,这样做最高效的算法吗?给你一堆假币,按照上述办法来做找假币,是最快的办法吗?
不是!
事实上可以将规模分成三份,每次比较任意两份,若相等则在第三份中,若不相等则在这两份的较轻一份中,这样问题的规模每次递减为原来规模的1/3。虽然它也是对数级别的复杂度,但一个是log2(n),一个是log3(n)
根据这一思想,对于二分查找,我们可以设计出更好一点的算法:三重查找,每次同时和数组中下标n/3, 2n/3的两个点比较,这样多比较一次就将问题规模定位到一个原规模三分之一的区间了。复杂度为log3(n),本节的习题给出了这样一个问题,实现不是很难,略。
2)俄式乘法
一个很简单但很有趣的例子,简单看下吧:
对于2个数相乘n * m,显然有这样的式子:
上面的式子显然可以递归的定义,见乘法的规模越变越小,把1 * m作为结束递归的条件。
这样做有什么好处和意义呢?应该注意到,用上述办法来做乘法,该算法所有运算只有折半,加倍,相加3个操作,这对于不想记乘法口诀表的人来说是一个诱惑,因此在19世纪俄国农夫广泛的采用了这种方法。另外,由于它只进行加法吗,折半和加倍(可以通过移位运算),速度比传统乘法快。