Pony ai interview preparation

2019-09-04
// CUDA: max pooling; convolution; average pooling.
// See the CUDA preparation part.

// BFS 变形题. One exit & calculate the shortest time. 从离开的点出发即可。matrix里面有很多人和一个出口,问离出口最远的人的距离

// 274. H-Index
int hIndex(vector<int>& citations) {
  sort(begin(citations), end(citations), greater<int>());
  for (int i = 0; i < citations.size(); ++i) {
    if (citations[i] < i + 1) return i;
  }
  return citations.size();
}

// skyline 变形
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
  vector<vector<int>> pts;
  for (const auto& pt: buildings) {
    pts.push_back({pt[0], -pt[2]});
    pts.push_back({pt[1], pt[2]});
  }
  sort(begin(pts), end(pts));
  multiset<int> m({0});
  int prev_max = 0;
  vector<vector<int>> ans;
  for (const auto& pt : pts) {
    if (pt[1] < 0) m.insert(-pt[1]);
    else m.erase(m.find(pt[1]));
    const auto cur_max = *crbegin(m);
    if (cur_max != prev_max) {
      ans.push_back({pt[0], cur_max});
      prev_max = cur_max;
    }
  }
  return ans;
}

// Dijkstra
// http://yuchenspace.info/graph-shortest-path/

// HashMap, design  set, get, setAll(value), by vector.

// 给一个有向图,判断否形成二叉树; 判断图是否是树,要有一些early exit。图的遍历,是否有环,以及child。给了一堆含有起点和终点的pair,问这些pair是否能够构成二叉树。
// 如何判断一个点是否在三角形内。面积,角度。
// 多线程角度:pip、FIFO、message queue、shared memory、socket、signal

// 23. Merge k Sorted Lists
ListNode* MergeLists(vector<ListNode*>& lists, const int stt, const int fin) {
  if (stt == fin) return lists[stt];
  if (stt > fin) return nullptr;
  ListNode* left = MergeLists(lists, stt, stt + (fin - stt) / 2);
  ListNode* right = MergeLists(lists, stt + (fin - stt) / 2 + 1, fin);
  ListNode* root = new ListNode(0);
  ListNode* cur = root;
  while (left && right) {
    if (left->val <= right->val) {
      cur->next = left;
      left = left->next;
    } else {
      cur->next = right;
      right = right->next;
    }
    cur = cur->next;
  }
  if (left) {
    cur->next = left;
  }
  if (right) {
    cur->next = right;
  }
  return root->next;
}  
  
ListNode* mergeKLists(vector<ListNode*>& lists) {
  return MergeLists(lists, 0, lists.size()-1);        
}

// 给一棵树,List of Node,寻找整个List Node的LCA
// 可以返回在当前树下的节点
TreeNode* lowestCommonAncestor(TreeNode* root, 
                                   TreeNode* p, TreeNode* q) {
  if (!root || p == root || q == root) return root;
  const auto left = lowestCommonAncestor(root->left, p, q);
  const auto right = lowestCommonAncestor(root->right, p, q);
  
  return left && right? root:(left?left:right);
}

class Solution {
public:
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        UnionFindSet s(edges.size());
        for(const auto& edge: edges) {
            if(!s.Union(edge[0],edge[1])) {
                return edge;
            }
        }    
        return {};
    }
};
  
// 435. Non-overlapping Intervals
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
  if (intervals.empty()) return 0;
  sort(begin(intervals), end(intervals), [](const vector<int>& v1,
                                            const vector<int>& v2) {
    return v1[1] < v2[1];
  });       
  int res = 0;
  int ed = -2e9;
  for (const auto& inter : intervals) {
    if (ed <= inter[0]) {
      ++res;
      ed = inter[1];
    }
  }
  return intervals.size() - res;
}

