目录
前言:
7. 整数反转 - 力扣(LeetCode)
面试题 16.05. 阶乘尾数 - 力扣(LeetCode)
总结;
前言:
今天仍然是无固定类型刷题,
7. 整数反转 - 力扣(LeetCode)
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
第一种思路:无脑拆解这个数组,然后利用reverse函数进行翻转后暴力相乘,在这期间特殊处理所有的特殊数字就可以,是一种效率最低的方法。
public:
int reverse(int x) {
vector<int> d1;
int a=0;
int judge=0;
if(x==-2147483648)
{
return 0;
}
if(x<0)
{
judge=1;
a=-x;
}
else
{
a=x;
}
while(a>0)
{
d1.push_back(a%10);
a=a/10;
}
::reverse(d1.begin(),d1.end());
long long int sum=0;
for(int i=0;i<d1.size();i++)
{
sum=sum+(d1[i]*pow(10,i));
}
if(judge==1)
{
sum=-sum;
}
if (-2147483648 < sum && sum < 2147483647)
{
return (int)sum;
}
return 0;
}
};
第二种思路:
我们不需要将所给的数字拆分后再反转,然后再乘,可以直接就拆分相乘,然后对每一次得到的新数字进行判断是否溢出。
class Solution {
public:
int reverse(int x) {
int res = 0;
while (x) {
int digit = x % 10; // 取最后一位数字
x /= 10; // 去掉最后一位数字
// 判断乘10之前是否会溢出
if (res > INT_MAX / 10 || (res == INT_MAX / 10 && digit > 7)) {
return 0;
}
if (res < INT_MIN / 10 || (res == INT_MIN / 10 && digit < -8)) {
return 0;
}
res = res * 10 + digit; // 将最后一位数字加到结果中
}
return res;
}
};
我们着重解释一下这两个if判断句:
这段代码的作用是判断在每次将数字的最后一位加到结果中之前,是否会发生溢出现象。
由于最终的结果需要在int
类型的有符号范围内,所以在判断当前结果res
加上最后一位数字后是否会越界时,需要判断已经累加的结果res
是否在INT_MAX / 10
和INT_MIN / 10
的范围内。对于任何一个已经加入结果中的数字,如果加上下一位数字后会超过INT_MAX
或者INT_MIN
,那么结果一定会越界,这时就需要返回0。
对于正整数,如果加上最后一位数字后越界,那么最后一位数字一定不小于8,因为INT_MAX / 10等于214748364,所以INT_MAX / 10乘以10的结果是2147483640,而8乘以任何数一定小于等于80,所以如果最后一位数字是8或者更大的数,结果就一定会越界。
对于负整数,如果加上最后一位数字后越界,那么最后一位数字一定不大于-8,因为INT_MIN / 10等于-214748364,所以INT_MIN / 10乘以10的结果是-2147483640,而-8乘以任何数一定不大于-80,所以如果最后一位数字是-8或者更小的数,结果就一定会越界。
面试题 16.05. 阶乘尾数 - 力扣(LeetCode)
设计一个算法,算出 n 阶乘有多少个尾随零。
这道题很多下意识的会采用求出阶乘结果之后再逐个判断的方式进行,但是这种方式存在一个问题:有的数字的阶乘结果都已经超出了int表示的范围,甚至是long lon int也不能容纳,这个时候又有人想到了用数组存储数字,示例:
vector<int> factorial(int n) {
vector<int> res(1, 1); // 初始化数组为1
for (int i = 2; i <= n; i++) { // 从2开始逐个计算
int carry = 0;
for (size_t j = 0; j < res.size(); j++) { // 从低位到高位逐位计算
int num = res[j] * i + carry; // 乘积加上上一次的进位
res[j] = num % 10; // 将当前位结果存回数组
carry = num / 10; // 计算新的进位
}
while (carry > 0) { // 如果最高位仍有进位,需要往数组插入新的位
res.push_back(carry % 10);
carry /= 10;
}
}
reverse(res.begin(), res.end()); // 将数组反转,转换成正序
return res;
}
但是这些都太过于复杂。本题其实就是一个脑筋急转弯。
数末尾0其实很简单,有几个因子10,就有几个末尾0。而10又可以拆成2和5,在阶乘中2的数量一定大于5的数量,因此我们数5就可以了。有几个5就有几个10.
但因为25和其倍数,如25*2.。。。里面都有两个5,所以遇到25和倍数都要+2;
同理125和其倍数,里面有3个5,所以遇到125和其倍数要+3;
因为25是5的倍数,125是25的倍数,
也就是说25,125的倍数都和5的倍数是重叠的;
所以从n/5开始,然后+n/25,+n/125,依次类推,这样就等于进行叠加了,不用额外考虑什么情况+2,什么情况+3...的问题;
class Solution {
public:
int trailingZeroes(int n) {
int count = 0;
while(n >= 5){
n /= 5;
count += n;
}
return count;
}
};
总结;
并不是所有的题都要依靠算法的思维逻辑来解决,有的时候我们不能钻牛角尖,总是试图找出一个可以套用的算法。