leetcode ——数学题目
69. x 的平方根
实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
解法一:
暴力解法,从0开始遍历,判断这个数的平方是否比x大。
需要考虑的点是开方以后可能是小数,不过这不影响我们暴力破解。只要找到一个开方以后稍大于X的数,这个数-1即为答案/
还有一个问题是,如果用integer类型很有可能整数溢出,所以用long。
另一个防止溢出的方法:把i*i换成i/x
class Solution {
public:
int mySqrt(int x) {
long i;
for(i=0;i*i<=x;i++)if(i*i==x)return i;
return (int)(i-1);
}
};
解法二:
二分法
如果开方是1的话,是不在我们的区间里面0,因为1/2=0,被舍掉了。
class Solution {
public:
int mySqrt(int x) {
if (x == 0) return 0;
if (x < 4)return 1;
int left = 2, right = x / 2, mid = right / 2;
while (left <= right) {
if (mid > x / mid)right = mid - 1;
else if (mid == x / mid)return mid;
else left = mid + 1;
mid = left + (right - left) / 2;
}
return right;
}
};
解法3:
牛顿求根法的原理和公式推导:
class Solution {
public:
int mySqrt(int x) {
double a=x, b=0;
while(abs(b-a)>=1){
b=a;
a=(a+x/a)/2;
}
return (int)a;
}
};
168. Excel表列名称
给定一个正整数,返回它在 Excel 表中相对应的列名称。
解法一:
这个题目还是有一些思路上的困扰,在于取余之前要减一。
顺着十进制取出每位数的思路做这种题,结果不对因为不是从0开始的。十进制是0-9,所以除10取余得到个位数。
本题中,为了得到最后一位数,如果除27取余,就会错乱。除26合理,但是得到0-25,最大的26A取余后是0在最前面,而且26/26是1.,有了一个进位。
所以我想到的办法是n-1,吧1-26变为0-26,这样可以从容地除26取余,也可以顺利的得到后面各位的数。
用十进制类比,本题相当于十进制,但是是1-10十个数而非0-9.
class Solution {
public:
string convertToTitle(int n) {
string s;
while (n != 0) {
int i = --n % 26;
n /= 26 ;
char c = 'A' + i ;
s = c+s;
}
return s;
}
};
171. Excel表列序号
给定一个Excel表格中的列名称,返回其相应的列序号。
解法一:
class Solution {
public:
int titleToNumber(string s) {
int sum=0, i=0;
while(i<s.size())
sum= sum*26+(s[i++] - 'A' + 1);
return sum;
}
};
解法二:
直接用pow函数算26的幂再相乘。
class Solution {
public:
int titleToNumber(string s) {
int sum=0, i=0;
while(i<s.size())
sum+= (s[i] - 'A' + 1)*pow(26,s.size()-1-(i++));
return sum;
}
};
172. 阶乘后的零
给定一个整数 n,返回 n! 结果尾数中零的数量。
如果算一个数的阶乘,稍微大点的数用int或者long来存就会溢出。
这也敢叫简单题?
解法一:
通过数学分析找规律,发现只要阶乘的数里有一个5,最后的结果就会有一个0.因为5前面一定有个2,而10可以分解为5*2;
所以问题转化为,n, n-1, n-2……3, 2, 1这些数里5的个数。
从n开始遍历,如果n里有5这个因数,那么n%5==0是真的,在内层循环找到n里所有的5.本思路代码如下:
class Solution {
public:
int trailingZeroes(int n) {
int num=0;
for(;n>0;n--)
for(int a= n;a%5==0;a/=5)num++;
return num;
}
};
但是问题是本思路用时很长,如果有一个很大的数要循环很多次。
解法二:
5是每5个数出现一次,123…10这十个数中5的个数就是10/2.
但是考虑到,每5个5就多一个因数无,也就是n=25时,1234……24 25并不是25/5=5个5,25中有两个5,125中有3个……
class Solution {
public:
int trailingZeroes(int n) {
int num=0;
for(;n>0;n/=5) num+=n/5;
return num;
}
};
202. 快乐数
一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为> 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。
解法一:
这也是一个找规律题目,但是如果找不到规律,就暴力破解一下。
在一定的迭代次数,能不能得到1.
为了计算快乐数,每次对十取余、/10得到最后一位,直到除的只剩了0.
class Solution {
public:
bool isHappy(int n) {
int m=0;
for(int i=10;i>0&&m!=1;i--,n=m)
for(m=0;n>0;n/=10) m+=(n%10)*(n%10);
return m==1;
}
};
解法二:
如果是无限循环的,那么每次迭代得到的结果一定会有重复。每次计算得到的值,如果在之前的计算中出现过,那么就一定不是快乐数。
使用set来完成这个统计,count() 用来查找set中某个某个键值出现的次数,set中的值都是不重复的,一个键值在set只可能出现0或1次。
class Solution {
public:
bool isHappy(int n) {
set<int>s;
int m=n;
while(s.count(m)!=1&&m!=1){
s.insert(m);
for(m=0;n>0;n/=10) m+=(n%10)*(n%10);
n=m;
}
return m==1;
}
};
解法三:
判断有没有环可以用快慢指针的方法。在每次循环中,快指针计算一次数的平方和,然后再计算一次,而慢指针只计算一次。
如果快指针能够追上慢指针,那么说明有环的存在,也就是这个数会一直无限循环下去。
class Solution {
public:
bool isHappy(int n) {
int fast=n, slow=n;
do{
fast=f(fast);
fast=f(fast);
slow=f(slow);
}while(slow!=fast);
return fast==1;
}
int f(int n){
int m=0;
for(m=0;n>0;n/=10) m+=(n%10)*(n%10);
return m;
}
};
204. 计数质数
统计所有小于非负整数 n 的质数的数量。
解法一,暴力破解
,但是数太大了就会超时。
~~class Solution {
public:
int countPrimes(int n) {
set<int>s;
s.insert(0);
s.insert(1);
for(int i=2; i<n; i++)
for(int j=i; j<n; j++){
s.insert(i*j);
if(i*j>n){
break;
i=n;
}
}
int num=0;
for(n=n-1;n>1;n--)if(s.count(n)==0)num++;
return num;
}
};~~
解法二:
埃拉托色尼筛选法
class Solution {
public:
int countPrimes(int n) {
int count = 0;
vector<bool> s(n, true);
for (int i = 2; i < n; i++) {
if (s[i]) {
count++;
for (int j = i *2; j < n; j += i) s[j] = false;
}
}
return count;
}
};
231. 2的幂
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
解法一:
思路是,如果一个数是2的幂,那么这个数一直除2,一定会变成2(除非是2^0=1)
2/2一定为1.
class Solution {
public:
bool isPowerOfTwo(int n) {
while(n%2==0&&n!=0) n/=2;
return n==1;
}
};
解法二:
位运算,如果一个数n2的幂, 那么他的二进制一定是最高位为1,后面全是0.所以n-1是最高位为0,后面全是1,这样做位运算的与就是0.
要处理的特殊情况是为0或者小于0.