// 给一些一维区间,问最多能选几个区间,要求选出的区间中任意两个不能有重合。
int MaxNonOverlap(vector<pair<int, int>>& nums) {
  sort(begin(nums), end(nums), [](const pair<int, int>& n1, 
                                 const pair<int, int>& n2) {
    return n1.second < n2.second;
  });
  int res = 0;
  int ed = -2e9;
  for (int i = 0; i < nums.size(); ++i) {
    if (ed < nums[i].first) {
      ++res;
      ed = nums[i].second;
    }
  }
}

// 684. Redundant Connection
// Union-find the find this redundant connection.
class UnionFindSet {
 public:
  vector<int> parents_;
  vector<int> ranks_;
  UnionFindSet(int n) {
    ranks_=vector<int>(n+1,0);
    parents_=vector<int>(n+1,0);
    for(int i=0;i<parents_.size();i++) {
      parents_[i]=i;
    }
  }
  bool Union(int u, int v) {
    int pu=Find(u);
    int pv=Find(v);
    if(pu==pv) {
      return false;
    }
    if(ranks_[pv]>ranks_[pu]){
      parents_[pu]=pv;
    }
    else if(ranks_[pu]>ranks_[pv]){
      parents_[pv]=pu;
    }
    else{
      parents_[pv]=pu;
      ranks_[pv]+=1;
    } 
    return true;
  }
  int Find(int u){
    if(u!=parents_[u]){
      parents_[u]=Find(parents_[u]);
    }
    return parents_[u];
  }    
};    
  
// 85. Maximal Rectangle
int maximalRectangle(vector<vector<char>>& matrix) {
  if (matrix.empty() || matrix[0].empty()) return 0;
  vector<int> heights(matrix[0].size() + 2, 0);
  int max_area = 0;
  for (int i = 0; i < matrix.size(); ++i) {
    for (int j = 0; j < matrix[0].size(); ++j) {
      if (matrix[i][j] == '0') {
        heights[j+1] = 0;
      } else {
        ++heights[j+1];
      }
    }
    max_area = max(max_area, MaxHistogramArea(heights));
  }
  return max_area;
}  
int MaxHistogramArea(const vector<int>& heights) {
  stack<int> record;
  record.push(heights[0]);
  int max_area = 0;
  for (int i = 1; i < heights.size(); ++i) {
    while (heights[record.top()] > heights[i]) {
      const int mid = record.top();
      record.pop();
      max_area = max(max_area, heights[mid] * (i - record.top() - 1));
    }
    record.push(i);
  }
  return max_area;
}  

// 221. Maximal Square
// 0101的二维数组,0代表空地,1代表地雷,找出有多少个d*d的正方形是没有地雷的
// DP method
int maximalSquare(vector<vector<char>>& matrix) {
  if (!matrix.size() || !matrix[0].size()) {
    return 0;
  }      
  int row = matrix.size();
  int col = matrix[0].size();
  int maxLen = 0;
  vector<vector<int>> rec(row, vector<int>(col, 0));     
  for (int idx = 0; idx < row; ++idx) {
    maxLen = max(maxLen, matrix[idx][0] - '0');   
    rec[idx][0] = matrix[idx][0] - '0';
  }
  for (int idx = 0; idx < col; ++idx) {
    maxLen = max(maxLen, matrix[0][idx] - '0');
    rec[0][idx] = matrix[0][idx] - '0';
  }    
  for (int r = 1; r < row; ++r) {
    for (int c = 1; c < col; ++c) {
      if (matrix[r][c] == '1') {
        rec[r][c] = min( min(rec[r-1][c], rec[r][c-1]), rec[r-1][c-1]) + 1;
        maxLen = max(maxLen, rec[r][c]);
      }
    }
  }
  return maxLen*maxLen;
}
// Accumulate sum method
void accumulate_volumn(vector<vector<int>>& rec, vector<vector<char>>& matrix, int m, int n) {
  for(int col=1; col<=n; col++) {
    for(int row = 1; row<=m; row++) {
      rec[row][col] = rec[row-1][col]+matrix[row-1][col-1]-'0';
    }    
  }    
}        
void accumulate_row(vector<vector<int>>& rec, vector<vector<char>>& matrix, int m, int n) {
  for(int row=1; row<=m; row++) {
    for(int col = 1; col<=n; col++) {
      rec[row][col] += rec[row][col-1];
    }    
  }    
}     
bool isFullSquare(vector<vector<int>>& rec, int row, int col, int size) {
  int target = size*size;
  int cur = rec[row+size-1][col+size-1]+rec[row-1][col-1]-rec[row-1][col+size-1]-rec[row+size-1][col-1];
  return cur==target;
}    
int maximalSquare(vector<vector<char>>& matrix) {
  int m=matrix.size();
  int n=m?matrix[0].size():0;
  vector<vector<int>> rec(m+1, vector<int>(n+1,0));
  accumulate_volumn(rec, matrix, m, n);
  accumulate_row(rec, matrix, m, n);
  int ans = 0;
  int size = min(m, n);
  while(size>=1) {
    for(int row=1; row<=m-size+1; row++) {
      for(int col=1; col<=n-size+1;col++) {
        if(isFullSquare(rec, row, col, size))
          return size*size;
      }    
    }    
    size--;
  }    
  return 0;
}
  
