小白 刷題 入門 leetcode (五) 數學題目 簡單 C++

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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章