Cruise ai interview preparation

2020-09-01
// 63. Unique Paths II
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
  if (!obstacleGrid.size() || !obstacleGrid[0].size()) return 0;
  int row = obstacleGrid.size();
  int col = obstacleGrid[0].size();
  vector<int> record(col, 0);
  record[0] = 1 - obstacleGrid[0][0];
  for (int r = 0; r < row; ++r) {
    record[0] &= 1 - obstacleGrid[r][0];
    for (int c = 1; c < col; ++c) {
      if (obstacleGrid[r][c] > 0) {
        record[c] = 0;
        continue;
      }
      record[c] += record[c - 1];
    }
  }
  return record[col - 1];
}

// 980. Unique Paths III
int cur_ = 0;  
const int dirs[2][4] = { {0, 1, 0, -1}, {-1, 0, 1, 0} };
pair<int, int> Find(const vector<vector<int>>& grid, const int target) {
  for (int i = 0; i < grid.size(); ++i) {
    for (int j = 0; j < grid[0].size(); ++j) {
      if (grid[i][j] == target) {
        return {i, j};
      }
    }
  }
  return {-1, -1};
}  
int Calculate(const vector<vector<int>>& grid) {
  int num = 0;
  for (int i = 0; i < grid.size(); ++i) {
    for (int j = 0; j < grid[0].size(); ++j) {
      num += !grid[i][j];
    }
  }
  return num;
}  
void UniquePaths(const pair<int, int>& target, vector<vector<int>>& grid,
                 const pair<int, int>& source, const int num, const int target_num) {
  if (target == source) {
    if (num == target_num) {
      ++cur_;
    }
    return;
  }
  const auto x = source.second;
  const auto y = source.first;
  if (x < 0 || y < 0 || y >= grid.size() || x >= grid[0].size() 
      || grid[y][x] == -1 || grid[y][x] == INT_MAX)
    return;
  const int prev = grid[y][x];
  grid[y][x] = INT_MAX;
  for (int i = 0; i < 4; ++i) {
    const auto new_x = dirs[0][i] + source.second;
    const auto new_y = dirs[1][i] + source.first;
    UniquePaths(target, grid, {new_y, new_x}, num + 1, target_num); 
  }
  grid[y][x] = prev;
}      
int uniquePathsIII(vector<vector<int>>& grid) {
  const pair<int, int> stt = Find(grid, 1);
  const pair<int, int> fin = Find(grid, 2);
  const int target = Calculate(grid);
  if (stt.first < 0) return 0;
  UniquePaths(fin, grid, stt, -1, target);
  return cur_;
}

// 986. Interval List Intersections
vector<vector<int>> intervalIntersection(vector<vector<int>>& first, vector<vector<int>>& second) {
  vector<vector<int>> ans;
  int idx1 = 0;
  int idx2 = 0;
  while (idx1 < first.size() && idx2 < second.size()) {
    if (first[idx1][1] < second[idx2][0]) {
      ++idx1;
    } else if (second[idx2][1] < first[idx1][0]) {
      ++idx2;
    } else {
      ans.emplace_back(vector<int>({max(first[idx1][0], second[idx2][0]),
                                    min(first[idx1][1], second[idx2][1])}));
      if (first[idx1][1] > second[idx2][1]) {
        ++idx2;
      } else {
        ++idx1;
      }
    }
  }
  return ans;
}