// 543. Diameter of Binary Tree
// DFS
int diameterOfBinaryTree(TreeNode* root, int& ans) {
  if(!root)
    return -1;
  int left = diameterOfBinaryTree(root->left, ans);
  int right = diameterOfBinaryTree(root->right, ans);
  ans = max(ans, left+right+2);
  return max(left,right)+1;
}    
int diameterOfBinaryTree(TreeNode* root) {
  int ans=0;
  diameterOfBinaryTree(root, ans);
  return ans;
}
// BFS: construct graph
unordered_map<int, unordered_set<int>> graph;
int max_depth_ = 0;
int node_ = -1;
int count = 0;  
void BFS(TreeNode* root, const int cur_depth, const int cur_val) {
  if (!root) return;
  if (cur_depth > max_depth_) {
    node_ = root->val;
    max_depth_ = cur_depth;
  }
  if (root->left) {
    root->left->val = count++;
    graph[root->val].insert(root->left->val);
    graph[root->left->val].insert(root->val);
    BFS(root->left, cur_depth + 1, root->left->val);
  }
  if (root->right) {
    root->right->val = count++;
    graph[root->val].insert(root->right->val);
    graph[root->right->val].insert(root->val);
    BFS(root->right, cur_depth + 1, root->right->val);
  }  
}  
int GetLongestPath(const int n, unordered_map<int, unordered_set<int>>& graph) {
  int max_len = 0;
  if (!graph.count(n)) return 0;
  for (const auto v : graph.at(n)) {
    graph[v].erase(n);
    max_len = max(GetLongestPath(v, graph), max_len);
  }
  graph.erase(n);
  return max_len + 1;
}  
int diameterOfBinaryTree(TreeNode* root) {
  if (!root) return 0;
  root->val = count++;
  BFS(root, 0, 1);
  return max(0, GetLongestPath(node_, graph) - 1);
}

// 1522. n-array tree for diameter
int Diameter(Node* root, int& ans) {
  if (!root) return -1;
  list<int> record;
  for (const auto n : root->children) {
    const int len = Diameter(n, ans);
    if (record.size() < 2)
      record.push_back(len);
    else if (record.front() < len || record.back() < len) {
      if (record.front() > record.back()) 
        record.pop_back();
      else record.pop_front();
      record.push_back(len);
    }
  }
  int cur1 = record.empty() ? -1:record.front();
  if (!record.empty()) record.pop_front();
  int cur2 = record.empty() ? -1: record.back();
  ans = max(ans, cur1 + cur2 + 2);
  return max(cur1, cur2) + 1;
}  
int diameter(Node* root) {
  if (!root) return 0;
  int ans = 0;
  Diameter(root, ans);
  return ans;
}

