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.