// 1258. Synonymous Sentences
vector<string> ans_;  
string Find(const string& s1, unordered_map<string, string>& sents) {
  if (sents[s1] != s1) {
    sents[s1] = Find(sents[s1], sents);
  }
  return sents[s1];
}    
vector<string> SplitString(const string& text) {
  vector<string> ans;
  string cur;
  for (const auto& c : text) {
    if (c == ' ') {
      if (!cur.empty()) {
        ans.emplace_back(cur);
      }
      cur.clear();
    } else {
      cur += c;
    }
  }
  if (!cur.empty()) {
    ans.emplace_back(cur);
  }
  return ans;
}  
void Generate(const vector<string>& strs, const int idx, 
              const unordered_set<string>& sets, 
              const unordered_map<string, string> sents,
              const unordered_map<string, vector<string>>& synos, 
              const string cur) {
  if (idx >= strs.size()) {
    ans_.emplace_back(cur);
    return;
  }
  if (!sets.count(strs[idx])) {
    Generate(strs, idx+1, sets, sents, synos, cur + (cur.empty()?"":" ") + strs[idx]);
  } else {
    for (const auto& w : synos.at(sents.at(strs[idx]))) {
      Generate(strs, idx+1, sets, sents, synos, cur + (cur.empty()?"":" ") + w);
    }
  }
}  
vector<string> generateSentences(vector<vector<string>>& synonyms, string text) {
  unordered_map<string, vector<string>> synos; // parent -> all synonymous
  unordered_map<string, string> sents;  // sym -> parent
  for (const auto& syn : synonyms) {
    sents[syn[0]] = syn[0];
    sents[syn[1]] = syn[1];
  }
  unordered_set<string> sets;
  for (const auto& syn : synonyms) {
    const auto& p1 = Find(syn[0], sents);
    const auto& p2 = Find(syn[1], sents);
    sets.insert(syn[0]);
    sets.insert(syn[1]);
    if (p1 != p2) {
      sents[p1] = p2;
    }
  }
  for (const auto& it : sets) {
    const auto& p1 = Find(it, sents);
    synos[p1].emplace_back(it);
  }
  vector<string> strs = SplitString(text);
  Generate(strs, 0, sets, sents, synos, "");
  sort(begin(ans_), end(ans_));
  return ans_;
}
  
// 489. Robot Room Cleaner

// LRU cache
class LRUCache {
 public:
  unordered_map<int, pair<int, list<int>::iterator>> record_;
  list<int> key_;
  int capacity_ = 0;
  
  LRUCache(int capacity) {
    capacity_ = capacity;
  }
    
  int get(int key) {
    auto it = record_.find(key);
    if (it == record_.end()) return -1;
    const auto value = it->second;
    record_.erase(it);
    key_.erase(value.second);
    key_.push_front(key);
    record_[key] = make_pair(value.first, key_.begin());
    return value.first;
  }
    
  void put(int key, int value) {
    auto it = record_.find(key);
    if (it != record_.end()) {
      const auto [_, it_list] = it->second;
      record_.erase(it);
      key_.erase(it_list);
    }
    if (key_.size() >= capacity_) {
      auto back_it = prev(key_.end());
      record_.erase(*back_it);
      key_.erase(back_it);
    }
    key_.push_front(key);
    record_[key] = std::make_pair(value, key_.begin());
  }
};

// 56. Merge Intervals
vector<vector<int>> merge(vector<vector<int>>& intervals) {
  sort(begin(intervals), end(intervals), [](
       vector<int>& v1, vector<int>& v2) {
    return v1[0] < v2[0];
  });
  vector<vector<int>> ans;
  int stt = intervals[0][0];
  int ed = intervals[0][1];
  for (const auto& c : intervals) {
    if (c[0] <= ed) {
      ed = max(c[1], ed);
      stt = min(stt, c[0]);
    } else {
      ans.push_back(vector<int>({stt, ed}));
      ed = c[1];
      stt = c[0];
    }
  }
  ans.push_back({stt, ed});
  return ans;
}

// 735. Asteroid Collision
vector<int> asteroidCollision(vector<int>& asteroids) {
  vector<int> ans;
  stack<int> stk;
  for (const auto& as : asteroids) {
    if (stk.empty()) {
      if (as < 0) {
        ans.emplace_back(as);
      } else {
        stk.push(as);
      }
    } else {
      if (as > 0) {
        stk.push(as);
      } else {
        while (!stk.empty() && stk.top() < abs(as)) {
          stk.pop();
        }
        if (stk.empty())
          ans.emplace_back(as);
        else if (stk.top() == abs(as))
          stk.pop();
      } 
    }
  }
  const int size = ans.size();
  while (!stk.empty()) {
    ans.emplace_back(stk.top());
    stk.pop();
  }
  reverse(ans.begin() + size, ans.end());
  return ans;
}

