leetcode解題思路分析(二十六)187 - 192題

  1. 重複的DNA序列
    編寫一個函數來查找 DNA 分子中所有出現超過一次的 10 個字母長的序列(子串)。
class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) 
    {
        //對應二進制00, 01, 10, 11.那麼10個組合只要20位就夠了。
        unordered_map<char, int> m{{'A', 0}, {'C', 1}, {'G', 2}, {'T', 3}};
        vector<string> res;
        bitset<1 << 20> s1, s2; //那麼所有組合的值將在0到(1 << 20 - 1)之間
        int val = 0, mask = (1 << 20) - 1; //mask等於二進制的20個1
        //類似與滑動窗口先把前10個字母組合
        for (int i = 0; i < 10; ++i) val = (val << 2) | m[s[i]];
        s1.set(val); //置位
        for (int i = 10; i < s.size(); ++i)
        {
            val = ((val << 2) & mask) | m[s[i]]; //去掉左移的一個字符再加上一個新字符
            if (s2.test(val)) continue; //出現過兩次跳過
            if (s1.test(val))
            {
                res.push_back(s.substr(i - 9, 10));
                s2.set(val);
            }
            else s1.set(val);
        }
        return res;
    }
};
  1. 買賣股票的最佳時機4
    給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。
    設計一個算法來計算你所能獲取的最大利潤。你最多可以完成 k 筆交易。
    注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。

本題採用動態規劃求解,和前面幾題的區別在於需要考慮k。如果K比較多支持每天都在買和賣,則直接累加,否則需要考慮哪天賣出最划算

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if(!prices.size()) return 0;
        if(k >= prices.size()/2)
        {
            int maxsumval = 0;
            for(int i = 1; i < prices.size(); i++)
                if(prices[i] > prices[i - 1])
                    maxsumval += prices[i] - prices[i - 1];
            return maxsumval;
        }
        vector<int> dp(k + 1, 0);
        vector<int> v(k + 1, prices[0]);
        for(int i = 1; i < prices.size(); i++)
        {
            for(int t = 1; t <= k; t++)
            {
                v[t] = min(v[t], prices[i] - dp[t - 1]);
                dp[t] = max(dp[t], prices[i] - v[t]);  
            }
        } 
        return dp[k];
    }
};


  1. 旋轉數組
    給定一個數組,將數組中的元素向右移動 k 個位置,其中 k 是非負數。

首先將所有元素反轉。然後反轉前 k 個元素,再反轉後面 n-kn−k 個元素,就能得到想要的結果。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        reverse(nums.begin(), nums.end() - k % nums.size());
        reverse(nums.end() - k % nums.size(), nums.end());
        reverse(nums.begin(), nums.end());
    }
};

  1. 顛倒二進制位
    顛倒給定的 32 位無符號整數的二進制位。

首先,我們將原來的 32 位分爲 2 個 16 位的塊。
然後我們將 16 位塊分成 2 個 8 位的塊。
然後我們繼續將這些塊分成更小的塊,直到達到 1 位的塊。
在上述每個步驟中,我們將中間結果合併爲一個整數,作爲下一步的輸入。

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        n = (n >> 16) | (n << 16);
        n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);
        n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4);
        n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2);
        n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1);
        return n;
    }
};

  1. 位1的個數
    編寫一個函數,輸入是一個無符號整數,返回其二進制表達式中數字位數爲 ‘1’ 的個數

最簡單的方法就是逐位檢查

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ret = 0;
        while(n)        
        {
            if (n & 1) ret++;
            n >>= 1;
        }
        return ret;
    }
};

在二進制表示中,數字 nn 中最低位的 11 總是對應 n - 1n−1 中的 00 。因此,將 nn 和 n - 1n−1 與運算總是能把 nn 中最低位的 11 變成 00 ,並保持其他位不變。


class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;

        while(n > 0)
        {
            n &= (n - 1);
            ++count;
        }

        return count;
    }
};


  1. 統計詞頻
    寫一個 bash 腳本以統計一個文本文件 words.txt 中每個單詞出現的頻率。

本題其實分兩步,第一步是單次分割,第二步是將分割的單次進行統計。

單次分割可以使用awk或者catxargs實現

awk '{for(i=1;i<=NF;i++){print $i}}' words.txt 

cat words.txt | xargs -n1

使用awk命令來完成這個任務的話很簡單,在進行分割的過程中直接用一個關聯數組直接保存每一個單詞出現的次數

awk '{for(i=1;i<=NF;i++){asso_array[$i]++;}};END{for(w in asso_array){print w,asso_array[w];}}' words.txt

使用cat + xargs的話需要使用sort以及uniq實現

cat words.txt | xargs -n1 | sort | uniq -c

最終代碼

awk '{for(i=1;i<=NF;i++){asso_array[$i]++;}};END{for(w in asso_array){print w,asso_array[w];}}' words.txt | sort -rn -k2

cat words.txt | xargs -n1 | sort | uniq -c | sort -rn | awk '{print $2,$1}'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章