Lintcode 360 Sliding Window Median

Given an array of n integer, and a moving window(size k), move the window at each iteration from the start of the array, find the median of the element inside the window at each moving. (If there are even numbers in the array, return the N/2-th number after sorting the element in the window. )

这道题在Lintcode上面的通过率只有3%,确实这道题花了我一个晚上的时间,主要是在处理一个细节上上让我检查了一个晚上,也是由于自己思维不够缜密吧


这道题我是用红黑树做的,对于重复元素维护一个val值来进行计数,插入时如果遇到相同相同元素 val值自增,删除时如果val值大于1则自减,否则按照正常逻辑操作,

首先建树花费klogk时间,然后(k+1)/2找到第一个中位数, 然后对于剩下的(n-k)次找中位数,每次都执行一次删除和一次插入查找以及一次后继或者前驱操作,时间复杂度logk,所以总得时间复杂度为 (n-k)logk

首先对前N个数构建红黑树,然后中序遍历找到第一个中位数,

由于窗口在移动过程中只改变首尾两个值,所以只要判断收尾两个值和当前中位数的值的关系就很容易找到新的中位数,然后删除首增加尾直到完成遍历。

关键点在于怎么根据首尾值及当前中位数来获取新的中位数,对于同一个元素有多个的情况下,还需要p值来记录当前中位数是元素中得第几个,而算法实现的难点也在于怎么处理p值的变化。


具体操作也是先进行插入,求中位数,再进行删除。

设首值l,尾值c,当前中位数m(在实现中为树节点)

如果l>c>m || l<c<m || l==c 则 m的位置不变

如果c<m<=l 则m需要前移一个位置。 如果 c=m<l 则不需要进行操作

如果l<m<=c 则m需要后后移一个位置。

如果l=m<c 则需要后移一个位置 但在对于p的处理时,如果p<m->val时p会自增(当前中位数的后继节点值不变)在删除时m->val会减掉1,会导致p与m->val不一致,所以当p<m->val,不 操作

                          

//

//  main.cpp

//  Sliding Window Median

//

//  Created by 孟文斌 on 15/4/29.

//  Copyright (c) 2015 孟文斌. All rights reserved.

//


#include <iostream>

#include <queue>

#include <stack>


using namespace std;


const int COLOR_RED = 0;

const int COLOR_BLACK = 1;


struct TreeNodes{

    int key;

    int val;

    int color;//0red 1black

    TreeNodes* p;

    TreeNodes *left;

    TreeNodes *right;

    TreeNodes(int x,int c,TreeNodes *init):key(x),val(1),color(c),p(init),left(init),right(init){}

    TreeNodes(int x,int c):key(x),val(1),color(c),p(NULL),left(NULL),right(NULL){}

};


TreeNodes * const nill = new TreeNodes(-1,COLOR_BLACK);


class RBTree{

private:

    TreeNodes * root;

    //when val is not the minmun of the Tree find the Node which key is min less than the val

    //when val is the minmun of the Tree find the Node which key is min larger than the val

    TreeNodes* findPos(int val){

        TreeNodes *t = root;

        TreeNodes *pre = root;

        while(t != nill){

            if(t->key == val) return t;

            pre = t;

            if(t->key < val) t = t->right;

            else t = t->left;

        }

        return pre;

    }

    

    void RB_left_rotate(TreeNodes* t){//t call left rotation operation

        if(t == NULL || t == nill) return;

        TreeNodes* p = t->p,*s = t->right;

        if(s == nill) return;

        t->right = s->left;

        if(s->left != nill)  s->left->p = t;

        s->left = t;

        t->p = s;

        if(p != nill){

            if(p->left == t) p->left = s;

            else p->right = s;

        }else{

            root = s;

        }

        s->p = p;

    }

    

