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;
        }
    };
posted @ 2013-03-19 15:51 一叶斋主人 阅读(...) 评论(...) 编辑 收藏