现在的位置: 首页 > 综合 > 正文

【lintcode】树形数据结构之Maxtree, Tree iterator, remove bst node, 优先队列之动态中位数Median, 矩阵dfs之word search II,最大连

2018年04月12日 ⁄ 综合 ⁄ 共 7701字 ⁄ 字号 评论关闭

解析

max ksubarray sum:  最大和 of 连续子序列 =>   最大和 of  k份连续子序列 属于dp,30行代码搞定,注意一些边界。
substr diff:  无queue的区间滑动窗口,记录当前最大值

maxtree:

九章算法中有讲到, 对每个节点,找到离他最近且比它大的左右两个节点中较小的那个,作为他的父节点。

其中,找父节点: 用递增栈分别从左向右和从右向左扫描一次,对每个节点取栈顶元素即可。 在O(n)时间里就可以找到距离该节点最近的比他大的节点。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param A: Given an integer array with no duplicates.
     * @return: The root of max tree.
     */
    TreeNode* maxTree(vector<int> A) {
        // write your code here
        int n = A.size();

        // allocate tree
        TreeNode * nodes = new TreeNode[n];
        for(int i =0; i<n; i++){
            nodes[i] = TreeNode(A[i]);
        }

        // obtain the left/right nearest larger node
        stack<int> ss;
        vector<int> lp(n, -1), rp(n, -1);
        for(int i =0; i<n; i++){
            while(!ss.empty() && A[i]>A[ss.top()]){
                ss.pop();
            }
            if(!ss.empty()){
                lp[i] = ss.top();
            }
            ss.push(i);
        }
        ss=stack<int>();
        for(int i =n-1; i>=0; i--){
            while(!ss.empty() && A[i]>A[ss.top()]){
                ss.pop();
            }
            if(!ss.empty()){
                rp[i] = ss.top();
            }
            ss.push(i);
        }

        // construct tree
        TreeNode * root = NULL;
        for(int i = 0; i<n; i++){
            if(lp[i]>=0 && (rp[i]<0 || A[rp[i]]>A[lp[i]])){
                nodes[lp[i]].right = &nodes[i];
            }
            else if(rp[i]>=0 && (lp[i]<0 || A[lp[i]]>A[rp[i]])){
                nodes[rp[i]].left =  &nodes[i];
            }else{
                root = &nodes[i];
            }
        }
        return root;
    }
};

tree iterator: 

实质:找一个节点的中序下一个节点。
用dfs(root, p) 在root树中,找p的下一个节点。 代价是O(logn)
如果要O(1)的时间代价,需要一个栈(空间O(logn))保存当前的路径(root ->xx -> p)。
/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 * Example of iterate a tree:
 * Solution iterator = new Solution(root);
 * while (iterator.hasNext()) {
 *    TreeNode node = iterator.next();
 *    do something for node
 * } 
 */
public class Solution {
    TreeNode  r;
    TreeNode  p;
    boolean org;
    //@param root: The root of binary tree.
    public Solution(TreeNode root) {
        // write your code here
        r = p = root;
        if(p!=null) while(p.left != null) p=p.left;
        org = true;
    }

    //@return: True if there has next node, or false
    public boolean hasNext() {
        // write your code here
        TreeNode q = p;
        if(!org) q = dfs(r, p);
        return q != null;
    }
    
    //@return: return next node
    public TreeNode next() {
        // write your code here
        if(!org) p = dfs(r, p);
        org = false;
        return p;
    }
    
    private TreeNode  dfs(TreeNode root, TreeNode p){
        if(root == null || p == null) return null;
        if(root.val>p.val){
            TreeNode q= dfs(root.left, p);
            if(q != null) return q;
            else return root;
        }else{
            return dfs(root.right, p) ;
        }
    }
}

动态Median

用一个大顶堆维护较小的一半序列,一个小顶堆维护较大的一半序列。

保持两边序列长度平衡,每次取大顶堆的顶,即为中位数。

