zoukankan      html  css  js  c++  java
  • string_view暴力串串题

    有一类串串题通常需枚举所有的子串,再进行统计。
    如果我们能O(1)得到一个子串,再用hash统计,1e4 的规模完全是可以过的

    string和string_view的区别

    string_view和string的区别:
    string_view 是C++17所提供的用于处理只读字符串的轻量对象。这里后缀 view 的意思是只读的视图。

    • 通过调用 string_view 构造器可将字符串转换为 string_view 对象。
      • string 可隐式转换为 string_view。
    • string_view 是只读的轻量对象,它对所指向的字符串没有所有权。
    • string_view通常用于函数参数类型,可用来取代 const char* 和 const string&。
      • string_view 代替 const string&,可以避免不必要的内存分配。
    • string_view的成员函数即对外接口与 string 相类似,但只包含读取字符串内容的部分。
      • string_view::substr()的返回值类型是string_view,不产生新的字符串,不会进行内存分配。
      • string::substr()的返回值类型是string,产生新的字符串,会进行内存分配。
    • string_view字面量的后缀是 sv。(string字面量的后缀是 s)

    std::string_view 的局限:

    • 追加和拼接会触发拷贝
    • 创建 string_view 的 string 不能修改,否则再次访问对应的 string_view 时,行为未定义

    复杂度:

    • substr
      • string的复杂度是O(Linear in count)
      • string_view的复杂度是O(constant)
    • operator =
      • string的复杂度是O(linear in size of str)
      • string_view的复杂度是O(constant)
    • operator ==
      • string的复杂度是O(size)
      • string_view的复杂度是O(size)

    string to string_view:

    string s = "hello"
    string_view ss(s);  
    

    string_view to string:

    inline std::string as_string(std::string_view v) { 
        return {v.data(), v.size()}; 
    }
    
    string(ss)
    

    暴力切题

    来 我们来秒困难题

    Leetcode 1316. 不同的循环子字符串

    题意:求所有aa格式的子串的个数
    方法:枚举所有子串,string_view可以直接判断是否相等,再用unordered_map或者unordered_set统计

    class Solution {
    public:
        int distinctEchoSubstrings(string text) {
            unordered_set<string_view>st;
            int n = text.size();
            string_view s(text);
            for(int i = 1;i <= n/2;i++) {  // 枚举长度
                for(int j = i;j+i <= n;j++) {  // 枚举中心
                    // cout << s.substr(j-i, i) << " " << s.substr(j, i) << endl;
                    if(s.substr(j-i, i) == s.substr(j, i)) {  // 直接比较,不需要逐一判断
                        st.insert(s.substr(j, i));
                    }
                }
            }
            return st.size();
        }
    };
    

    Leetcode 1044. 最长重复子串

    题意:出现次数大于等于2次的子串称为重复子串,求最长的重复子串
    方法:对于长度,有单调性,可以二分。假如指定长度,我们可以用string_view得到所有指定长度的子串,再通unordered_map统计

    class Solution {
    public:
        inline std::string as_string(std::string_view v) { 
            return {v.data(), v.size()}; 
        }
        string check(string s, int len) {
            string_view ss(s);
            unordered_map<string_view, int>mp;
            for(int i = 0;i <= ss.size()-len;i++) {
                // cout << ss.substr(i, len) << endl;
                mp[ss.substr(i, len)]++;
            }
            for(auto it = mp.begin(); it != mp.end();it++) {
                if(it->second >= 2)  return (it->first).data();
            }
            return "";
        }
    
        string longestDupSubstring(string s) {
            int left = 1, right = s.size(), mid;
            string ans;
            while(left <= right) {
                mid = (left + right) / 2;
                string res = check(s, mid);
                // cout << mid << " " << res << endl;
                if(res != "") {
                    left = mid+1;
                    ans = res;
                }
                else right = mid-1;
            }
            return ans;
        }
    };
    

    Leetcode187. 重复的DNA序列

    题意:相当于上题的简化版,求指定长度的重复子串
    方法:暴力统计

    class Solution {
    public:
        vector<string> findRepeatedDnaSequences(string s) {
            unordered_map<string_view, int>mp;
            string_view ss(s);
            for(int i = 0;i <= (int)s.size()-10;i++) {
                mp[ss.substr(i, 10)]++;
            }
            vector<string>ans;
            for(auto item : mp) {
                if(item.second >= 2)  ans.push_back(string(item.first));
            }
            return ans;
        }
    };
    

    因为在加入哈希表的过程中,不会改变字符串的内容,因此使用string_view可以获得比substr更好的性能。(虽然对于本题这种较短的string会使用COW技术优化内存,故时间复杂度体现的不明显)。
    参考:https://leetcode-cn.com/problems/repeated-dna-sequences/solution/c17-ha-xi-biao-jie-he-string_view-by-owe-z0oy/

    Leetcode 面试题 17.13. 恢复空格

    题意:给定一些单词,求给定字符串切割后,不在字典中的字母最小
    方法:首先unordered_set统计字典,dp[i]表示前i个未识别的字符数,dp[i] = min(dp[i-1]+1, dp[j]),sbustr(j, i-j)可以用string_view

    class Solution {
    public:
        int respace(vector<string>& dictionary, string sentence) {
            unordered_set<string_view> s;
            for (const string &str : dictionary)
                s.insert(str);
            int n = sentence.size();
            vector<int> dp(n + 1);
            
            string_view sv(sentence);
            
            for (int i = 1; i <= n; ++i) {
                dp[i] = dp[i - 1] + 1;
                for (int j = 1; j <= i; ++j) {
                    string_view sub = sv.substr(j - 1, i - j + 1);
                    if (s.find(sub) != s.end())
                        dp[i] = min(dp[i], dp[j - 1]);
                }
            }
            
            return dp[n];
        }
    };
    

    Trie和AC自动机在其他题解中已经有了详细介绍,这里主要提供一个加速普通字符串哈希算法的方法。
    原理就是利用C++ 17提供的string_view,减少子串查找过程中不必要的字符串创建开销。
    与直接用string相比,运行时间从1600+ ms降低到不到400 ms。
    参考:https://leetcode-cn.com/problems/re-space-lcci/solution/c-string_view-by-lucifer1004/

    参考链接:

    1. How to correctly create std::string from a std::string_view?
    2. C++17特性 string_view substr只要常数复杂度,且省内存
  • 相关阅读:
    MYSQL索引
    列表里重复次数最多的元素
    python学习笔记
    Spark 扫描 HDFS lzo/gz/orc异常压缩文件
    Yarn RM写ZNode超数据量限制bug修复
    Spark HistoryServer日志解析&清理异常
    【Yarn源码分析】Container启动流程源码分析
    Yarn NodeManager总体架构
    【Yarn源码分析】ApplicationMaster源码分析
    【Yarn源码分析】FairScheduler资源调度
  • 原文地址:https://www.cnblogs.com/lfri/p/15731731.html
Copyright © 2011-2022 走看看