2021-10-30 Daily-Challenge

Today I have done leetcode's October LeetCoding Challenge with cpp.

October LeetCoding Challenge 30

Description

Longest Duplicate Substring

Given a string s, consider all duplicated substrings: (contiguous) substrings of s that occur 2 or more times. The occurrences may overlap.

Return any duplicated substring that has the longest possible length. If s does not have a duplicated substring, the answer is "".

Example 1:

Input: s = "banana"
Output: "ana"

Example 2:

Input: s = "abcd"
Output: ""

Constraints:

  • 2 <= s.length <= 3 * 10^4
  • s consists of lowercase English letters.

Solution

almost copied from https://leetcode.com/problems/longest-duplicate-substring/discuss/695101/C%2B%2B-short-O(n-log(n))-solution-with-std%3A%3Aunordered_setlessstd%3A%3Astring_viewgreater

std::string_view does not copy the whole string and std::unordered_set handles the logic of hashing and comparing std::string_view's.

auto speedup = [](){
  cin.tie(nullptr);
  cout.tie(nullptr);
  ios::sync_with_stdio(false);
  return 0;
}();
class rabinFingerprint {
public:
  size_t operator()(const string_view& s)
  {
    if (m_clear) {
      m_pow = 1;
      for (size_t i = 1; i != s.size(); ++i) {
        m_pow = (m_pow * base) % p;
      }
      m_cur = 0;
      for (auto c : s) {
        m_cur = ((m_cur * base) % p + (c - 'a')) % p;
      }
      m_clear = false;
    } else {
      m_cur = ((ssize_t(m_cur) - ssize_t(m_pow * (m_first - 'a'))) % ssize_t(p) + p) % p;
      m_cur = (m_cur * base + (s.back() - 'a')) % p;
    }
    m_first = s.front();
    return m_cur;
  };
  
  void clear() { m_clear = true; }

private:
  static constexpr size_t p = 19260817;
  static constexpr size_t base = 26;

  bool m_clear = true;
  size_t m_cur;
  size_t m_pow;
  char m_first;
};
struct wrapper {
  size_t operator()(const string_view& s) const {
    return m_hasher(s);
  }
  
  rabinFingerprint& m_hasher;  
};
class Solution {
public:
  string longestDupSubstring(string &s) {
    int len = s.length();
    rabinFingerprint hasher;
    unordered_set<string_view, wrapper> st{10, wrapper{hasher}};

    string_view answer;
    int low = 1;
    int high = len;
    while(low <= high) {
      int mid = (low + high) >> 1;
      bool found = false;
      for(int i = 0; i + mid <= len; ++ i) {
        const auto [it, inserted] = st.emplace(s.data() + i, mid);
        if(!inserted) {
          answer = *it;
          found = true;
          break;
        }
      }
      if(found) {
        low = mid + 1;
      } else {
        high = mid - 1;
      }
      
      st.clear();
      hasher.clear();
    }

    return {answer.begin(), answer.end()};
  }
};

// Accepted
// 66/66 cases passed (604 ms)
// Your runtime beats 91.95 % of cpp submissions
// Your memory usage beats 80.2 % of cpp submissions (167.4 MB)

will learn https://leetcode.com/problems/longest-duplicate-substring/discuss/1548070/solution-with-explanation-C%2B%2B-beats-99-time-85-memory-(suffix-array) later