// 792. Number of Matching Subsequences
int addOne(string A, string B) {
  int idx=0;
  int idx2=0;
  while(idx<A.size() && idx2<B.size()) {
    if(B[idx2]==A[idx]) { 
      idx2++;
      idx++;
      continue;
    }    
    idx++;
  }    
  return idx2==B.size();
}    
bool mapContain(unordered_map<char,int> A, string B) {
  for(auto c:B) {
    A[c]--;
    if(A[c]<0)
      return false;
  }    
  return true;
}    
int numMatchingSubseq(string S, vector<string>& words) {
  int len=words.size();
  vector<queue<string>> rec(26);
  for(auto w:words)
    rec[w[0]-'a'].push(w);
  int ans=0;
  for(auto c:S) {
    int len_q = rec[c-'a'].size();
    for(int i=0;i<len_q;i++){
      string tp=rec[c-'a'].front().substr(1);
      rec[c-'a'].pop();
      if(!tp.size())
        ans++;
      else
        rec[tp[0]-'a'].push(tp);
    }    
  }    
  return ans;
}

// Buy stock series.
// 121. Best Time to Buy and Sell Stock
int maxProfit(vector<int>& prices) {
  int buy = prices[0];
  int p = 0;
  for (int i = 1; i < prices.size(); ++i) {
    if (prices[i] > buy) {
      p = max(p, prices[i] - buy);
    } else {
      buy = prices[i];
    }
  }
  return p;
}

// 33. Search in Rotated Sorted Array
// Follow up, with duplicate
int search(vector<int>& nums, int target) {
  if (!nums.size()) return -1;
  int stt_idx = 0;
  int fin_idx = nums.size() - 1;
  while (stt_idx + 1 < fin_idx) {
    const int mid_idx = stt_idx + (fin_idx - stt_idx) / 2;
    const int val = nums[mid_idx];
    if (nums[stt_idx] < val) {
      if (val >= target && nums[stt_idx] <= target) fin_idx = mid_idx;
      else stt_idx = mid_idx;
    } else {
      if (val <= target && nums[fin_idx] >= target) stt_idx = mid_idx;
      else fin_idx = mid_idx;
    }
  }
  if (nums[stt_idx] == target) return stt_idx;
  if (nums[fin_idx] == target) return fin_idx;
  return -1;
}

bool search(vector<int>& nums, int target) {
  if (!nums.size()) return false;
  int stt_idx = 0;
  int fin_idx = nums.size() - 1;
  while (stt_idx + 1 < fin_idx) {
    const int mid_idx = stt_idx + (fin_idx - stt_idx) / 2;
    const int val = nums[mid_idx];
    if (nums[stt_idx] < val) {
      if (val >= target && nums[stt_idx] <= target) fin_idx = mid_idx;
      else stt_idx = mid_idx;
    } else if (nums[stt_idx] > val){
      if (val <= target && nums[fin_idx] >= target) stt_idx = mid_idx;
      else fin_idx = mid_idx;
    } else {
      ++stt_idx;
    }       
  }
  if (nums[stt_idx] == target || nums[fin_idx] == target) return true;
  return false;  
}

// 386. Lexicographical Numbers
vector<int> lexicalOrder(int n) {
  vector<int> ans;
  Helper(1, n, ans); 
  return ans;
}  
void Helper(const int stt, const int end, vector<int>& ans) {
  if (stt > end) return;
  ans.push_back(stt);
  Helper(stt * 10, end, ans);
  if (stt % 10 != 9) {
    Helper(stt + 1, end, ans);
  }
} 
  