// 84. Largest Rectangle in Histogram
int largestRectangleArea(vector<int>& heights) {
  stack<int> record;
  heights.insert(heights.begin(), 0);8
  heights.emplace_back(0);
  int max_area = 0;
  record.push(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;
}

// 529. Minesweeper
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
  const int dirs[2][8] = { {-1, 0, 1, 1, 1, 0, -1, -1}, {-1, -1, -1, 0, 1, 1, 1, 0} };
  queue<pair<int, int>> processing;
  processing.push(make_pair(click[0], click[1]));
  while (!processing.empty()) {
    const auto [row, col] = processing.front();
    processing.pop();
    if (board[row][col] == 'M') {
      board[row][col] = 'X';
      return board;
    } else if (board[row][col] == 'E') {
      int cnt_mine = 0;
      vector<int> empty;
      for (int i = 0; i < 8; ++i) {
        const int new_row = row + dirs[1][i];
        const int new_col = col + dirs[0][i];
        if (new_row < 0 || new_col < 0 || new_row >= board.size() ||
              new_col >= board[0].size()) continue;
        if (board[new_row][new_col] == 'M') ++cnt_mine;
        else if (board[new_row][new_col] == 'E') 
          empty.push_back(i);
      }
      if (!cnt_mine) {
        board[row][col] = 'B';
        for (const auto& idx : empty) {
          processing.push(make_pair(dirs[1][idx] + row, dirs[0][idx] + col));
        }
      } else {
        board[row][col] = '0' + cnt_mine;
      }  
    }
  }
  return board;
}

// 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);        
}

// 200. Number of Islands
int numIslands(vector<vector<char>>& grid) {
  int row = grid.size();
  int cnt = 0;
  if (!row) {
    return cnt;
  }
  int col = grid[0].size();
  int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };      
  for (int r = 0; r < row; ++r) {
    for (int c = 0; c < col; ++c) {
      if (grid[r][c] < '1') {
        continue;
      }
      queue<int> que; 
      que.push(r*col + c);
      grid[r][c] = -1;
      while (!que.empty()) {
        int cur_r = que.front()/col;
        int cur_c = que.front()%col;
        for (int d = 0; d < 4; ++d) {
          int new_r = cur_r + dir[d][0];
          int new_c = cur_c + dir[d][1];
          if (new_r < 0 || new_r >= row || new_c < 0 || new_c >= col) {
            continue;
          }
          if (grid[new_r][new_c] == '1') {
            grid[new_r][new_c] = '0';
            que.push(new_r*col + new_c);
          }
        }
        que.pop();
      }
      ++cnt;
    }
  } 
  return cnt;
}
// Calculate ACU
// https://towardsdatascience.com/how-to-efficiently-implement-area-under-precision-recall-curve-pr-auc-a85872fd7f14
// Shared_ptr
template <class Type>
class SharedPtr {
 public:
  SharedPtr() : count_ref_(new int(0)) {}
  
  SharedPtr(T* ptr) : data_(ptr), count_ref(new int(1)) {}
  
  // copy
  SharedPtr(const SharedPtr& obj) {
    data_ = obj.data_;
    count_ref_ = obj.count_ref_;
    if (data_ != nullptr) {
      ++(*count_ref_);
    }
  }
  
  SharedPtr& operator=(const SharedPtr& obj) {
    CleanUp();
    
    data_ = obj.data_;
    count_ref_ = obj.count_ref_;
    if (data_ != nullptr) {
      ++(*count_ref_);
    }
  }
  
  // move
  SharedPtr(SharedPtr&& obj) {
    data_ = obj.data_;
    count_ref_ = obj.count_ref_;
    obj.data_ = obj.count_ref_ = nullptr;
  }
  
