leetcode刷題筆錄-1


1. 回文分割

  • 給定一個字符串s,將s分割為數個子串,每個子串都是回文。
    比如,給定字符串"aab",返回:
    [
        ["aa","b"],
        ["a","a","b"]   
    ]
  • 思路:遞歸法,子串 s[i]...s[j] 的所有回文分割,都是由 s[1] 單獨構成的一個元素的子串連接上 s[2]...s[j] 的所有回文分割(子問題),以及任何一個回文子串 s[1]...s[k] 連接上上 s[k+1]...s[j] 的回文分割(子問題)
  • 實現:
    class Solution {
    public:
        vector<vector<string>> partition(string s);
    private:
        vector<vector<string>> _partition(const string& s, const int i, const int j);
        vector<string> addhead(const vector<string>& list, const string& head);
        bool isPal(const string& s, const int i, const int j);
        vector<vector<int>> pals;
    };
    
    vector<vector<string>> Solution::partition(string s) {
        int n = s.size();
        pals = vector<vector<int>>(n, vector<int>(n, 0));
        return _partition(s, 0, n-1);
    }
    
    vector<vector<string>> Solution:: _partition(const string& s, const int i, const int j){
        vector<vector<string>> list;
        if(i==j){
            string tmp(1, s[i]);
            list.push_back(vector<string>(1, tmp));
            return list;
        }
        for(int p=i; p<j; p++){
            if(isPal(s,i,p)){
                vector<vector<string>> _list = _partition(s, p+1, j);
                string _head = s.substr(i,p-i+1);
                for(int k=0; k<=_list.size()-1; k++){
                    vector<string> tmp = addhead(_list[k],_head);
                    list.push_back(tmp);
                }
            }
        }
        if(isPal(s,i,j)){
            list.push_back(vector<string>(1, s.substr(i,j-i+1)));
        }
        return list;
    }
    
    vector<string> Solution::addhead(const vector<string>& list, const string& head){
        vector<string> rs;
        rs.push_back(head);
        for(int i=0; i<=list.size()-1; i++){
            rs.push_back(list[i]);
        }
        return rs;
    }
    
    bool Solution::isPal(const string& s, const int i, const int j){             
        if(i>=j){
            return true;
        }
        if(pals[i][j]!=0){
            return pals[i][j]>0 ? true : false;
        }    
        if(s[i]==s[j]){
            bool _isPal = isPal(s, i+1, j-1);
            pals[i][j] = _isPal ? 1 : -1;
            return _isPal;
        }
        else{
            pals[i][j] = -1;
            return false;
        }
    }  

2. 回文分割2

  • 給定一個字符串s,將s分割為數個子串,每個子串都是回文。
    返回將字符串回文分割最少分割次數。
    比如,給定字符串"aab",返回1,因為分割["aa","b"]可由一個分割(逗號)生成。
  • 思路:動態規划,維護兩個二維表,分別表示子串 s[i]...s[j] 是否是回文,以及最少回文分割次數(如果子串本身是回文,這個域就是0)。子串的最小回文分割次數就是 s[i]...s[k] 和 s[k+1]...s[j] 的最小回文分割次數之和(兩個子問題的和)加1,在區間[i,j]取一個k值使該結果最小。
  • 實現:
    class Solution {
    public:
        int minCut(string s);
    
    private:
        int _minCut(const string& s, const int i, const int j);    
        bool isPal(const string& s, const int i, const int j);
        
        vector<vector<int>> mcTable;
        vector<vector<int>> isPalTable; // 1 for true, -1 for false, 0 for uncertain
    };
    
    int Solution::minCut(string s){
        int n = s.size();
        mcTable = vector<vector<int>>(n, vector<int>(n,-1));
        isPalTable = vector<vector<int>>(n, vector<int>(n, 0));
        return _minCut(s, 0, n-1);
    }
    
    int Solution::_minCut(const string& s, 
                            const int i, 
                            const int j){
                        
        if(mcTable[i][j] != -1){
            return mcTable[i][j];
        }
        else{
            if(isPal(s,i,j)){
                mcTable[i][j]=0;
                return 0;
            }
            else{
                int min = INT_MAX;
                for(int k=i; k<=j-1; k++){
                    int cutNums = _minCut(s,i,k) + _minCut(s,k+1,j) + 1;
                    if(cutNums<min){
                        min = cutNums;
                    }
                }
                mcTable[i][j]=min;
                return min;
            }
        }
    }
    
    bool Solution::isPal(const string& s,
                            const int i, 
                            const int j){
                                
        if(i>=j){
            return true;
        }
        if(isPalTable[i][j] != 0){
            return isPalTable[i][j]>0 ? true : false;
        }
        else{
            if(s[i]!=s[j]){
                isPalTable[i][j]=-1;
                return false;
            }
            else{
                if(isPal(s,i+1,j-1)){
                    isPalTable[i][j]=1;
                    return true;
                }
                else{
                    isPalTable[i][j]=-1;
                    return false;
                }
            }
        }
    }