// 1824. Minimum Sideway Jumps 
class Solution {
public:
  struct Node {
    int dis_ = INT_MAX;
    int lane_ = -1;
    int point_ = -1;
    Node(const int lane, const int point, const int dis = INT_MAX) {
      lane_ = lane;
      point_ = point;
      dis_ = dis;
    }
  };
  struct Comp {
    bool operator()(const Node& node1, const Node& node2) {
      return node1.dis_ > node2.dis_;
    }
  };
  pair<int, int> OtherLane(const int num) {
    if (num == 1) return make_pair(2, 3);
    if (num == 2) return make_pair(1, 3);
    return make_pair(1, 2);
  }
  int minSideJumps(vector<int>& obstacles) {
    const int n = obstacles.size() - 1;
    priority_queue<Node, vector<Node>, Comp> pq;
    vector<vector<int>> history(4, vector<int>(obstacles.size(), INT_MAX));
    pq.push(Node(2, 0, 0));
    pq.push(Node(1, 0, 1));
    pq.push(Node(3, 0, 1));
    history[2][0] = 0;
    history[1][0] = 1;
    history[3][0] = 1;
    while (!pq.empty()) {
      const auto tp = pq.top();
      pq.pop();
      const auto [l1, l2] = OtherLane(tp.lane_);
      if (obstacles[tp.point_] != l1) {
        if (history[l1][tp.point_] > tp.dis_ + 1) {
          history[l1][tp.point_] = tp.dis_ + 1;
          pq.push(Node(l1, tp.point_, tp.dis_ + 1));
        }
      }
      if (obstacles[tp.point_] != l2) {
        if (history[l2][tp.point_] > tp.dis_ + 1) {
          history[l2][tp.point_] = tp.dis_ + 1;
          pq.push(Node(l2, tp.point_, tp.dis_ + 1));
        }
      }
      if (tp.point_ < n && obstacles[tp.point_+1] != tp.lane_) {
        history[tp.lane_][tp.point_+1] = tp.dis_;
        pq.push(Node(tp.lane_, tp.point_ + 1, tp.dis_));
      }
    }
    return min(min(history[1][n], history[2][n]), history[3][n]);
  }
};
  
// 1838. Frequency of the Most Frequent Element
int maxFrequency(vector<int>& nums, int k) {
  sort(begin(nums), end(nums));
  vector<long long> acc_sum(nums.size()+1, 0);
  for (int i = 0; i < nums.size(); ++i)
    acc_sum[i+1] = acc_sum[i] + nums[i];
  int max_res = 0;
  for (int i = 1, j = 1; i < acc_sum.size(); ++i) {
    while ((i - j + 1ll)*nums[i-1] - (acc_sum[i] - acc_sum[j-1]) > k) ++j;
    max_res = max(max_res, i - j + 1);
  }
  return max_res;
}  

// 121. Best Time to Buy and Sell Stock
int maxProfit(vector<int>& prices) {
  int buy = prices[0];
  int p = 0;
  for (int i = 1; i < prices.size(); ++i) {
    if (prices[i] > buy) {
      p = max(p, prices[i] - buy);
    } else {
      buy = prices[i];
    }
  }
  return p;
}
// Clean solution
int MaxProfit(const vector<int>& nums) {
  int profit = 0;
  for (int i = 0, min_p = INT_MAX; i < nums.size(); ++i) {
    profit = max(profit, nums[i] - min_p);
    min_p = min(nums[i], min_p);
  }
  return profit;
}

// 122. Best Time to Buy and Sell Stock II
int maxProfit(vector<int>& prices) {
  int profit = 0;
  for (int i = 0; i + 1< prices.size(); ++i) {
    profit += max(0, prices[i+1] - prices[i]);
  }
  return profit;
}

// 123. Best Time to Buy and Sell Stock III
// f(i) = p(i) - min_p
//      = f(i-1)
// 前后缀分解
int maxProfit(vector<int>& prices) {
  vector<int> f(prices.size()+2, 0);
  for (int i = 1, min_p = INT_MAX; i <= prices.size(); ++i) {
    f[i] = max(f[i-1], prices[i-1]-min_p);
    min_p = min(min_p, prices[i-1]);
  }
  int res = 0;
  for (int i = prices.size(), max_p = 0;
       i >= 1; --i) {
    res = max(res, f[i-1] + max_p - prices[i-1]);
    max_p = max(prices[i-1], max_p);
  }
  return res;
}

