zoukankan      html  css  js  c++  java
  • leetcode1157 子数组中占绝大多数的元素

    题意:就是查询区间内的绝对众数(保证次数超过一半)

    解法一:随机+二分

    对于一个查询[left, right, threshold],从arr[left...right]中随机取一个,它有一个预处理好的”出现点“数组,求出[left, right]包含的“出现点”的个数,再与threshold比较。

    class MajorityChecker {
    public:
        #define random(a,b) ((a)+rand()%((b)-(a)+1))    
        unordered_map<int, vector<int>>mp;
        vector<int>arr;
        MajorityChecker(vector<int>& _arr) {
            for(int i = 0;i < _arr.size();i++)  mp[_arr[i]].push_back(i);
            arr = _arr;
        }
        
        int query(int left, int right, int threshold) {
            int cnt = 0;
            while(cnt < 10)
            {
                cnt++;
                int major = arr[random(left, right)];
                // cout << random(left, right) << endl;
                vector<int>& vec = mp[major];  // 写成引用才不会超时
                auto it1 = lower_bound(vec.begin(), vec.end(), left);
                // if(it1 == mp[major].end())  return -1;
                auto it2 = upper_bound(vec.begin(), vec.end(), right);
                if(it2 - it1 >= threshold)  return major;
            }
            return -1;
        }
    };

    解法二:用线段树维护绝对众数

    总所周知,线段树不能维护众数,但是在这里,可以维护绝对众数。

    要使用线段树,需要元线段可累加,对这道题目,可以使用摩尔投票法对元线段进行累加。
    令元素的值为val,元素的个数为count,
    (val1, count1) + (val2, count2) =
    (val1, count1+count2) cond val1 == val2
    (val1, count1-count2) cond val1 != val2 && count1 > count2
    (val2, count2-count1) cond val1 != val2 && count2 > count1
    这样建立完树后,就可以使用线段树的查找操作,直接找到区间内的众数的值。

    Query查询时,得到某个被包含的子区间,也是将当前区间和之前区间做同样的合并。

    class MajorityChecker {
    public:
    
        struct SegTree {
            #define maxn 20010  //元素总个数
            #define ls rt<<1
            #define rs rt<<1|1
            int Val[maxn<<2],Count[maxn<<2]; //Val绝对众数,Count众数个数
            // int A[maxn],n;//存原数组数据下标[1,n] 
            vector<int>A;
    
            void init(vector<int>& _A){
                A = _A;
            }
    
            //PushUp函数更新节点信息 ,这里是求和
            void PushUp(int rt){
                // Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];
                // Max[rt] = max(Max[rt<<1], Max[rt<<1|1]); // 标记不需要向上维护
                if(Val[ls] == Val[rs]) {
                    Val[rt] = Val[ls];
                    Count[rt] = Count[ls] + Count[rs];
                } else {
                    if(Count[ls] < Count[rs]) {
                        Val[rt] = Val[rs];
                        Count[rt] = Count[rs] - Count[ls];
                    } else {
                        Val[rt] = Val[ls];
                        Count[rt] = Count[ls] - Count[rs];
                    }
                }
            }
            //Build函数建树 
            void Build(int l,int r,int rt){ //l,r表示当前节点区间,rt表示当前节点编号
                // cout << "build: " << l << " " << r << endl;
                if(l==r) {//若到达叶节点 
                    // Sum[rt]=A[l-1];//储存数组值 
                    Val[rt]=A[l];
                    Count[rt]=1;
                    return;
                }
                int m=(l+r)>>1;
                //左右递归 
                Build(l,m,ls);
                Build(m+1,r,rs);
                //更新信息 
                PushUp(rt);
            }
    
    
            void Query(int L,int R,int l,int r,int rt, int& val, int& counts){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
                // cout << "Query: " << l << " " << r << endl;
                if(L <= l && r <= R){
                    //在区间内,直接返回 
                    // return Max[rt];
                    if(Val[rt] == val)  counts += Val[rt];
                    else {
                        if(Count[rt] > counts) {
                            val = Val[rt];
                            counts = Count[rt] - counts;
                        } else {
                            counts -= Count[rt];
                        }
                    }
                    return;
                }
                int m=(l+r)>>1;
                //下推标记,否则Sum可能不正确
                // PushDown(rt,m-l+1,r-m); 
                
                //累计答案
                if(L <= m) Query(L,R,l,m,ls,val,counts);
                if(R >  m) Query(L,R,m+1,r,rs,val,counts);
            } 
        }segTree;
        int n;
        unordered_map<int, vector<int>>mp;
    
        MajorityChecker(vector<int>& arr) {
            n = arr.size();
            segTree.init(arr);
            segTree.Build(0, n-1,1);
    
            for(int i = 0;i < n;i++)
                mp[arr[i]].push_back(i);
        }
        
        int query(int left, int right, int threshold) {
            int znum = -1, counts = 0;
            segTree.Query(left, right, 0, n-1, 1, znum, counts);
            auto it1 = lower_bound(mp[znum].begin(), mp[znum].end(), left);
            auto it2 = upper_bound(mp[znum].begin(), mp[znum].end(), right);
            if(it2 - it1 >= threshold)  return znum;
            return -1;
        }
    };

    注意,区间可以写成[0, n-1]也可以是[1, n]在Build赋值和调用Build, Query时做个区分就行。

    其次,没有Update,是静态的数组。

    参考链接:https://leetcode-cn.com/problems/online-majority-element-in-subarray/solution/er-fen-fa-mo-er-tou-piao-fa-xian-duan-shu-by-xiaoy/

    个性签名:时间会解决一切
  • 相关阅读:
    python yield from (一)
    python yield: send, close, throw
    python I/O多路复用 使用http完成http请求
    python I/O复用
    python 进程间通信
    mac 使用express -e ./
    Object.keys使用整理
    MacBook pro管理员变成普通用户无法解锁问题
    MAC应用无法打开或文件损坏的处理方法
    Redis "MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk"问题的解决
  • 原文地址:https://www.cnblogs.com/lfri/p/14536888.html
Copyright © 2011-2022 走看看