  SharedPtr& operator=(SharedPtr && obj) {
    CleanUp();
    
    data_ = obj.data_;
    count_ref_ = obj.count_ref_;
    obj.data_ = obj.count_ref_ = nullptr;
  }
  
  int GetCount() const {
    return *count_ref_;
  }
  
  T& Get() const {
    return data_;
  }
  
  T* operator->() const {
    return data_;
  }
  
  T& operator*() const {
    return data_;
  }
  
  ~SharedPtr() {
    --(*count_ref_);
    if (!*count_ref_) {
      if (data_ != nullptr) delete data_;
      delete count_ref_;
    }
  }
  
 private:
  int* count_ref_ = nullptr;
  T* data_ = nullptr;
};  

// Example
class Box {
 public:
  int length, width, height;
  Box() : length(0), width(0), height(0) {}
};

int main() {
  SharedPtr<Box> obj;
  cout << obj.GetCount() << endl; // prints 0
  SharedPtr<Box> box1(new Box());
  cout << box1.GetCount() << endl; // prints 1
  SharedPtr<Box> box2(box1); // calls copy constructor
  cout << box1.GetCount() << endl; // prints 2
  cout << box2.GetCount() << endl; // also prints 2
 
  return 0;
}
// Memory pool
// http://www.pinksquirrellabs.com/blog/2018/01/31/-fixed-memory-pool-design/
// https://github.com/cacay/MemoryPool
// Polygon in another Polygon
// Verify all points are in another polygon.
// Cruise topic
// https://leetcode.com/company/cruise-automation/

// 311. Sparse Matrix Multiplication
vector<vector<int>> multiply(vector<vector<int>>& mat1, vector<vector<int>>& mat2) {
  unordered_map<int, unordered_set<int>> sparse_index1;
  unordered_map<int, unordered_set<int>> sparse_index2;
  
  const int k = mat1.size();
  const int n = mat2[0].size();
  for (int i = 0; i < mat1.size(); ++i) {
    for (int j = 0; j < mat1[0].size(); ++j) {
      if (mat1[i][j]) {
        sparse_index1[i].insert(j);
      }
    }
  } 
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < mat2.size(); ++j) {
      if (mat2[j][i]) {
        sparse_index2[i].insert(j);
      }
    }
  }
  vector<vector<int>> ans(k, vector<int>(n, 0));
  
  for (int i = 0; i < k; ++i) {
    for (int j = 0; j < n; ++j) {
      if (!sparse_index1[i].empty() && !sparse_index2[j].empty()) {
        const auto& j_col = sparse_index2[j];
        for (const auto& ele : sparse_index1[i]) {
          if (i == 1) cout << ele << " " << i << " " << j << endl;
          if (j_col.count(ele) > 0) {
            ans[i][j] += mat1[i][ele]*mat2[ele][j];
          }
        }
      }
    }
  }
  
  return ans;
}

// 694. Number of Distinct Islands
bool SameIsland(const vector<int>& cur_traj, const vector<vector<int>>& target) {
  int len = 0;
  queue<pair<int, int>> que;
  for (int i = 0; i < target.size(); ++i) {
    que.push(make_pair(i, 50));
  }
  while (!que.empty()) {
    const int cur_que = que.size();
    bool has_same = false;
    for (int i = 0; i < cur_que; ++i) {
      const auto [idx, pos] = que.front();
      que.pop();
      if (pos == cur_traj[len]) {
        has_same = true;
        que.push(make_pair(idx, len+1 >= cur_traj.size()?-1:target[idx][len+1]));
      }
    }
    if (has_same)
      ++len;
    if (len >= cur_traj.size())
      break;
  }
  return len == cur_traj.size()?true:false;
}  
int numDistinctIslands(vector<vector<int>>& grid) {
  unordered_map<int, vector<vector<int>>> trajectory;
  const int shift = 50;
  const int dirs[2][4] = { {0, 1, 0, -1}, {-1, 0, 1, 0} };
  for (int i = 0; i < grid.size(); ++i) {
    for (int j = 0; j < grid[0].size(); ++j) {
      if (grid[i][j]) {
        int num = 0;
        vector<int> cur_traj;
        grid[i][j] = 0;
        queue<pair<int, int>> que({ {i, j} });
        while (!que.empty()) {
          const auto [row, col] = que.front();
          que.pop(); 
          ++num;
          cur_traj.emplace_back((row - i) * 100 + j - col + 50);
          for (int k = 0; k < 4; ++k) {
            const int nr = row + dirs[1][k];
            const int nc = col + dirs[0][k];
            if (nr < 0 || nc < 0 || nr >= grid.size() || 
                nc >= grid[0].size() || !grid[nr][nc]) {
              continue;
            }
            que.push(make_pair(nr, nc));
            grid[nr][nc] = 0;
          }
        }
        if (!trajectory.count(num)) {
          trajectory[num] = {cur_traj};
        } else if (!SameIsland(cur_traj, trajectory[num])) {
          trajectory[num].push_back(cur_traj);
        }
      }
    }
  }
  int ans = 0;
  for (const auto& [size, eles] : trajectory) {
    ans += eles.size();
  }
  return ans;
}