// 188. Best Time to Buy and Sell Stock IV
// state machine DP
// 0(no buy stock)  1(buy stock)
int maxProfit(int k, vector<int>& prices) {
  const int INF = -1e8;
  const int size = prices.size();
  if (k >= size/2) {
    int res = 0;
    for (int i = 1; i < prices.size(); ++i) {
      res += max(0, prices[i] - prices[i-1]);
    }
    return res;
  }
  vector<vector<int>> f(size+1, vector<int>(k+1, INF));
  auto g = f;
  int res = 0;
  f[0][0] = 0;
  for (int i = 1; i <= size; ++i) {
    for (int j = 0; j <= k; ++j) {
      f[i][j] = max(f[i-1][j], g[i-1][j] + prices[i-1]);
      g[i][j] = g[i-1][j];
      if (j) g[i][j] = max(g[i][j], f[i-1][j-1] - prices[i-1]);
      res = max(res, f[i][j]);
    }
  }
  return res;
}
// Optimization
int maxProfit(int k, vector<int>& prices) {
  const int INF = -1e8;
  const int size = prices.size();
  if (k >= size/2) {
    int res = 0;
    for (int i = 1; i < prices.size(); ++i) {
      res += max(0, prices[i] - prices[i-1]);
    }
    return res;
  }
  vector<vector<int>> f(2, vector<int>(k+1, INF));
  auto g = f;
  int res = 0;
  f[0][0] = 0;
  for (int i = 1; i <= size; ++i) {
    for (int j = 0; j <= k; ++j) {
      f[i & 1][j] = max(f[i-1 & 1][j], g[i-1 & 1][j] + prices[i-1]);
      g[i & 1][j] = g[i-1 & 1][j];
      if (j) g[i & 1][j] = max(g[i & 1][j], f[i-1 & 1][j-1] - prices[i-1]);
      res = max(res, f[i & 1][j]);
    }
  }
  return res;
}

// 714. Best Time to Buy and Sell Stock with Transaction Fee
// https://www.acwing.com/problem/content/description/1165/
int maxProfit(vector<int>& prices, int fee) {
  const int size = prices.size();
  const int INF = 1e8;
  vector<vector<int>> f(size+1, vector<int>(2, -INF));
  f[0][0] = 0;
  int res = 0;
  for (int i = 1; i <= size; ++i) {
    f[i][0] = max(f[i-1][0], f[i-1][1] + prices[i-1]);
    f[i][1] = max(f[i-1][1], f[i-1][0] - prices[i-1] - fee);
    res = max(res, f[i][0]);
  }
  return res;
}

// 309. Best Time to Buy and Sell Stock with Cooldown

// 1923. Longest Common Subpath

// 1235. Maximum Profit in Job Scheduling

// 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit

// 1239. Maximum Length of a Concatenated String with Unique Characters

// 1916. Count Ways to Build Rooms in an Ant Colony

// 786. K-th Smallest Prime Fraction
bool Check(const double boundary, const vector<int>& arr, const int k,
           vector<int>& res) {
  int cnt = 0;
  for (int i = 0, j = 0; i < arr.size(); ++i) {
    while (j+1 <= i && 1.0*arr[j+1]/arr[i] <= boundary)
      ++j;
    if (1.0*arr[j]/arr[i] <= boundary)
      cnt += j + 1;
    if (abs(1.0*arr[j]/arr[i] - boundary) < 1.0e-8) {
      res[0] = arr[j];
      res[1] = arr[i];
    }
  }
  return cnt >= k;
}  
vector<int> kthSmallestPrimeFraction(vector<int>& arr, int k) {
  double l = 0.0;
  double r = 1.0;
  constexpr double eps = 1.0e-8;
  vector<int> ans(2);
  while (r - l > eps) {
    const double mid = (r + l)/2.0;
    if (Check(mid, arr, k, ans)) {
      r = mid;
    } else {
      l = mid;
    }
  }
  Check(r, arr, k, ans);
  return ans;
}

// 1922. Count Good Numbers
long long MOD = 1e9 + 7;  
long long Quick(long long num, long long t) {
  long long res = 1;
  while (t) {
    if (t & 1) res = res * num % MOD;
    num = num * num % MOD;
    t >>= 1;
  }
  return res;
}  
int countGoodNumbers(long long n) {
  return Quick(5, (n+1)/2) * Quick(4, n/2) % MOD;
}

