2018年力扣高頻算法面試題1數學&位運算

友鏈

在這裏插入圖片描述

在這裏插入圖片描述

1、只出現一次的數字

給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
要求:線性時間複雜度、不使用額外空間
解答:典型的位運算,相同的兩個數異或爲0,擴展形式爲,找出給定非空整數數組中只出現一次的兩個整數。

int singleNumber(vector<int>& nums) {
        int ans=nums[0];
        for(int i=1;i<nums.size();i++)
        {
            ans^=nums[i];
        }
        return ans;
    }

2、直線上最多的點數【需二刷】

參考

給定一個二維平面,平面上有 n 個點,求最多有多少個點在同一條直線上。
特殊情況:①是當兩個點重合時,無法確定一條直線,但這也是共線的情況,需要特殊處理。②是斜率不存在的情況,由於兩個點 (x1, y1) 和 (x2, y2) 的斜率k表示爲 (y2 - y1) / (x2 - x1),那麼當 x1 = x2 時斜率不存在,這種共線情況需要特殊處理。
哈希表:記錄斜率和共線點個數之間的映射,其中第一種重合點的情況我們假定其斜率爲 INT_MIN,第二種情況我們假定其斜率爲 INT_MAX,這樣都可以用 map 映射了。

class Solution {
public:
    int maxPoints(vector<vector<int>>& points) {
        int res = 0;
        for (int i = 0; i < points.size(); ++i) {
            int duplicate = 1;
            for (int j = i + 1; j < points.size(); ++j) {
                int cnt = 0;
                long long x1 = points[i][0], y1 = points[i][1];
                long long x2 = points[j][0], y2 = points[j][1];
                if (x1 == x2 && y1 == y2) {++duplicate; continue;}
                for (int k = 0; k < points.size(); ++k) {
                    int x3 = points[k][0], y3 = points[k][1];
                    if (x1 * y2 + x2 * y3 + x3 * y1 - x3 * y2 - x2 * y1 - x1 * y3 == 0) {
                        ++cnt;
                    }
                }
                res = max(res, cnt);
            }
            res = max(res, duplicate);
        }
        return res;
    }
};

3、分數到小數【需二刷】

參考

給定兩個整數,分別表示分數的分子 numerator 和分母 denominator,以字符串形式返回小數。如果小數部分爲循環小數,則將循環的部分括在括號內。
①循環體出現的標誌是什麼?我們研究一下1/6。
最開始補零,變成10/6,寫成0.1,這時候餘數是4。
餘數4再去除以6,變成40/6,寫成0.16,這時候餘數是4,。
餘數4再去除以6……
這個時候我們都知道接下來必定是循環體結構了,因爲出現了相同的被除數。
所以我們不能把兩個整數變成double類型,直接相除,而是應該不斷地整數相除,記錄餘數,餘數再去除以除數。
在這個過程中記錄餘數,如果出現了重複的餘數,那麼必定是循環體結構了。
②邊界條件,比如-2147483648/-1,-1/-2147483648,7/-12等等。

string fractionToDecimal(int numerator, int denominator) 
    {
        if(numerator==INT_MIN&&denominator==-1)//邊界條件,沒法直接除,因爲除完結果溢出
        return "2147483648";
        if(numerator==-1&&denominator==INT_MIN)//邊界條件,都是int類型,沒法除
        return "0.0000000004656612873077392578125";
        int shang=numerator/denominator,yushu=numerator%denominator;//記錄商和餘數
        string res;//最終要返回的string
        if(double(numerator)/double(denominator)<0)//如果兩個數一正一負
        {
            if(shang==0)//如果商爲0
                res='-'+to_string(abs(shang));//可能有的同學疑惑爲什麼要這樣處理,比如7/-12,除完shang爲0,但是我們要的是-0
            else
                res=to_string(shang);//如果不爲0,那麼直接處理
        }
        else//如果都是正數或者都是負數
            res=to_string(shang);//直接處理
        if(yushu==0)//如果餘數爲0,那麼到此爲止,返回res就可以了
            return res;
        res+='.';//如果還有餘數,那麼要加個小數點
        unordered_map<int,int>record;//記錄出現過的餘數和餘數除以除數得到的商的位置
        while(yushu!=0)
        {
            yushu=abs(yushu);//餘數有可能是負的,全都轉爲正數
            denominator=abs(denominator);//除數也轉爲正數
            yushu*=10;//餘數乘10,作爲新的被除數
            if(record.count(yushu))//如果之前出現過了這個餘數,那麼可以取出循環體了
            {
                int start=record[yushu],end=res.size()-1;//start和end表示循環體的開端和末尾
                res=res.substr(0,start)+'('+res.substr(start,end-start+1)+')';//加一下括號
                return res;//直接返回
            }
            record[yushu]=res.size();//如果沒出現過,那麼記錄在record中,value是這個餘數除以除數得到的商應該放的位置
            shang=yushu/denominator;//更新商
            yushu=yushu%denominator;//更新餘數
            res+=to_string(shang);//加入最新的商
        }
        return res;//如果一直沒有出現重複的餘數,那麼最終跳出循環後直接返回res
    }

4、階乘後的零

給定一個整數 n,返回 n! 結果尾數中零的數量。
要求:時間複雜度應爲 O(log n)。
思路:1~n之間有多少5的倍數。

class Solution {
public:
    int trailingZeroes(int n) {
        int res = 0;
        while(n){
            n /= 5;
            res += n;
        }
        return res;
    }
};

5、缺失數字

給定一個包含 0, 1, 2, …, n 中 n 個數的序列,找出 0 … n 中沒有出現在序列中的那個數。
要求:算法應具有線性時間複雜度,僅使用額外常數空間來實現。
不缺失數字時候的和可以計算,缺失數字之後的和遍歷一遍也可以計算出來,二者相減就是缺失的數字.

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int res=nums.size();
        for(int i=0;i<nums.size();i++)
        {
            res +=(i-nums[i]);
        }
        return res;
    }
};

6、3的冪

給定一個整數,寫一個函數來判斷它是否是 3 的冪次方。
進階:你能不使用循環或者遞歸來完成本題嗎?

class Solution {
public:
    bool isPowerOfThree(int n) {
        if(n == 0) return false;
        while(n%3 == 0) n /= 3;
        if(n == 1) return true;
        return false;
    }
};

7、顛倒二進制位【需二刷】

顛倒給定的 32 位無符號整數的二進制位。
進階:如果多次調用這個函數,你將如何優化你的算法?

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t res = 0;
        for (int i = 0; i < 32; ++i) {
            if (n & 1 == 1) {  // 最後一位爲1
                res = (res << 1) + 1;
            } else {
                res = res << 1;
            }
            n = n >> 1;
        }
        return res;
    }
};

補充題目

Sum of Two Integers

Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
由於異或是相同則位0,不同則位1,因此我們可以把異或看成是一種不進位的加減法
由於與是全部位1則位1,否則位0,因此我們可以求與之後左移一位來表示進位

class Solution {
public:
    int getSum(int a, int b) {
        long long carry; // 64-bit
        while (b != 0) {
            carry = a & b;
            a = a ^ b;
            b = ((carry & 0xffffffff) << 1); // limited to 32 bits
        }
        return a;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章