这里主要是和编程思想有关的习题
大多来自于牛客与LeetCode,总结如下
习题
1. 阶乘尾数中0的个数
例: 3! = 6;故而尾数0的个数为0个
5! = 120;故而尾数中0的个数为1个
2.旋转数组
要求三种方法以及O(1)的空间复杂度(原地算法)
例如: 1,2,3,4,5 移动次数 2
第一次 5,1,2,3,4
第二次 4,5,1,2,3 结果值
答案
1.阶乘尾数中0的个数
由于偶数乘任何数都得偶数
首先阶乘中获得的结果除去尾数的0也必定为偶数
例 : 1*2*3*4*5 = (2*5) * 1*3*4
并且1-9做乘法运算只有5乘偶数才能得到0
其次5与任何偶数作乘获得0的十位为1,2,3,4 -->(2,4,6,8)
例 : 5! = (1) * 1*3*4 得到一个尾数0
而且分解的偶数必定多于5的个数
故而求阶乘尾数0的个数实际就变成了阶乘每一项因式分解能得到的5的个数
将n/5就获得了所有因式分解中含有一个5的数的第一个5
继续除5就获得了因式分解中含有两个5的数的第二个5
将这些结果加起来就得到了所有5的个数
5 2*5 3*5 4*5 5*5 6*5 ...
n/5 1 1 1 1 1 1 ...
n/25 0 0 0 0 1 0 ...
.. 0 0 0 0 0 0 ...
具体代码如下 :
1 2 3 4 5 6
| public int trailingZeros(int n){ int result = 0; while((n /= 5) > 0) result += n; return result; }
|
旋转数组
首先移动次数等于数组长度,就复原了
那么移动次数为k%数组长度,若为0则不移动
然后移动k个位置其实就是将前k个元素移动到后面
思路一 :
利用反转,数组反转两次就得到了原数组
那么先反转一次,前面的元素都到了后面
而后面的元素都到前面
然后拿后面的k个元素反转,以及前面的长度-k个元素反转
就得到了符合条件的数组
思路二 :
利用进制运算,进制为数组的长度
将第一个元素移动到它应该在的位置,再将下一个以同样的规律移动
一直循环就能得到符合条件的数组,但是要注意k是长度的约数的情况
原理证明:
利用的反证法,一开始索引为0且一直加k对长度取余
得到的余数集第一个重复的值必定为0
先从0开始 后面的值开始在0的后面 同样的操作必定是0先
如果是约数,会在长度次数之前获得重复值
长度8,k=2 8/2=4次 0..2..4..8(8 % 8=0)
这时候就需要对0...k-1作操作即可交换整个数组所有位置
如果不是约数,由于第一个重复值必定是第一个索引
直接操作长度次数即可