leetcode 2213. 由单个字符重复的最长子字符串

本题2213 由单个字符重复的最长子字符串,可以用线段树和珂朵莉树解决,涉及到单点修改和区间查询,关键点在于单点修改后的区间分割与合并。

线段树方法

我是通过这篇博客学习线段树相关的知识,博主讲的很详细了,比较推荐。

class Solution {
public:
    struct node
    {
        int l, r, pre, suf, max, size;
        char lch, rch;
    };
    node t[400005];
    string ss;

    void update(int p, char v, int l, int r, int k)
    {
        if(l == r)
        {
            t[k].lch = t[k].rch = v;
        }
        else
        {
            int m = l + ((r-l)>>1);
            if(p <= m)
                update(p, v, l, m, k<<1);
            else
                update(p, v, m+1, r, k<<1|1);
            merge(k);
        }
    }

    void merge(int k)
    {
        t[k].l = t[k<<1].l;
        t[k].r = t[k<<1|1].r;
        t[k].size = t[k].r - t[k].l + 1;
        t[k].lch = t[k<<1].lch;
        t[k].rch = t[k<<1|1].rch;
        if(t[k<<1].rch == t[k<<1|1].lch)
        {
            if(t[k<<1].suf == t[k<<1].size) 
            {
                t[k].pre = t[k<<1].size + t[k<<1|1].pre;
            }
            else t[k].pre = t[k<<1].pre;
            if(t[k<<1|1].pre == t[k<<1|1].size)
            {
                t[k].suf = t[k<<1].suf + t[k<<1|1].size;
            }
            else t[k].suf = t[k<<1|1].suf;
            t[k].max = max(t[k<<1].max, t[k<<1|1].max);
            t[k].max = max(t[k].max, max(t[k].pre, t[k].suf));
            t[k].max = max(t[k].max, t[k<<1].suf + t[k<<1|1].pre);
        }
        else
        {
            t[k].pre = t[k<<1].pre;
            t[k].suf = t[k<<1|1].suf;
            t[k].max = max(t[k<<1].max, t[k<<1|1].max);
        }
    }

    void build(int l, int r, int k)
    {
        if(l == r)
        {
            t[k].l = t[k].r = l;
            t[k].lch = t[k].rch = ss[l];
            t[k].suf = t[k].pre = 1;
            t[k].size = t[k].max = 1;
        }
        else
        {
            int m = l + ((r-l) >> 1);
            build(l, m, k<<1);
            build(m+1, r, k<<1|1);
            merge(k);
        }
    }

    vector<int> longestRepeating(string s, string queryCharacters, vector<int>& queryIndices) {
        vector<int> ans;
        ss = "0" + s;
        int n = s.size();
        build(1, n, 1);
        for(int i = 0; i < queryCharacters.size(); ++i)
        {
            update(queryIndices[i]+1, queryCharacters[i], 1, n, 1);
            ans.push_back(t[1].max);
        }
        return ans;
    }
};

珂朵莉树方法

线段树之前就听说过,但以前只是会用模板,这次好好学习了一下。但是看到珂朵莉树就有点懵了,为什么数据结构和动漫可以扯上关系,原来这种数据结构来源于cf上的一道题的题解,题目就是有关动漫的,珂朵莉应该就是女主了。这种数据结构是通过多个集合维护不同的区间,可以参考这篇博客

class Solution {
public:
    struct node
    {
        mutable int l, r, len;
        char ch;
        bool operator < (const node& rhs) const
        {
            return l < rhs.l;
        }
        node(int a = -1, int b = -1, int c = 0, char d = '0'){
            l=a,r=b,len=c,ch=d;
        }
    };
    set<node> st;
    multiset<int> nodelen;
    set<node>::iterator split(int pos)
    {
        set<node>::iterator it = st.lower_bound(node(pos));
        if(it != st.end() && it->l == pos) return it;
        --it;node tmp = *it;st.erase(it);
        nodelen.erase(nodelen.find(tmp.len));
        nodelen.insert(pos - tmp.l);
        nodelen.insert(tmp.r-pos+1);
        st.insert(node(tmp.l, pos-1, pos - tmp.l, tmp.ch));
        return st.insert(node(pos, tmp.r, tmp.r - pos + 1, tmp.ch)).first;
    }

    void assign(int p, char ch)
    {
        set<node>::iterator spr = split(p+1), spl = split(p);
        st.erase(spl, spr);
        set<node>::iterator it = st.insert(node(p, p, 1, ch)).first;
        
        
        if(it != st.begin())
        {
            
            set<node>::iterator itl = it;
            --itl;
            if(itl->ch == it->ch)
            {
                nodelen.erase(nodelen.find(itl->len));
                nodelen.erase(nodelen.find(it->len));
                it->l = itl->l;
                it->len = it->len + itl->len;
                nodelen.insert(it->len);
                st.erase(itl);
                
            }
        }
        
        if(it != st.end())
        {
            set<node>::iterator itr = it;
            ++itr;
            
            if(itr != st.end() && itr->ch == it->ch)
            {
                nodelen.erase(nodelen.find(itr->len));
                nodelen.erase(nodelen.find(it->len));
                it->r = itr->r;
                it->len = it->len + itr->len;
                nodelen.insert(it->len);
                st.erase(itr);
                
            }
        }
    }

    vector<int> longestRepeating(string s, string queryCharacters, vector<int>& queryIndices) {
        char now = s[0];
        int cnt = 1;
        vector<int> ans;
        int n = s.size();
        for(int i = 1; i < n; ++i)
        if(s[i] == now)
        {
            cnt++;
        }
        else
        {
            st.insert(node(i-cnt, i-1, cnt, now));
            nodelen.insert(cnt);
            now = s[i];
            cnt = 1;
        }
        st.insert(node(n-cnt, n-1, cnt, now));
        nodelen.insert(cnt);
        for(int i = 0; i < queryCharacters.size(); ++i)
        {
            assign(queryIndices[i], queryCharacters[i]);
            ans.push_back(*nodelen.rbegin());
        }
        return ans;
    }
};

ps:这部番评价很好,之后可以补番了。

posted @ 2022-04-02 23:15  South1999  阅读(68)  评论(0编辑  收藏  举报