两道题:
一、
题目:求一个数的阶乘后面有几个0
如11! = 39916800,所以后面有两个0
要求时间复杂度小于O(log N)
思路:
因为有时间复杂度的限制,肯定不能直接算出阶乘
想一想后发现所有末尾出现0的肯定和5有关的,都是5乘一个偶数或者5的倍数乘一个偶数
如5*2 ,15*2,35*2或者直接包括类似10、100的。
但是不用组合的得出的0的个数也是不一样的。
如只是5的倍数而不是5的高次幂的倍数,只出现一个0:如5*2、15*2、10*2;
5的平方的倍数出现两个0:如25*4, 50*4,75*4;
以此类推:
5的立方的倍数出现3个0:如125*8、250*4等
于是有了思路,0的个数n=n/5+n/25+n/125+ ......;
于是可以写函数了 ,写了一个递归函数
int zeroNumber(int n)
{
if(n<5)
return 0;
return n/5+zeroNumber(n/5);
}
第一层递归先算出5的倍数,第二层算出25的倍数的个数.........知道有一层为0,然后全加起来就是结果,
想了想非递归算法也很简单:
int xz(int n)
{
while(n!=0)
{
x=x+n/5;
n=n/5;
}
return x;
}
解释:x为0的个数
这道题的重点在于转化问题,把0的个数转化为阶乘中5的n次幂的倍数的个数的问题。
二、
字符串偏移
偏移量为n
要求空间复杂度为O(1)
例子:
Given "abcdefg"
.
offset=0 => "abcdefg"
offset=1 => "gabcdef"
offset=2 => "fgabcde"
offset=3 => "efgabcd"
但是想了很久才写出代码:
因为空间复杂度为确定为O(1);
所以只能一个字符一个字符的转移,并且转移的同时保存
这样的话只能按照转移的顺序执行程序,即abcdefg偏移量为3的话
a到d
d到g
g到c
c到f.
..
直到全部完成
但是!!!!
例如abcdef 偏移量为3
就会进入一个循环
a到d
d到a
永远不会完成
所以需要加判断如果回到了一开始的地方并且没有完成,就往后走一位继续运算
判断完成只需用一个计数器即可,而判断回到一开始也只需要保存一下第一个就好。
满足空间复杂度为O(1)
代码如下:
void sz(string &str,int n)
{
int m=str.length();
if(m==0)return;
if(n==0)return;
char x=str[0];
char y;
n=n%m;
int i=0;
int count=0;
int c=0;
while(1)
{
y=str[(i+n)%m];
str[(i+n)%m]=x;
x=y;
count++;
if((i+n)%m==c)
{
c++;
i++;
x=str[(i+n)%m];
}
if(count==m)
break;
i=i+n;
}
return;
}
有些看上去很简单的东西,还真没有想的那么简单。。。。
一开始总是按照顺序做.后来发现那样的话,因为偏移量的不同,前一个字符不到下一个字符的位置,所以需要很多的不确定空间
所以做不出来....
后来就想到了分组转移,按照前一个字符到下一个字符的位置的顺序转移就很简单了