// 1915. Number of Wonderful Substrings
int s[100001][10] = {0};
int cnt[1024] = {0};  
long long wonderfulSubstrings(string str) {
  ++cnt[0];
  long long res = 0;
  for (int i = 1; i <= str.size(); ++i) {
    for (int j = 0; j < 10; ++j) {
      if (str[i-1] - 'a' == j) {
        s[i][j] = s[i-1][j] + 1;
      } else {
        s[i][j] = s[i-1][j];
      }
    }
    int state = 0;
    for (int j = 0; j < 10; ++j) {
      state = state * 2 + s[i][j] % 2;
    }
    res += cnt[state];
    for (int j = 0; j < 10; ++j) {
      res += cnt[state ^ (1 << j)];
    }
    ++cnt[state];
  }
  return res;
}

// 291. Word Pattern II
bool wordPatternMatch(string pattern, string s) {
  unordered_map<char, string> mp;
  unordered_set<string> in_mp;
  return Pattern(pattern, 0, s, 0, mp, in_mp);      
}
bool Pattern(const string& p, const int p_idx, 
             const string& s, const int s_idx, 
             unordered_map<char, string>& mp,
             unordered_set<string>& in_mp) {
  if (p_idx == p.size() && s.size() == s_idx) {
    return true;
  } else if (p_idx == p.size() || s.size() == s_idx) {
    return false;
  }
  for (int i = s_idx; i < s.size(); ++i) {
    const string cur = s.substr(s_idx, i - s_idx + 1);
    if (mp.count(p[p_idx]) > 0) {
      if (mp[p[p_idx]] != cur) continue;
      if (Pattern(p, p_idx+1, s, i+1, mp, in_mp)) {
        return true;
      }
    } else {
      if (in_mp.count(cur) > 0) continue;
      mp[p[p_idx]] = cur;
      in_mp.insert(cur);
      if (Pattern(p, p_idx+1, s, i+1, mp, in_mp)) {
        return true;
      }
      mp.erase(p[p_idx]);
      in_mp.erase(cur);
    }
  }
  return false;
}  

// 1349. Maximum Students Taking Exam
// TLE
const int dirs_[2][4] = { {-1, 1, -1, 1}, {0, 0, -1, -1} };  
int cur_ = 0;  
void MaxStudents(int x, int y, const int cur, 
                vector<vector<char>>& seats) {
  if (x >= seats[0].size()) {
    x = 0;
    ++y;
  }
  if (y >= seats.size()) {
    cur_ = max(cur, cur_);
    return;
  }
  while (seats[y][x] == '#') {
    ++x;
    if (x >= seats[0].size()) {
      x = 0;
      ++y;
    }
    if (y >= seats.size()) {
      cur_ = max(cur, cur_);
      return;
    }
  }
  bool is_ok = true;
  for (int i = 0; i < 4; ++i) {
    const int new_x = dirs_[0][i] + x;
    const int new_y = dirs_[1][i] + y;
    if (new_x < 0 || new_x >= seats[0].size() ||
        new_y < 0 || new_y >= seats.size()) {
      continue;
    }
    if (seats[new_y][new_x] == '+') {
      is_ok = false;
      break;
    }
  }  
  if (is_ok) {
    seats[y][x] = '+';
    MaxStudents(x+1, y, cur+1, seats);
    seats[y][x] = '.';
    MaxStudents(x+1, y, cur, seats);
  } else {
    MaxStudents(x+1, y, cur, seats);
  }
}  
int maxStudents(vector<vector<char>>& seats) {
  MaxStudents(0, 0, 0, seats);        
  return cur_;
}