class Solution {
public:
    /**
     * @param nums: A list of integers.
     * @return: The median of numbers
     */
    vector<int> medianII(vector<int> &nums) {
        // write your code here
        priority_queue<int> lq;
        priority_queue<int, vector<int>, greater<int> >rq; // top small, bottom bigger
        vector<int> rs;
        for(int i = 0; i<nums.size(); i++){
            if(lq.empty() || nums[i]<=lq.top())
                lq.push(nums[i]);
            else rq.push(nums[i]);
            if(lq.size()>rq.size()+1){
                int t = lq.top();
                lq.pop(), rq.push(t);
            }else if(lq.size()<rq.size()){
                int t = rq.top();
                rq.pop(), lq.push(t);
            }
            rs.push_back(lq.top());
        }
        return rs;
    }
};

remove bst node

这个题目不好写,如果删除一个节点p,先找到他的父节点prt,然后找到他的左子数最大点pre以及父节点preprt,或右子树最小点nxt以及父节点nxtprt,然后用该点pre/nxt替换掉自己就可以了。

指针运算很容易出错地奥! 尤其是当preprt == p的时候, prt==null的时候,都需要注意。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param root: The root of the binary search tree.
     * @param value: Remove the node with given value.
     * @return: The root of the binary search tree after removal.
     */
    TreeNode* removeNode(TreeNode* root, int value) {
        // write your code here
        if(!root) return NULL;
        if(root->val == value ){
            if(root->left){
                TreeNode *t;
                TreeNode *p = preNode(root, &t);

                // remove pre, insert at root
                if(t!=root){
                    t->right = p->left, p->left = root->left;
                }
                p->right = root->right;

                delete root; return p;
            }else if(root->right){
                TreeNode *t;
                TreeNode *p = nxtNode(root, &t);
                if(t!=root){
                    t->left= p->right, p->right = root->right;
                }
                p->left = root->left;
                delete root; return p;
            }else{
                delete root; return NULL;
            }
        }else{
            if(root->val > value){
                root->left = removeNode(root->left, value);
                return root;
            }else{
                root->right =removeNode(root->right, value);
                return root;
            }
        }
    }

    // @param root: no equal to NULL
    // get root's largest smaller sub-node, and its parent
    TreeNode *preNode(TreeNode *root, TreeNode **prt){
        TreeNode *p = root->left; *prt = root;
        if(p) while(p->right) *prt = p, p = p->right;
        return p;
    }
    
    TreeNode *nxtNode(TreeNode *root, TreeNode **prt){
        TreeNode *p = root->right; *prt = root;
        if(p) while(p->left) *prt = p, p = p->left;
        return p;
    }
};

Word Search II

class Solution {
public:
    /**
     * @param board: A list of lists of character
     * @param words: A list of string
     * @return: A list of string
     */
    vector<string> wordSearchII(vector<vector<char> > &board, vector<string> &words) {
        // write your code here
        int m = board.size();
        vector<string> res;
        if(!m) return res;
        int n = board[0].size();
        vector<vector<bool> >visit(m, vector<bool>(n, false));

        dr[0][0] = -1, dr[0][1] = 0, dr[1][0] = 1, dr[1][1] = 0;
        dr[2][0] = 0, dr[2][1] = -1, dr[3][0] = 0, dr[3][1] = 1;
        
        for(int i = 0; i<words.size(); i++){
            for(int j = 0; j<m; j++){
                int k = 0;for( ; k<n; k++){
                    if(dfs(board, words[i], visit, 0, j, k)) {
                        res.push_back(words[i]);
                        break;
                    }
                }
                if(k<n) break;
            }
        }
        
        return res;
    }
    int dr[4][2] ;//= {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    bool dfs(vector<vector<char> >& board, const string &word, vector<vector<bool> > &visit, int idx, int x, int y){
        //if(idx>=word.length()) return true;//@remove
        if(board[x][y]!=word[idx]) return false;
        if(idx==word.length()-1) return true; //@add
        
        visit[x][y] = true;
        
        bool s = false;
        int m = visit.size(), n = visit[0].size();
        for(int i = 0; i<4; i++){
            int x1 = x+dr[i][0], y1 = y+dr[i][1];
            if(x1>=0 && x1<m && y1>=0 && y1<n && !visit[x1][y1]) 
            if(dfs(board, word, visit, idx+1, x1, y1)){
                s = true; break;
            }
        }
        
        visit[x][y] = false;
        return s;
    }
};

