剑指offer刷题总结

来源:互联网 发布:大和号战列舰模型淘宝 编辑:程序博客网 时间:2024/05/22 16:05

快速幂

求a的b次方(b为整型):

不妨记b的二进制为 bnbn1...b0,其中 bi=0 or 1,则:

ab=abn2n+...+b020=(a20)b0...(a2n)bn

可以看到新的底数 a2i+1=a2ia2i,根据这个规律可以写出快速幂的代码(仅考虑 b>0 的情况):

public double Power(double a, int b) {    double base = a;    double result = 1;    while(b != 0){        //判断b二进制末位是1,即bi是1的情况下,result需要乘上新的底数        if((b & 1) == 1) result * = base;         //按照规律更新底数        base * = base;        //将b的二进制右移1位,即删掉原始末位        b >> = 1;    }       return result;}

相比于循环 b 次做乘法,快速幂的时间复杂度仅为O(logb)

字典序全排列

以元素互异的字符集{p1,p2,…,pn}为例,输出它的全排列
假设字符元素之间存在某种偏序关系,例如整数集可以利用数值大小进行排序。全排列可以看成由字符集所有元素组成的字符串,如何不重复有序地输出该字符集的所有全排列,关键在于如何根据给定的全排列有规则地输出下一个全排列。

以{1,2,3}为例,其全排序为123,132,213,231,312,321,可以看到这里全排列的枚举方式保证了全排列的递增趋势,我们可以将这个递增的规则抽象出全排列生成的规则,从而避免重复枚举,或者遗漏。

根据上述例子,可以简述一下字典序全排列的步骤:

  • 记当前的全排列p=p1...pn
  • 找到j=max{i|pi<pi+1},k=max{i|pi>pj}
  • 交换换pj,pk
  • pj+1...pn这部分后缀进行翻转

可以证明一下这样得到的全排列,是大于当前全排列的最小的全排列(不妨假设字符集为正整数集):

  1. i>j, 则pi>pi+1,且k>j(pj+1>pj)
  2. 因为下标为j之前的部分没有发生改变,不妨忽略,记后缀部分为p=pj..pk...pn,pj+1...pn为递减列,p>pj(),其中pj()是指以pj开头的任意后缀,当然后面的字符为pj+1...pn的全排列
  3. pk为后续字符中大于pj的最小字符,下一个全排列应为pk()
  4. pjpk交换后,后面仍为递减列,将其翻转则为递增列,为这些字符组成的最小的全排列
原创粉丝点击