// 695. Max Area of Island
int maxAreaOfIsland(vector<vector<int>>& grid) {
  if (!grid.size() || !grid[0].size()) {
    return 0;
  }
  int row = grid.size();
  int col = grid[0].size();
  priority_queue<int> cur_island; 
  int cnt_res = 0;
  const int MAX_SIZE = 50;
  int dirs[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
  const int NUM_DIR = 4;
  for (int r = 0; r < row; ++r) {
    for (int c = 0; c < col; ++c) {
      if (!grid[r][c]) {
        continue;
      }
      cur_island.push(r*MAX_SIZE + c);
      grid[r][c] = 0;
      int cnt = 1;
      while (!cur_island.empty()) {
        int tp = cur_island.top();
        cur_island.pop();
        for (int idx = 0; idx < NUM_DIR; ++idx) {
          int cur_r = tp/MAX_SIZE + dirs[idx][0];
          int cur_c = tp%MAX_SIZE + dirs[idx][1];
          if (cur_r < 0 || cur_c < 0 || 
              cur_r >= row || cur_c >= col ||
              !grid[cur_r][cur_c]) {
             continue;
          }
          ++cnt;
          cur_island.push(cur_r*MAX_SIZE + cur_c);
          grid[cur_r][cur_c] = 0;
        }        
      }
      cnt_res = max(cnt_res, cnt);  
    }
  }
  return cnt_res;
}

// 981. Time Based Key-Value Store
class TimeMap {
 public:
  /** Initialize your data structure here. */
  TimeMap() {}
  
  void set(string key, string value, int timestamp) {
    data_[key].emplace_back(timestamp, value);      
  }
    
  string get(string key, int timestamp) {
    const auto& data = data_[key];
    if (data.empty()) return "";
    auto it = upper_bound(begin(data), end(data), 
      make_pair(timestamp, key), [](const pair<int, string>& p1,
                            const pair<int, string>& p2) {
        return p1.first < p2.first;
      });
    if (it != begin(data)) {
      --it;
    } else {
      return "";
    }
    return it->second;
  }
  
 private: 
  unordered_map<string, vector<pair<int, string>>> data_;
};

// 528. Random Pick with Weight
class Solution {
 public:
  vector<int> accumulate_sum_;
  Solution(vector<int>& weights) {
    for (const auto w : weights) {
      accumulate_sum_.push_back(accumulate_sum_.empty()?w : accumulate_sum_.back()+w);
    }
    record_ = vector<int>(weights.size(), 0);  
  }  
  int pickIndex() {
    const int random_weight = accumulate_sum_.back() * (static_cast<double>(rand()) / RAND_MAX);
    const int index = upper_bound(accumulate_sum_.begin(), accumulate_sum_.end(), random_weight) - begin(accumulate_sum_);  
    return min(index, (int)accumulate_sum_.size());  
  }
};

// 79. Word Search
const int dirs[2][4] = { {0, 1, 0, -1}, {-1, 0, 1, 0} };
bool Exist(const vector<vector<char>>& board, const int row, 
           const int col, const int index, const string& word,
           vector<vector<bool>>& status) {
  if (index >= word.size()) return true;
  if (row < 0 || row >= board.size() ||
      col < 0 || col >= board[0].size() ||
      board[row][col] != word[index])
    return false;
  if (status[row][col]) return false;
  status[row][col] = true;
  for (int i = 0; i < 4; ++i) {
    if (Exist(board, row + dirs[1][i], col + dirs[0][i], 
          index+1, word, status))
      return true;
  }
  status[row][col] = false;
  return false;
}  
bool exist(vector<vector<char>>& board, string word) {
  for (int i = 0; i < board.size(); ++i) {
    for (int j = 0; j < board[0].size(); ++j) {
      if (board[i][j] == word[0]) {
        vector<vector<bool>> status(board.size(), 
            vector<bool>(board[0].size(), false));
        if (Exist(board, i, j, 0, word, status)) {
          return true;
        }
      }
    }
  }  
  return false;
}

// 1094. Car Pooling
bool carPooling(vector<vector<int>>& trips, int capacity) {
  map<int, vector<int>> record;
  for (const auto& trip : trips) {
    record[trip[1]].emplace_back(trip[0]);
    record[trip[2]].emplace_back(-trip[0]);
  }
  int cur = 0;
  for (const auto& r : record) {
    for (const auto& cap : r.second) {
      cur += cap;
    }
    if (cur > capacity) {
      return false;
    }
  }
  return true;
}

// 304. Range Sum Query 2D - Immutable
class NumMatrix {
 public:   
  vector<vector<int>> _matrix;
  NumMatrix(vector<vector<int>>& matrix) {
    _matrix = matrix;
    int row = matrix.size();
    int col = row?matrix[0].size():0;    
    for (int r = 0; r < row; ++r) {
      for (int c = 1; c < col; ++c) {
        _matrix[r][c] += _matrix[r][c-1];
      }
    }    
    for (int c = 0; c < col; ++c) {
      for (int r = 1; r < row; ++r) {
        _matrix[r][c] += _matrix[r-1][c];
      }
    }
  }  
  int sumRegion(int row1, int col1, int row2, int col2) {
    int s_1 = _matrix[row2][col2];
    int row1_1 = row1 - 1;
    int col1_1 = col1 - 1;
    int row2_1 = row2 - 1;
    int col2_1 = col2 - 1;
    int s_2 = row1_1 >= 0 && col1_1 >= 0?_matrix[row1_1][col1_1]:0;
    int s_3 = row1_1 >= 0?_matrix[row1_1][col2]:0;
    int s_4 = col1_1 >= 0?_matrix[row2][col1_1]:0;
    return s_1 + s_2 - s_3 - s_4;
  }
};

// 36. Valid Sudoku
const int size = 9;
bool insert_record(vector<unordered_set<int>> &rec, int row, int col, char c) {
  int tar = c-'0';
  if(rec[row].find(tar)!=rec[row].end())
    return false;
  rec[row].insert(tar);
  if(rec[col+size].find(tar)!=rec[col+size].end())
    return false;
  rec[col+size].insert(tar);
  int rl=row/3;
  int cl=col/3;
  int blk = size*2 + rl*3 + cl;
  if(rec[blk].find(tar)!=rec[blk].end())
    return false;
  rec[blk].insert(tar);
  return true;
}    
bool isValidSudoku(vector<vector<char>>& board) {
  assert(board.size()==size && board[0].size()==9);
  vector<unordered_set<int>> rec(27,unordered_set<int>());
  for(int row=0; row<size; row++) {
    for(int col=0; col<size; col++) {
      bool verify = true;
      if(board[row][col]!='.')
        verify = insert_record(rec, row, col, board[row][col]);
      if(!verify)
        return false;
    }
  }
  return true;
}