①阶乘后的零
示例 1:
输入: 3 输出: 0 解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5 输出: 1 解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
1.计算阶乘之后零的个数,也即计算阶乘中包含5的个数,对于25、125这样的可能包含多个5,需要注意一下:
class Solution {
public:
int trailingZeroes(int n) {
int cnt = 0;
while (n)
{
cnt += n/5;
n /= 5;
}
return cnt;
}
};
2.利用递归,将上述思路写成递归:
class Solution {
public:
int trailingZeroes(int n) {
return n == 0 ? 0 : (n/5) + trailingZeroes(n/5);
}
};
②旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入:[1,2,3,4,5,6,7]
和 k = 3 输出:[5,6,7,1,2,3,4]
解释: 向右旋转 1 步:[7,1,2,3,4,5,6]
向右旋转 2 步:[6,7,1,2,3,4,5]
向右旋转 3 步:[5,6,7,1,2,3,4]
示例 2:
输入: [-1,-100,3,99]
和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的原地算法。
1.遍历数组,从0遍历到n-k(n为数组长度),将首部元素插入到容器尾部,并删除首部元素,依次遍历,实现旋转数组:
具体实现:
输入数组:[1,2,3,4,5,6,7], k = 3
第一轮:数组[2,3,4,5,6,7,1]
第二轮:数组[3,4,5,6,7,1,2]
第三轮:数组[4,5,6,7,1,2,3]
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if (nums.empty() || (k %= nums.size()) == 0) //如果容器为空或旋转步数大于数组长度返回空
return;
int n = nums.size();
for (int i = 0; i < n-k; ++i)
{
nums.push_back(nums[0]); //将数组首元素插入到容器尾
nums.erase(nums.begin()); //删除容器首元素
}
}
};
2.调用标准库算法reverse,首先将数组中旋转步数之外的元素进行翻转,然后把旋转步数之内的元素进行翻转,最后将前两步得到的数组整体翻转,得到旋转数组:
具体实现:
输入数组:[1,2,3,4,5,6,7]
第一步:数组:[4,3,2,1,5,6,7]
第二步:数组:[4,3,2,1,7,6,5]
第三步:数组:[5,6,7,1,2,3,4]
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if (nums.empty() || (k %= nums.size()) == 0)
return;
int n = nums.size();
reverse(nums.begin(), nums.begin() + n-k); //翻转前半部分
reverse(nums.begin() + n-k, nums.end()); //翻转后半部分
reverse(nums.begin(), nums.end()); //翻转整个数组
}
};
3.用数组初始化得到一个新数组t,保存当前元素,然后通过映射将原元素值存入数组的对应位置中(t中i对应nums中(i + k) %n):
具体实现:
输入数组:[1,2,3,4,5,6,7]
例:i = 0时,对应存入数组(i + k) % n位置,即第3位
按照这样的映射关系得到旋转数组
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if (nums.empty() || (k %= nums.size()) == 0)
return;
vector<int> t = nums; //保存原数组元素
int n = nums.size();
for (int i = 0; i < n; ++i)
{
nums[(i + k) % n] = t[i]; //将元素通过映射存入原数组
}
}
};