2021-03-30 Daily-Challenge

Today I have done Unique Paths, Longest Increasing Subsequence, Search Suggestions System and leetcode's March LeetCoding Challenge with cpp.

Unique Paths

Description

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?

Example 1:

img

Input: m = 3, n = 7
Output: 28

Example 2:

Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Down -> Down
2. Down -> Down -> Right
3. Down -> Right -> Down

Example 3:

Input: m = 7, n = 3
Output: 28

Example 4:

Input: m = 3, n = 3
Output: 6

Constraints:

  • 1 <= m, n <= 100
  • It's guaranteed that the answer will be less than or equal to 2 * 109.

Solution

using constexpr to get a precomputed table

template<int N>
struct Table {
  constexpr Table() : values() {
    for(int i = 0; i < N; ++i) {
      for(int j = 0; j < N; ++j) {
        if(!i || !j) values[i][j] = 1;
        else {
          if(INT_MAX - values[i - 1][j] > values[i][j - 1]) {
            values[i][j] = values[i - 1][j] + values[i][j - 1];         
          } else {
            values[i][j] = 1;  
          }
        }
      }
    }
  }
  int values[N][N];
};

constexpr auto table = Table<100>();

class Solution {
public:
  int uniquePaths(int m, int n) {
    return table.values[m - 1][n - 1];
  }
};

// Runtime: 0 ms, faster than 100.00% of C++ online submissions for Unique Paths.
// Memory Usage: 6 MB, less than 66.04% of C++ online submissions for Unique Paths.

or just dp

class Solution {
public:
  int uniquePaths(int m, int n) {
    int dp[2][m];
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j < m; ++j) {
        if(!i || !j) {
          dp[i & 1][j] = 1;
        } else {
          dp[i & 1][j] = dp[(i & 1) ^ 1][j] + dp[i & 1][j - 1];
        }
      }
    }
    return dp[(n & 1) ^ 1][m - 1];
  }
};

Longest Increasing Subsequence

Description

Given an integer array nums, return the length of the longest strictly increasing subsequence.

A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7].

Example 1:

Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

Example 2:

Input: nums = [0,1,0,3,2,3]
Output: 4

Example 3:

Input: nums = [7,7,7,7,7,7,7]
Output: 1

Constraints:

  • 1 <= nums.length <= 2500
  • $-10^4 \le nums[i] \le 10^4$

Follow up:

  • Could you come up with the $O(n^2)$ solution?
  • Could you improve it to $O(n \log (n))$ time complexity?

Solution

class Solution {
public:
  int lengthOfLIS(vector<int>& nums) {
    vector<int> dp;
    for(auto i : nums) {
      auto it = lower_bound(dp.begin(), dp.end(), i);
      if(it == dp.end()) {
        dp.push_back(i);
      } else {
        *it = i;
      }
    }
    return dp.size();
  }
};

Search Suggestions System

yesterday's problems

Solution

I knew it! hahahahaha gotcha!

struct TrieNode {
  bool isEnd;
  TrieNode *next[26];
  TrieNode() : isEnd(false) {
    for(int i = 0; i < 26; ++i) next[i] = nullptr;
  }
};

void insertTrie(string &s, TrieNode *root) {
  TrieNode *cur = root;
  for(auto c : s) {
    if(!cur->next[c - 'a']) {
      cur->next[c - 'a'] = new TrieNode();
    }
    cur = cur->next[c - 'a'];
  }
  cur->isEnd = true;
}

void getWords(vector<string> &words, TrieNode *root, int count, string &cur) {
  if(root == nullptr) return;
  if(root->isEnd) words.push_back(cur);
  for(int i = 0; i < 26 && words.size() < count; ++i) {
    if(root->next[i]) {
      cur.push_back(i + 'a');
      getWords(words, root->next[i], count, cur);
      cur.pop_back();
    }
  }
}

class Solution {
public:
  vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
    auto root = new TrieNode();
    for(auto &product : products) {
      insertTrie(product, root);
    }
    
    auto cur = root;
    vector<vector<string>> answer;
      string word;
    for(auto c : searchWord) {
      vector<string> words;
      word.push_back(c);
      cur = cur ? cur->next[c - 'a'] : cur;
      getWords(words, cur, 3, word);
      answer.push_back(words);
    }
    
    return answer;
  }
};

March LeetCoding challenge 30

Description

Russian Doll Envelopes

You are given a 2D array of integers envelopes where envelopes[i] = [wi, hi] represents the width and the height of an envelope.

One envelope can fit into another if and only if both the width and height of one envelope is greater than the width and height of the other envelope.

Return the maximum number of envelopes can you Russian doll (i.e., put one inside the other).

Note: You cannot rotate an envelope.

Example 1:

Input: envelopes = [[5,4],[6,4],[6,7],[2,3]]
Output: 3
Explanation: The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).

Example 2:

Input: envelopes = [[1,1],[1,1],[1,1]]
Output: 1

Constraints:

  • 1 <= envelopes.length <= 5000
  • envelopes[i].length == 2
  • 1 <= wi, hi <= 10^4

Solution

$O(n^2)$ solution

class Solution {
public:
  int maxEnvelopes(vector<vector<int>>& envelopes) {
    sort(envelopes.begin(), envelopes.end());
    int len = envelopes.size();
    int dp[len];
    dp[0] = 1;
    for(int i = 1; i < len; ++i) {
      dp[i] = 1;
      for(int j = 0; j < i; ++j) {
        if(envelopes[i][0] > envelopes[j][0] && envelopes[i][1] > envelopes[j][1] && dp[i] <= dp[j]) {
          dp[i] = dp[j] + 1;
        }
      }
    }
    return *max_element(dp, dp + len);
  }
};

$O(n\log n)$ solution

class Solution {
public:
  int maxEnvelopes(vector<vector<int>>& envelopes) {
    sort(envelopes.begin(), envelopes.end(), [](vector<int> &a, vector<int> &b) {
      return a[0] < b[0] || (a[0] == b[0] && a[1] > b[1]);
    });
    vector<int> dp;
    for(auto &e : envelopes) {
      auto it = lower_bound(dp.begin(), dp.end(), e[1]);
      if(it == dp.end()) {
        dp.push_back(e[1]);
      } else {
        *it = e[1];
      }
    }
    return dp.size();
  }
};