MAX k subarray sum

三维DP:

  • maxn [i][k] = max{ maxn[i-1][k],  maxn[j<i][k-1] + maxsub[j+1][i] }

其中maxsub[i][j]代表【i,j】区间最大的连续子段的sum, 

  • maxsub[i][j] = max{maxsub[i][j-1],  max{  sum([k, j-1]), i<=k<=j }+ nums[j] },  前后两项分别表示该子段不使用nums[j]和使用

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @param k: An integer denote to find k non-overlapping subarrays
     * @return: An integer denote the sum of max k non-overlapping subarrays
     */
    int maxKSubArrays(vector<int> nums, int K) {
        // write your code here
        int n = nums.size();
        if(!n || n<K) return 0;
        vector<vector<int> > one(n, vector<int>(n, 0));
        for(int i = 0; i<n; i++){
            one[i][i] = nums[i];
            int lst = max(0, nums[i]);
            for(int j = i+1; j<n; j++){
                one[i][j] = max(one[i][j-1], lst+nums[j]);
                lst += nums[j];//@error: not nums[i]
                if(lst<0) lst = 0;
                // cout<<i<<','<<j<<": "<<one[i][j]<<endl;
            }
        }

        vector<vector<int> > m(n, vector<int>(K+1));
        for(int i = 0; i<n; i++){
            m[i][1] = one[0][i];
            for(int j = 2; j<=i+1 && j<=K; j++){
                m[i][j] = m[i-1][j-1]+nums[i];
                if(j<i+1) m[i][j] =max(m[i][j], m[i-1][j]);
                if(nums[i]>0 && j<i+1)
                  for(int k = i-1; k>=j-1; k--){//@error: k>=j-1  not j
                    m[i][j] = max(m[i][j], m[k-1][j-1]+one[k][i]);
                  }
                // cout<<i<<" divide "<<j<<": "<<m[i][j]<<endl;
            }
        }
        return m[n-1][K];
    }
};

substr diff

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std; 


int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */
    //int cnt[i][j][l]= m; // given m, return max l
   // cnt[i-j]
    int N; cin>>N;
    for(int ii=0; ii<N; ii++){
        string s, t; int m;
        cin>>m>>s>>t;
        int maxL=-1;
        int n = s.length();
        for(int i = 0; i<n; i++){
            int c = 0, k = i;
            for(int j = i; j<n; j++){
                if(s[j] != t[j-i])  c++;
                while(c>m) { while(s[k] == t[k-i]) k++; k++; c--;}
                maxL = max(maxL, j-k+1);
            }
        }
        for(int i = 0; i<n; i++){
            int c = 0, k = i;
            for(int j = i; j<n; j++){
                if(t[j] != s[j-i])  c++;
                while(c>m) { while(t[k] == s[k-i]) k++; k++; c--;}
                maxL = max(maxL, j-k+1);
            }
        }
        cout<<maxL<<endl;
    }
    return 0;
}

附加:二叉树线索化 

http://baike.baidu.com/link?url=h2Z7V2zrCul8bVb5ARq9YFxRKLp_0ba_eoxtB1FcUetAhOy-l0SulzlB9Me_wHxJ7O_3-NRubjsPxWHc2n42Da

建立线索二叉树,或者说对二叉树线索化,实质上就是遍历一棵二叉树。在遍历过程中,访问结点的操作是检查当前的左,右指针域是否为空,将它们改为指向前驱结点或后续结点的线索。为实现这一过程,设指针pre始终指向刚刚访问的结点,即若指针p指向当前结点,则pre指向它的前驱,以便设线索。
另外,在对一颗二叉树加线索时,必须首先申请一个头结点,建立头结点与二叉树的根结点的指向关系,对二叉树线索化后,还需建立最后一个结点与头结点之间的线索。
下面是建立中序二叉树的递归算法,其中pre为全局变量。

 

序列化和反序列化

方法1  BFS  

BFS分层序列化,空指针用#代替。反序列化的时候,用一个队列不断把当前节点的子节点添加进来,空节点利用bfs顺序的固定性。
(node) (node) ... # .. (node) ... #

方法2  DFS

抱歉!评论已关闭.