3. 圍棋

  • 給定一塊二維棋盤,每一個格子要么是'X'要么是'O'。將所有被'X'圍起來(像圍棋一樣圍起來)'O',都轉變為'O'。
    比如,給定:
    X X X X
    X O O X
    X X O X
    X O X X

    返回:

    X X X X
    X X X X
    X X X X
    X O X X
  • 思路:四條邊上的'O'是不會被圍起來的,與他們相鄰的'O'也不會被圍起來。該性質可以傳遞下去,類似於“感染”。那么就將四邊上的'O'感染為'A',再遞歸地感染相鄰的'O',完成之后將未被感染的'O'轉為'X',再將'A'轉為'O'。
  • 實現:
    class Solution {
    public:
        void solve(vector<vector<char>> &board);
    private:
        void infect(vector<vector<char>>& board, int i, int j);
    };
    
    void Solution::solve(vector<vector<char>> &board) {
        int n = board.size();
        if(n==0){
            return;
        }
        int m = board[0].size();
        for (int i=0; i<=n-1; i++){
            if (board[i][0]=='O'){
                infect(board, i, 0);
            }
            if (board[i][m-1]=='O'){
                infect(board, i, m-1);
            }
        }
        for (int j=0; j<=m-1; j++){
            if (board[0][j]=='O'){
                infect(board, 0, j);
            }
            if (board[n-1][j]=='O'){
                infect(board, n-1, j);
            }
        }
    
        for (int i=0; i<=n-1; i++){
            for (int j=0; j<=m-1; j++){
                if (board[i][j]=='O'){
                    board[i][j]='X';
                }
            }
        }
    
        for (int i=0; i<=n-1; i++){
            for (int j=0; j<=m-1; j++){
                if (board[i][j]=='A'){
                    board[i][j]='O';
                }
            }
        }
    }
    
    void Solution::infect(vector<vector<char>>& board, int i, int j){
        board[i][j] = 'A';
        int n = board.size();
        int m = board[0].size();
        if(i!=0 && board[i-1][j]=='O'){
            infect(board, i-1, j);
        }
        if(i!=n-1 && board[i+1][j]=='O'){
            infect(board, i+1, j);
        }
        if(j!=0 && board[i][j-1]=='O'){
            infect(board, i, j-1);
        }
        if(j!=m-1 && board[i][j+1]=='O'){
            infect(board, i, j+1);
        }
    }

4. “根-葉”數之和

  • 給定一個二叉樹,每個樹的節點值都為 0~9 的整數。每一個從根節點到葉節點的路徑代表一個整數。
    比如,路徑 1-2-3 代表整數 123。找到二叉樹所有從根節點到葉節點的路徑的“根-葉”數之和。
    比如,給定:
        1
       / \
      2   3

     1-2路徑表示12,1-3路徑表示13,那么應當返回12+13=25。

  • 思路:進入每一棵子樹時,傳入一個從根節點開始累積的值,到達葉節點后將改值加到全局變量sum上,如路徑 1-2-3 : 1-(1)-2-(12)-3(123)-sum+=123。這樣就仍可以自然地進行遞歸迭代,而不用寫二叉樹的迭代遍歷。
  • 實現:
    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int sumNumbers(TreeNode *root) {
            sum = 0;
            _sumNumbers(root, 0);
            return sum;
        }
    private:
        void _sumNumbers(TreeNode* root, int rootVal){
            if (root==NULL){
                return;
            }
            int val = rootVal*10+root->val;
            if (root->left==NULL && root->right==NULL){
                sum += val;
            }
            _sumNumbers(root->left, val);
            _sumNumbers(root->right, val);
        }
        int sum;
    }; 

5. 最長連續序列

  • 給定一個未排序的整數數組,找到最長連續序列的長度。
    比如,給定[100,4,200,1,3,2],應當返回4,因為最長連續序列為[1,2,3,4],其長度為4。
    算法的時間代價應當為O(n)。
  • 思路:規定了O(n)的時間復雜度,想到使用哈希表。使用哈希集合st來濾掉重復的元素,哈希表mp中維護着這樣的結構:所有已考慮的元素組成的連續序列的兩端,鍵為兩端的位置,值為另一端的位置。如果序列僅有一個元素(如考慮第一個元素時),則兩端都是它自身,它的值指向它自己。由於st的幫助,所有新考慮的值都不會出現在連續序列中。
  • 實現:
    class Solution {
    public:
        int longestConsecutive(vector<int> &num) {
            hash_map<int, int> mp;
            hash_set<int> st;
            int max = 0;
            for (int i=0; i<=num.size()-1; i++){
                if (st.find(num[i])!=st.end()){
                    continue;
                }
                st.insert(num[i]);
                int tleft = num[i];
                int tright = num[i];
                if (mp.find(tleft-1)!=mp.end()){
                    tleft = mp[tleft-1];
                }
                if (mp.find(tright+1)!=mp.end()){
                    tright = mp[tright+1];
                }
                int len = tright-tleft+1;
                max = max<len ? len : max;
                mp[tleft] = tright;
                mp[tright] = tleft;
            }
            return max;
        }
    };


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM