例子一 判断是否是4的幂(Leetcode上有该题)
实现方法一
实现方法二
通过位运算优化了方法一
实现方法三
该方法成功将复杂度降到了O(1)
- num > 0 是因为 4的幂皆大于0
- num & (num - 1) 可以验证num是否为2的幂(4的幂为2的幂的子集),背后原理是:任何二进制数n和它的(n-1)进行位运算,结果中1的数量会比n中1的数量少1个(可以很简单地由数学归纳法证明此结论)
- num & 0xAAAAAAAA 由于在四的幂的二进制表达式中,(注: 以下位数是从0位开始计算, 比如100: 从右往左数,分别是第零位,第一位和第二位, [与从1开始计算会有不同] )1只可能存在于偶数位,且只有一个,其他位数皆为0,(由于前两步已经验证了该数为2的幂,所以我们无需验证1是否只存在1位), 所以我们只需通过num & 0xAAAAAAAA便可验证其是否位四的幂
实现方法四
(正则表达式知识补充:
(?:pattern)
匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
引用:js 正则中冒号代表什么正则表达式,正则匹配冒号weixin_39710361的博客-CSDN博客 )
例子二 洗牌算法
错误实现一
错误在于:使用该算法会发生越小的数倾向于出现在前面,可以通过统计并对比(在较大尺度下)每位出现的数的和来发现该问题,因为这里是使用sort进行洗牌,而它并不能做到均匀的交换(具体可以看sort的实现)
实现方法一
该方法解决了以上的问题,每轮从所有n张牌中抽一张放在最后一张,然后下一轮重复该操作(但作用域缩小至n-1张牌,不包括那张已被分配的牌),该算法的随机性可通过数学归纳法证明
实现方法二
(使用了生成器)
例子三 分红包算法
- 我们不可能真的完全随机分,需要加一些限制,否则会遇到一些问题,比如,每个人分的钱数至少要大等于一分
切西瓜算法
- 基本思路:每次都挑最大那份,然后随机切一刀(第一刀切的是整个西瓜,因为初始状态下,西瓜就是最大的那份!!!),直至达到需要分的份数为止
- 该算法的问题是,最终分出的结果为更倾向于均分,金额的随机性没那么强,很难出现比如这种的情况(99.97 0.01 0.01 0.01)
抽牌算法
- 基本思路:假设100元抽n个人,我们在0-9999之间插入(n-1)张牌,第一个红包的金额是:第一张牌的索引减0;第n个红包金额是:第k张牌的索引减第(k-1)张牌的索引,最后一个红包的金额是:array.length - 最后一张牌的索引(即第n-1张牌的索引)
- 解决了金额随机性不够强的问题,提高了抢红包的游戏性,刺激性