    void RB_right_rotate(TreeNodes* t){//t call right rotation operation

        if(t == NULL || t == nill) return;

        TreeNodes* p = t->p,*s = t->left;

        if(s == nill) return;

        t->left = s->right;

        if(s->right != nill) s->right->p = t;

        s->right = t;

        t->p = s;

        

        if(p != nill){

            if(p->left == t) p->left = s;

            else p->right = s;

        }else{

            root = s;

        }

        s->p = p;

    }

    

    void RB_insert_fixup(TreeNodes* t){

        if(t == nill || t->p == root) return;

        while(t->p->color == COLOR_RED){

            if(t->p == t->p->p->left){//t's father is in left tree

                // t's father and uncle are both red: change father and uncle into black and t's grandfather into red

                if(t->p->p->right->color == COLOR_RED){

                    t->p->color = COLOR_BLACK;

                    t->p->p->right->color = COLOR_BLACK;

                    t->p->p->color = COLOR_RED;

                    t = t->p->p;

                }else{

                    if(t == t->p->right) {//uncle is black and t is the right child

                        t = t->p;

                        RB_left_rotate(t);

                    }

                    t->p->color = COLOR_BLACK;//uncle is black and t is the left child

                    t->p->p->color = COLOR_RED;

                    RB_right_rotate(t->p->p);

                }

            }else {//exchange the direction

                if(t->p->p->left->color == COLOR_RED){

                    t->p->color = COLOR_BLACK;

                    t->p->p->left->color = COLOR_BLACK;

                    t->p->p->color = COLOR_RED;

                    t = t->p->p;

                }else{

                    if(t == t->p->left) {

                        t = t->p;

                        RB_right_rotate(t);

                    }

                    t->p->color = COLOR_BLACK;

                    t->p->p->color = COLOR_RED;

                    RB_left_rotate(t->p->p);

                }

            }

        }

        root->color = COLOR_BLACK;

    }

    

    void RB_delete_fixup(TreeNodes* t){

        if(t == NULL) return;

        TreeNodes* w = NULL;

        while(t != root && t->color == COLOR_BLACK){

            if(t == t->p->left){//t is left child

                w = t->p->right;

                if(w->color == COLOR_RED){//brother is red

                    w->color = COLOR_BLACK;

                    t->p->color = COLOR_RED;

                    RB_left_rotate(t->p);

                    w = t->p->right;

                }

                if(w->left->color==COLOR_BLACK && w->right->color==COLOR_BLACK){

                    //brother is black and his children are also black

                    w->color = COLOR_RED;

                    t = t->p;

                }else {

                    if(w->right->color == COLOR_BLACK){//left child is black and right child is red

                        w->left->color = COLOR_BLACK;

                        w->color = COLOR_RED;

                        RB_right_rotate(w);

                        w = t->p->right;

                    }

                    w->color = t->p->color;//right child is red

                    t->p->color = COLOR_BLACK;

                    w->right->color = COLOR_BLACK;

                    RB_left_rotate(t->p);

                    t = root;

                }

            }else{//exchanged all direction

                w = t->p->left;

                if(w->color == COLOR_RED){//brother is red

                    w->color = COLOR_BLACK;

                    t->p->color = COLOR_RED;

                    RB_right_rotate(t->p);

                    w = t->p->left;

                }

                if(w->left->color==COLOR_BLACK && w->right->color==COLOR_BLACK){//brother is black and his children are also black

                    w->color = COLOR_RED;

                    t = t->p;

                }else {

                    if(w->left->color == COLOR_BLACK){//left child is black and right child is red

                        w->right->color = COLOR_BLACK;

                        w->color = COLOR_RED;

                        RB_left_rotate(w);

                        w = t->p->left;

                    }

                    w->color = t->p->color;//right child is red

                    w->left->color = COLOR_BLACK;

                    t->p->color = COLOR_BLACK;

                    RB_right_rotate(t->p);

                    t = root;

                }

            }

        }

        t->color = COLOR_BLACK;

    }

    

    /**

     * insert a Node into the Tree

     */