// 1525. Number of Good Ways to Split a String
int numSplits(string s) {
  int left[26] = {0};
  int right[26] = {0};
  int num_left = 1;
  int num_right = 0;
  ++left[s[0]-'a'];
  for (int i = 1; i < s.size(); ++i) {
    ++right[s[i]-'a'];
    if (right[s[i]-'a'] == 1)
      ++num_right;
  }
  int res = num_left == num_right;
  for (int i = 1; i < s.size() - 1; ++i) {
    --right[s[i]-'a'];
    if (!right[s[i]-'a'])
      --num_right;
    ++left[s[i]-'a'];
    if (left[s[i]-'a'] == 1)
      ++num_left;
    res += num_left == num_right;
  }
  return res;
}

// 489. Robot Room Cleaner
unordered_set<string> record_;
const int dirs_[2][4] = { {0, 1, 0, -1}, {-1, 0, 1, 0} };  
void cleanRoom(Robot& robot, const int x = 0, 
               const int y = 0, const int dir = 0) {
  const auto key = to_string(x) + " " + to_string(y);
  if (record_.count(key)) return;
  record_.insert(key);
  robot.clean();
  for (int i = 0; i < 4; ++i) {
    const int new_x = x + dirs_[0][(i+dir)%4];
    const int new_y = y + dirs_[1][(i+dir)%4];
    if (robot.move()) {
      cleanRoom(robot, new_x, new_y, (dir + i)%4);
      robot.turnRight();
      robot.turnRight();
      robot.move();
      robot.turnRight();
      robot.turnRight();
    }
    robot.turnRight();
  }
}

// 给了一堆点的横纵坐标,要求找到一个三角形,这个三角形不包含任何其他的点
  
// 759. Employee Free Time
vector<Interval> MergeIntervals(const vector<vector<Interval>>& schedule, const 
                                int left, const int right) {
  if (left == right) return schedule[left];
  else if (left > right) return {};
  
  const int mid = left + (right - left)/2;
  const auto left_int = MergeIntervals(schedule, left, mid);
  const auto right_int = MergeIntervals(schedule, mid + 1, right);
  if (left_int.empty()) return right_int;
  if (right_int.empty()) return left_int;
  vector<Interval> ans;
  int stt = INT_MIN;
  int ed = INT_MIN;
  int idx1 = 0;
  int idx2 = 0;
  while (idx1 < left_int.size() && idx2 < right_int.size()) {
    if (ed < min(left_int[idx1].start, right_int[idx2].start)) {
      if (stt >= 0) {
        ans.emplace_back(Interval(stt, ed));
      } 
      stt = min(left_int[idx1].start, right_int[idx2].start);
      if (left_int[idx1].start >= right_int[idx2].start) {
        ed = right_int[idx2].end;
        ++idx2;
      }
      else { 
        ed = left_int[idx1].end;
        ++idx1;
      }
    } else {
      const int tmp = ed;
      if (ed >= left_int[idx1].start) {
        ed = max(ed, left_int[idx1].end);
        ++idx1;
      }
      if (tmp >= right_int[idx2].start) {
        ed = max(ed, right_int[idx2].end);
        ++idx2;
      }
    }
  }
  ans.emplace_back(Interval(stt, ed));
  while (idx1 < left_int.size()) {
    if (ans.back().end >= left_int[idx1].start) {
      ans.back().end = max(left_int[idx1].end, ans.back().end);
    } else {
      ans.emplace_back(left_int[idx1]);
    }
    ++idx1;
  }
  while (idx2 < right_int.size()) {
    if (ans.back().end >= right_int[idx2].start) {
      ans.back().end = max(right_int[idx2].end, ans.back().end);
    } else {
      ans.emplace_back(right_int[idx2]);
    }
    ++idx2;
  }
  return ans;
}  
vector<Interval> employeeFreeTime(vector<vector<Interval>> schedule) {
  vector<Interval> intervals = MergeIntervals(schedule, 0, schedule.size()-1);      
  vector<Interval> ans;
  int stt = INT_MIN;
  for (const auto& interval : intervals) {
    if (stt >= 0)
      ans.emplace_back(Interval(stt, interval.start));
    stt = interval.end;
  }
  return ans;
}