    void insertTreeNodes(TreeNodes* t){

        TreeNodes * pre = findPos(t->key);//find the pos to insert

        if(pre->key == t->key) {

            pre->val++;

            return;

        }

        if(pre->key < t->key) pre->right = t;

        else pre->left = t;

        t->p = pre;

        RB_insert_fixup(t);// fix the tree

    }

    

    /**

     * delete a Node from the Tree

     */

    void deleteTreeNodes(TreeNodes* z){

        if(z == NULL || z==nill) {

            return;

        }

        TreeNodes *y = NULL,*x = NULL;

        if(z->left==nill || z->right==nill) y = z;//t is single

        else y =  Tree_Successor(z,z->val);// t has both right and left child

        if(y->left != nill) x = y->left;//t's left child is not nill point x to s's left

        else x = y->right;

        x->p = y->p; //point x's parent to s's parent even if it is a NIL for the fix of the tree

        if(y->p == nill) root = x;

        else if(y->p->left == y) y->p->left = x;

        else y->p->right = x;

        if(y != z) {

            z->key = y->key; // chage the z to y and y is deleted

            z->val = y->val;

            y->left = NULL;

            y->p = z;

            y->right = NULL;

        }

        if(y->color == COLOR_BLACK) RB_delete_fixup(x);//fix the tree

    }

    TreeNodes * Tree_Minimum(TreeNodes *x){

        TreeNodes *r = x;

        while(r->left != nill)

            r = r->left;

        return r;

    }

    

    TreeNodes * Tree_Maximum(TreeNodes *x){

        TreeNodes *r = x;

        while(r->right != nill)

            r = r->right;

        return r;

    }

    

public:

    

    RBTree(){

        root = nill;

    }

    /**

     * insert val into tree

     */

    void insertVal(int val){

        if(root == NULL || root == nill) {

            root = new TreeNodes(val,COLOR_BLACK,nill);

            return;

        }

        TreeNodes *t = new TreeNodes(val,COLOR_RED,nill);

        insertTreeNodes(t);

    }

    

    void deleteVal(int val){

        TreeNodes *z = findPos(val);

        if(z->key != val) return;// can't find the val

        if(z->val > 1) {

            z->val--;

            return;

        }

        deleteTreeNodes(z);

    }

    

    TreeNodes * Tree_Predecesor(TreeNodes *x,int& p){

        if(p > 1) {

            p--;

            return x;

        }

        

        if(x->left != nill){

            TreeNodes *t = Tree_Maximum(x->left);

            p = t->val;

            return t;

        }

        TreeNodes *y = x->p;

        while(y != nill && x == y->left){

            x = y;

            y = y->p;

        }

        p = y->val;

        return y;

    }

    

    TreeNodes * Tree_Successor(TreeNodes *x,int& p){

        if(p < x->val) {

            p++;

            return x;

        }

        if(x->right != nill){

            p = 1;

            return Tree_Minimum(x->right);

        }

        TreeNodes *y = x->p;

        while(y != nill && x == y->right){

            x = y;

            y = y->p;

        }

        p = 1;

        return y;

    }

    

    TreeNodes* getPosM(int m,int &p){

        if(!root) return root;

        stack<TreeNodes*> s;

        TreeNodes* tmp = root;

        int num=0;

        while(tmp!=nill){

            s.push(tmp);

            tmp = tmp->left;

        }

        while(!s.empty()){

            tmp = s.top();

            s.pop();

            num += tmp->val;

            if(num >= m) {

                p = tmp->val - num + m;

                return tmp;

            }

            tmp = tmp->right;

            while(tmp != nill){

                s.push(tmp);

                tmp = tmp->left;

            }

        }

        return root;

    }

};


class Solution {

public:

    /**

     * @param nums: A list of integers.

     * @return: The median of the element inside the window at each moving

     */

    vector<int> medianSlidingWindow(vector<int> &nums, int k) {

        // write your code here

        int n = (int)nums.size();

        vector<int> res;

        if(n==0 || k == 0 || n <k) return res;

        if(k==1) return nums;

        RBTree b;

        for(int i=0;i<k;i++){

            b.insertVal(nums[i]);

        }

        int p = 1;

        TreeNodes *m = b.getPosM((k+1)/2,p);

        res.push_back(m->key);

        int l,c;

        for(int i=k;i<n;i++){

            l = nums[i-k];c = nums[i];

            if(l == c){

                res.push_back(m->key);

                continue;

            }

            b.insertVal(c);

            

            if(l > c){

                if(c < m->key && l >= m->key){

                    m = b.Tree_Predecesor(m,p);

                }

            }else if(l < c){

                if(c == m->key) {

                    p++;

                }else if(l == m->key){//here is very easy to enter trap.............important

                    if(p == m->val)m = b.Tree_Successor(m,p);

                }else if(l < m->key && c > m->key) {

                    m = b.Tree_Successor(m,p);

                }

            }

            b.deleteVal(l);

            if(m->left == NULL) m = m->p;

            res.push_back(m->key);

        }

        return res;

    }

};


void displayVector(vector<int> &res){

    for(int i=0;i<res.size();i++){

        cout<<res[i]<<" ";

    }

    cout<<endl;

}



int main(int argc, const char * argv[]) {

//    1811,1202,917,535,570,883,

//    vector<int> nums = {1811,1202,917,535,570,883,421,1735,293,1557,1112,171,1140,656,1052,914,325,1127,642,1862,866,515,712,884,1341,1412,1799,546,1891,1257,1734,72,1434,1295,1896,1215,366,1010,1491,1501,775,131,1916,120,905,11,1315,1909,983,1167,1634,741,1202,978,1970,487,1187,266,877,385,1501,1056,1349,423,1247,1810,1630,572,1762,1400,15,576,1892,1877,991,1775,579,1374,1927,1362,1155,1994,1330,386,1825,928,1762,1139,119,1083,1069,534,320,704,522,713,1177,713,1179,900,378,1564,1295,1424,169,747,1160,183,580,116,1739,917,1814,204,231,1845,371,949,690,685,536,155,1891,124,403,1786,1104,1526,649,1954,1211,57,393,543,62,589,570,570,443,906,836,1305,747,1759,358,262,281,521,226,287,1329,1054,390,1224,1373,45,253,1624,1962,205,380,333,258,699,1617,1266,1341,1928,405,432,969,7,1342,1606,293,451,1959,270,1671,1969,1089,58,480,802,1196,1144,425,315,366,204,1136,259,89,787,1776,41,541,1618,1892,566,1586,669,307,1105,745,151,1963,397,1870,1697,1775,78,368,283,155,413,1362,1043,1844,1032,1038,596,1451,1736,661,1059,1246,1495,1948,1607,1948};

    

    vector<int> nums = {34,454,6,4,36,345,7547,654,8,65,7,65,7,54,6,45,6,45,345,23,4,234,23,423,4,32,4,234,23,4,234,32,423,4,234,4,324,32,4,354326,547,57,56,8,6,456,342,5,34534,5,342,6,547568,657,54,6,435,345,43,5,43647,567,65,7,546,34,5,34,523,5,543,45,34,5,43,654,7,5,7,56,4,634,5,23,43,54326,456,5,7,564,7,546,43,6,435,23,4,234,2,4,234,3,45,43,6,46,45,6,456,45,64,56,45,645,6,546,54,6,456,45,6,546,435,423,64,57,56,87,69,80,5462,43,5,435,235,423,5,43,6,45,65,7,658,65,4,754,7,457,54,6745,457,453,7,345,7,547,634,25,34,5,2,5,6457,456,8,9,76,9,7,65754,6,45,32,5,34,52,345,34};

//    vector<int> nums = {5,5,5,6,4};

    vector<int> res;

    Solution sol;

    res = sol.medianSlidingWindow(nums,3);

    displayVector(res);

    return 0;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值