diff --git a/C++/01-matrix.cpp b/C++/01-matrix.cpp new file mode 100644 index 000000000..bb7c65b70 --- /dev/null +++ b/C++/01-matrix.cpp @@ -0,0 +1,37 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + vector> updateMatrix(vector>& matrix) { + queue> queue; + for (int i = 0; i < matrix.size(); ++i) { + for (int j = 0; j < matrix[0].size(); ++j) { + if (matrix[i][j] == 0) { + queue.emplace(i, j); + } + else { + matrix[i][j] = numeric_limits::max(); + } + } + } + + const vector> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + while (!queue.empty()) { + auto cell = queue.front(); + queue.pop(); + for (const auto& dir : dirs) { + auto i = cell.first + dir.first; + auto j = cell.second + dir.second; + if (i < 0 || i >= matrix.size() || j < 0 || j >= matrix[0].size() || + matrix[i][j] <= matrix[cell.first][cell.second] + 1) { + continue; + } + queue.emplace(i, j); + matrix[i][j] = matrix[cell.first][cell.second] + 1; + } + } + + return matrix; + } +}; diff --git a/C++/1-bit-and-2-bit-characters.cpp b/C++/1-bit-and-2-bit-characters.cpp new file mode 100644 index 000000000..cc075fea6 --- /dev/null +++ b/C++/1-bit-and-2-bit-characters.cpp @@ -0,0 +1,14 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isOneBitCharacter(vector& bits) { + auto parity = 0; + for (int i = static_cast(bits.size()) - 2; + i >= 0 && bits[i]; --i) { + parity ^= bits[i]; + } + return parity == 0; + } +}; diff --git a/C++/132-pattern.cpp b/C++/132-pattern.cpp new file mode 100644 index 000000000..c854b5dd1 --- /dev/null +++ b/C++/132-pattern.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + bool find132pattern(vector& nums) { + int ak = numeric_limits::min(); + stack st; + for (int i = nums.size() - 1; i >= 0; --i) { + if (nums[i] < ak) { + return true; + } else { + while (!st.empty() && nums[i] > st.top()) { + ak = st.top(), st.pop(); + } + } + st.emplace(nums[i]); + } + return false; + } +}; diff --git a/C++/2-keys-keyboard.cpp b/C++/2-keys-keyboard.cpp new file mode 100644 index 000000000..01343232d --- /dev/null +++ b/C++/2-keys-keyboard.cpp @@ -0,0 +1,18 @@ +// Time: O(sqrt(n)) +// Space: O(1) + +class Solution { +public: + int minSteps(int n) { + auto result = 0; + // the answer is the sum of prime factors + for (auto p = 2 ; p * p <= n; ++p) { + while (n % p == 0) { + result += p; + n /= p; + } + } + result += (n > 1) ? n : 0; + return result; + } +}; diff --git a/C++/24-game.cpp b/C++/24-game.cpp new file mode 100644 index 000000000..0bd48e540 --- /dev/null +++ b/C++/24-game.cpp @@ -0,0 +1,205 @@ +// Time: O(n^3 * 4^n) = O(1), n = 4 +// Space: O(n^2) = O(1) + +class Solution { +public: + bool judgePoint24(vector& nums) { + vector doubles; + std::transform(nums.begin(), nums.end(), std::back_inserter(doubles), + [](const int num) { return double(num); }); + return dfs(doubles); + } + +private: + bool dfs(const vector& nums) { + if (nums.size() == 1) { + return fabs(nums[0] - 24) < 1e-6; + } + static unordered_map> ops = + { + {'+', std::plus()}, + {'-', std::minus()}, + {'*', std::multiplies()}, + {'/', std::divides()}, + }; + for (int i = 0; i < nums.size(); ++i) { + for (int j = 0; j < nums.size(); ++j) { + if (i == j) { + continue; + } + vector next_nums; + for (int k = 0; k < nums.size(); ++k) { + if (k == i || k == j) { + continue; + } + next_nums.emplace_back(nums[k]); + } + for (const auto& op : ops) { + if (((op.first == '+' || op.first == '*') && i > j) || + (op.first == '/' && nums[j] == 0)) { + continue; + } + next_nums.emplace_back(op.second(nums[i], nums[j])); + if (dfs(next_nums)) { + return true; + } + next_nums.pop_back(); + } + } + } + return false; + } +}; + + +class Fraction { +public: + Fraction() = default; + Fraction(int n) + : Fraction(n, 1) + { + } + Fraction(int n, int d) + : numerator_(n) + , denominator_(d) + { + } + ~Fraction() = default; + + void set_num(int value) { numerator_ = value; } + void set_den(int value) { denominator_ = value; } + int get_num() const { return numerator_; } + int get_den() const { return denominator_; } + void reduce(); + int calculate_gcd(int, int) const; +private: + int numerator_, denominator_; +}; + +void Fraction::reduce() +{ + const auto gcd = calculate_gcd(numerator_, denominator_); + numerator_ = numerator_ / gcd; + denominator_ = denominator_ / gcd; +} + +int Fraction::calculate_gcd(int a, int b) const +{ + a = std::abs(a); + b = std::abs(b); + while (b != 0) { + int tmp = b; + b = a % b; + a = tmp; + } + return a; +} + +Fraction operator+(const Fraction& lhs, const Fraction& rhs) +{ + Fraction result{}; + + result.set_num((lhs.get_num() * rhs.get_den()) + (lhs.get_den() * rhs.get_num())); + result.set_den(lhs.get_den() * rhs.get_den()); + + result.reduce(); + + return result; +} + +Fraction operator-(const Fraction& lhs, const Fraction& rhs) +{ + Fraction result{}; + + result.set_num((lhs.get_num() * rhs.get_den()) - (lhs.get_den() * rhs.get_num())); + result.set_den(lhs.get_den() * rhs.get_den()); + + result.reduce(); + + return result; +} + +Fraction operator*(const Fraction& lhs, const Fraction& rhs) +{ + Fraction result{}; + + result.set_num(lhs.get_num() * rhs.get_num()); + result.set_den(lhs.get_den() * rhs.get_den()); + + result.reduce(); + + return result; +} + +Fraction operator/(const Fraction& lhs, const Fraction& rhs) +{ + Fraction result{}; + + result.set_num(lhs.get_num() * rhs.get_den()); + result.set_den(lhs.get_den() * rhs.get_num()); + + result.reduce(); + + return result; +} + +bool operator==(const Fraction &lhs, const Fraction &rhs) { + return (((lhs.get_num() * rhs.get_den()) - (rhs.get_num() * lhs.get_den())) == 0); +} + +std::ostream &operator<<(std::ostream &os, const Fraction &value) { + os << value.get_num() << "/" << value.get_den(); + return os; +} + +// Time: O(n^3 * 4^n) = O(1), n = 4 +// Space: O(n^2) = O(1) +class Solution2 { +public: + bool judgePoint24(vector& nums) { + vector fraction_nums; + std::transform(nums.begin(), nums.end(), std::back_inserter(fraction_nums), + [](const int num) { return Fraction(num); }); + return dfs(fraction_nums); + } + +private: + bool dfs(const vector& nums) { + if (nums.size() == 1) { + return nums[0] == 24; + } + static unordered_map> ops = + { + {'+', std::plus()}, + {'-', std::minus()}, + {'*', std::multiplies()}, + {'/', std::divides()}, + }; + for (int i = 0; i < nums.size(); ++i) { + for (int j = 0; j < nums.size(); ++j) { + if (i == j) { + continue; + } + vector next_nums; + for (int k = 0; k < nums.size(); ++k) { + if (k == i || k == j) { + continue; + } + next_nums.emplace_back(nums[k]); + } + for (const auto& op : ops) { + if (((op.first == '+' || op.first == '*') && i > j) || + (op.first == '/' && nums[j] == 0)) { + continue; + } + next_nums.emplace_back(op.second(nums[i], nums[j])); + if (dfs(next_nums)) { + return true; + } + next_nums.pop_back(); + } + } + } + return false; + } +}; diff --git a/C++/3sum-closest.cpp b/C++/3sum-closest.cpp new file mode 100644 index 000000000..02e0aaa7e --- /dev/null +++ b/C++/3sum-closest.cpp @@ -0,0 +1,44 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + /** + * @param numbers: Give an array numbers of n integer + * @param target: An integer + * @return: return the sum of the three integers, the sum closest target. + */ + int threeSumClosest(vector nums, int target) { + int ans = numeric_limits::max(); + int min_diff = numeric_limits::max(); + + // Make nums in increasing order. Time: O(nlogn) + sort(nums.begin(), nums.end()); + + for (int i = 0; i < static_cast(nums.size()) - 2; ++i) { + if (i == 0 || nums[i] != nums[i - 1]) { // Skip duplicated. + int j = i + 1; + int k = nums.size() - 1; + + while (j < k) { // Time: O(n) for each i. + const auto sum = nums[i] + nums[j] + nums[k]; + + if (sum > target) { // Should decrease sum. + --k; + } else if (sum < target) { // Should increase sum. + ++j; + } else { + return target; + } + + if (abs(sum - target) < min_diff) { + min_diff = abs(sum - target); + ans = sum; + } + } + } + } + + return ans; + } +}; diff --git a/C++/3sum-smaller.cpp b/C++/3sum-smaller.cpp new file mode 100644 index 000000000..db32ead82 --- /dev/null +++ b/C++/3sum-smaller.cpp @@ -0,0 +1,25 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + int threeSumSmaller(vector& nums, int target) { + sort(nums.begin(), nums.end()); + const int n = nums.size(); + + int count = 0; + for (int k = 2; k < n; ++k) { + int i = 0, j = k - 1; + while (i < j) { // Two Pointers, linear time. + if (nums[i] + nums[j] + nums[k] >= target) { + --j; + } else { + count += j - i; + ++i; + } + } + } + + return count; + } +}; diff --git a/C++/3sum.cpp b/C++/3sum.cpp new file mode 100644 index 000000000..d1889e4a8 --- /dev/null +++ b/C++/3sum.cpp @@ -0,0 +1,41 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + /** + * @param numbers : Give an array numbers of n integer + * @return : Find all unique triplets in the array which gives the sum of zero. + */ + vector> threeSum(vector &nums) { + vector> ans; + const int target = 0; + + // Make nums in increasing order. Time: O(nlogn) + sort(nums.begin(), nums.end()); + + for (int i = 0; i < static_cast(nums.size()) - 2; ++i) { + if (i == 0 || nums[i] != nums[i - 1]) { // Skip duplicated. + for (int j = i + 1, k = nums.size() - 1; j < k; ) { // Time: O(n) for each i. + if (j - 1 > i && nums[j] == nums[j - 1]) { // Skip duplicated. + ++j; + } else if (k + 1 < nums.size() && nums[k] == nums[k + 1]) { // Skip duplicated. + --k; + } else { + const auto sum = nums[i] + nums[j] + nums[k]; + if (sum > target) { // Should decrease sum. + --k; + } else if (sum < target) { // Should increase sum. + ++j; + } else { + ans.push_back({nums[i], nums[j], nums[k]}); + ++j, --k; + } + } + } + } + } + + return ans; + } +}; diff --git a/C++/4-keys-keyboard.cpp b/C++/4-keys-keyboard.cpp new file mode 100644 index 000000000..6ddccef1d --- /dev/null +++ b/C++/4-keys-keyboard.cpp @@ -0,0 +1,39 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int maxA(int N) { + if (N < 7) { + return N; + } + if (N == 10) { // the following rule doesn't hold when N = 10 + return 20; + } + auto n = N / 5 + 1; // n3 + n4 increases one every 5 keys + // (1) n = n3 + n4 + // (2) N + 1 = 4 * n3 + 5 * n4 + // 5 x (1) - (2) => 5*n - N - 1 = n3 + auto n3 = 5 * n - N - 1; + auto n4 = n - n3; + return pow(3, n3) * pow(4, n4); + } +}; + + +// Time: O(n) +// Space: O(1) +class Solution2 { +public: + int maxA(int N) { + if (N < 7) { + return N; + } + vector dp(6); + iota(dp.begin(), dp.end(), 0); + for (int i = 7; i <= N; ++i) { + dp[i % 6] = max(dp[(i - 4) % 6] * 3, dp[(i - 5) % 6] * 4); + } + return dp[N % 6]; + } +}; diff --git a/C++/4sum-ii.cpp b/C++/4sum-ii.cpp new file mode 100644 index 000000000..925945787 --- /dev/null +++ b/C++/4sum-ii.cpp @@ -0,0 +1,23 @@ +// Time: O(n^2) +// Space: O(n^2) + +class Solution { +public: + int fourSumCount(vector& A, vector& B, vector& C, vector& D) { + unordered_map A_B_sum; + for (const auto& a : A) { + for (const auto& b : B) { + ++A_B_sum[a + b]; + } + } + int result = 0; + for (const auto& c : C) { + for (const auto& d : D) { + if (A_B_sum.find(-c - d) != A_B_sum.end()) { + result += A_B_sum[-c - d]; + } + } + } + return result; + } +}; diff --git a/C++/4sum.cpp b/C++/4sum.cpp new file mode 100644 index 000000000..3687abf2d --- /dev/null +++ b/C++/4sum.cpp @@ -0,0 +1,79 @@ +// Time: O(n^3) +// Space: O(1) + +class Solution { +public: + vector > fourSum(vector &num, int target) { + int len = num.size(); + int left, right, sum; + sort(num.begin(), num.end()); + vector> res; + for (int i = 0; i < len - 3; ++i) { + if (i && num[i] == num[i - 1]) { + continue; + } + for (int j = i + 1; j < len - 2; ++j) { + if (j != i + 1 && num[j] == num[j - 1]) { + continue; + } + sum = target - num[i] - num[j]; + left = j + 1, right = len - 1; + while (left < right) { + if (num[left] + num[right] == sum) { + res.push_back({num[i], num[j], num[left], num[right]}); + ++left, --right; + while (left < right && num[left] == num[left - 1]) { + ++left; + } + while (left < right && num[right] == num[right + 1]) { + --right; + } + } else { + if (num[left] + num[right] > sum) { + --right; + } else { + ++left; + } + } + } + } + } + return res; + } +}; + +// Time: O(n^4) +// Space: O(n^2) +class Solution2 { +public: + vector > fourSum(vector &num, int target) { + vector> ans; + if (num.size() < 4) { + return ans; + } + sort(num.begin(), num.end()); + unordered_multimap> cache; + + for (int i = 0; i < num.size(); ++i) { + for (int j = i + 1; j < num.size(); ++j) { + cache.emplace(num[i] + num[j], make_pair(i, j)); + } + } + + for (auto i = cache.begin(); i != cache.end(); ++i) { + auto a = i->second.first; + auto b = i->second.second; + auto range = cache.equal_range(target - i->first); + for (auto j = range.first; j != range.second; ++j) { + auto c = j->second.first; + auto d = j->second.second; + if (b < c) { + ans.push_back({num[a], num[b], num[c], num[d]}); + } + } + } + sort(ans.begin(), ans.end()); + ans.erase(unique(ans.begin(), ans.end()), ans.end()); + return ans; + } +}; diff --git a/C++/accounts-merge.cpp b/C++/accounts-merge.cpp new file mode 100644 index 000000000..b4d27cc95 --- /dev/null +++ b/C++/accounts-merge.cpp @@ -0,0 +1,63 @@ +// Time: O(nlogn), n is the number of total emails, and the max length of email is 320, p.s. {64}@{255} +// Space: O(n) + +class Solution { +public: + vector> accountsMerge(vector>& accounts) { + UnionFind union_find; + unordered_map email_to_name; + unordered_map email_to_id; + for (const auto& account : accounts) { + const auto& name = account[0]; + for (int i = 1; i < account.size(); ++i) { + if (!email_to_id.count(account[i])) { + email_to_name[account[i]] = name; + email_to_id[account[i]] = union_find.get_id(); + } + union_find.union_set(email_to_id[account[1]], email_to_id[account[i]]); + } + } + + unordered_map> lookup; + for (const auto& kvp : email_to_name) { + const auto& email = kvp.first; + lookup[union_find.find_set(email_to_id[email])].emplace(email); + } + vector> result; + for (const auto& kvp : lookup) { + const auto& emails = kvp.second; + vector tmp{email_to_name[*emails.begin()]}; + for (const auto& email : emails) { + tmp.emplace_back(email); + } + result.emplace_back(move(tmp)); + } + return result; + } + +private: + class UnionFind { + public: + int get_id() { + set_.emplace_back(set_.size()); + return set_.size() - 1; + } + + int find_set(const int x) { + if (set_[x] != x) { + set_[x] = find_set(set_[x]); // Path compression. + } + return set_[x]; + } + + void union_set(const int x, const int y) { + int x_root = find_set(x), y_root = find_set(y); + if (x_root != y_root) { + set_[min(x_root, y_root)] = max(x_root, y_root); + } + } + + private: + vector set_; + }; +}; diff --git a/C++/add-and-search-word-data-structure-design.cpp b/C++/add-and-search-word-data-structure-design.cpp new file mode 100644 index 000000000..1968871e1 --- /dev/null +++ b/C++/add-and-search-word-data-structure-design.cpp @@ -0,0 +1,58 @@ +// Time: O(min(n, h)), per operation +// Space: O(min(n, h)) + +class WordDictionary { +public: + struct TrieNode { + bool isString = false; + unordered_map leaves; + }; + + WordDictionary() { + root_ = new TrieNode(); + root_->isString = true; + } + + // Adds a word into the data structure. + void addWord(string word) { + auto* p = root_; + for (const auto& c : word) { + if (p->leaves.find(c) == p->leaves.cend()) { + p->leaves[c] = new TrieNode; + } + p = p->leaves[c]; + } + p->isString = true; + } + + // Returns if the word is in the data structure. A word could + // contain the dot character '.' to represent any one letter. + bool search(string word) { + return searchWord(word, root_, 0); + } + + bool searchWord(string word, TrieNode *node, int s) { + if (s == word.length()) { + return node->isString; + } + // Match the char. + if (node->leaves.find(word[s]) != node->leaves.end()) { + return searchWord(word, node->leaves[word[s]], s + 1); + } else if (word[s] == '.') { // Skip the char. + for (const auto& i : node->leaves) { + if (searchWord(word, i.second, s + 1)) { + return true; + } + } + } + return false; + } + +private: + TrieNode *root_; +}; + +// Your WordDictionary object will be instantiated and called as such: +// WordDictionary wordDictionary; +// wordDictionary.addWord("word"); +// wordDictionary.search("pattern"); diff --git a/C++/add-binary.cpp b/C++/add-binary.cpp new file mode 100644 index 000000000..7a273e67d --- /dev/null +++ b/C++/add-binary.cpp @@ -0,0 +1,57 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string addBinary(string a, string b) { + string res; + size_t res_len = max(a.length(), b.length()) ; + + size_t carry = 0; + for (int i = 0; i < res_len; ++i) { + const size_t a_bit_i = i < a.length() ? a[a.length() - 1 - i] - '0' : 0; + const size_t b_bit_i = i < b.length() ? b[b.length() - 1 - i] - '0' : 0; + size_t sum = carry + a_bit_i + b_bit_i; + carry = sum / 2; + sum %= 2; + res.push_back('0' + sum); + } + if (carry) { + res.push_back('0' + carry); + } + reverse(res.begin(), res.end()); + + return res; + } +}; + +// Iterator solution. +class Solution2 { +public: + string addBinary(string a, string b) { + size_t carry = 0; + string res; + + for (auto a_it = a.rbegin(), b_it = b.rbegin(); a_it != a.rend() || b_it != b.rend();) { + const size_t a_bit_i = (a_it != a.rend()) ? *a_it - '0' : 0; + const size_t b_bit_i = (b_it != b.rend()) ? *b_it - '0' : 0; + size_t sum = a_bit_i + b_bit_i + carry; + carry = sum / 2; + sum %= 2; + res.push_back('0' + sum); + + if (a_it != a.rend()) { + ++a_it; + } + if (b_it != b.rend()) { + ++b_it; + } + } + if (carry) { + res.push_back('0' + carry); + } + reverse(res.begin(), res.end()); + + return res; + } +}; diff --git a/C++/add-bold-tag-in-string.cpp b/C++/add-bold-tag-in-string.cpp new file mode 100644 index 000000000..9e695c2c6 --- /dev/null +++ b/C++/add-bold-tag-in-string.cpp @@ -0,0 +1,28 @@ +// Time: O(s * d * l), l is the average string length +// Space: O(s) + +class Solution { +public: + string addBoldTag(string s, vector& dict) { + vector bold(s.length()); + for (const auto& d: dict) { + auto pos = -1; + while ((pos = s.find(d, pos + 1)) != string::npos) { + fill(bold.begin() + pos, bold.begin() + pos + d.length(), true); + } + } + string result; + bool prev = false; + for (int i = 0; i < s.length(); ++i) { + if (prev != bold[i]) { + result += prev ? "" : ""; + prev = bold[i]; + } + result.push_back(s[i]); + } + if (prev) { + result += ""; + } + return result; + } +}; \ No newline at end of file diff --git a/C++/add-digits.cpp b/C++/add-digits.cpp new file mode 100644 index 000000000..fe74f6818 --- /dev/null +++ b/C++/add-digits.cpp @@ -0,0 +1,9 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int addDigits(int num) { + return (num - 1) % 9 + 1; + } +}; diff --git a/C++/add-one-row-to-tree.cpp b/C++/add-one-row-to-tree.cpp new file mode 100644 index 000000000..32e307c79 --- /dev/null +++ b/C++/add-one-row-to-tree.cpp @@ -0,0 +1,28 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* addOneRow(TreeNode* root, int v, int d) { + if (d == 0 || d == 1) { + auto node = new TreeNode(v); + (d == 1 ? node->left : node->right) = root; + return node; + } + if (root && d >= 2) { + root->left = addOneRow(root->left, v, d > 2 ? d - 1 : 1); + root->right = addOneRow(root->right, v, d > 2 ? d - 1 : 0); + } + return root; + } +}; + diff --git a/C++/add-strings.cpp b/C++/add-strings.cpp new file mode 100644 index 000000000..11c811ee6 --- /dev/null +++ b/C++/add-strings.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string addStrings(string num1, string num2) { + string result; + + for (int i = num1.size() - 1, j = num2.size() - 1, carry = 0; + i >= 0 || j >= 0 || carry; + carry /= 10) { + + if (i >= 0) { + carry += num1[i--] - '0'; + } + if (j >= 0) { + carry += num2[j--] - '0'; + } + result += to_string(carry % 10); + } + reverse(result.begin(), result.end()); + + return result; + } +}; diff --git a/C++/add-two-numbers-ii.cpp b/C++/add-two-numbers-ii.cpp new file mode 100644 index 000000000..a1f4707d9 --- /dev/null +++ b/C++/add-two-numbers-ii.cpp @@ -0,0 +1,51 @@ +// Time: O(m + n) +// Space: O(m + n) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + stack stk1, stk2; + while (l1) { + stk1.emplace(l1->val); + l1 = l1->next; + } + while (l2) { + stk2.emplace(l2->val); + l2 = l2->next; + } + + ListNode *prev = nullptr, *head = nullptr; + int sum = 0; + while (!stk1.empty() || !stk2.empty()) { + sum /= 10; + if (!stk1.empty()) { + sum += stk1.top(); + stk1.pop(); + } + + if (!stk2.empty()) { + sum += stk2.top(); + stk2.pop(); + } + + head = new ListNode(sum % 10); + head->next = prev; + prev = head; + } + + if (sum >= 10) { + head = new ListNode(sum / 10); + head->next = prev; + } + + return head; + } +}; diff --git a/C++/add-two-numbers.cpp b/C++/add-two-numbers.cpp new file mode 100644 index 000000000..1715de77e --- /dev/null +++ b/C++/add-two-numbers.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + ListNode dummy{0}; + auto curr = &dummy; + + auto carry = 0; + while (l1 || l2 || carry) { + auto a = l1? l1->val : 0, b = l2? l2->val : 0; + auto val = carry + a + b; + curr->next = new ListNode(val % 10); + carry = val / 10; + l1 = l1 ? l1->next : nullptr; + l2 = l2 ? l2->next : nullptr; + curr = curr->next; + } + + return dummy.next; + } +}; diff --git a/C++/addBinary.cpp b/C++/addBinary.cpp deleted file mode 100644 index 585618ce6..000000000 --- a/C++/addBinary.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - string addBinary(string a, string b) { - size_t carry = 0; - string ans; - - for(auto ai = a.rbegin(), bi = b.rbegin(); ai != a.rend() || bi != b.rend();) { - const size_t av = (ai != a.rend())? *ai - '0' : 0; - const size_t bv = (bi != b.rend())? *bi - '0' : 0; - const size_t val = (av + bv + carry) % 2; - carry = (av + bv + carry) / 2; - ans.push_back( val + '0' ); - - if(ai != a.rend()) - ++ai; - if(bi != b.rend()) - ++bi; - } - if(carry) - ans.push_back('1'); - - reverse(ans.begin(), ans.end()); - - return ans; - } -}; diff --git a/C++/addTwoNumbers.cpp b/C++/addTwoNumbers.cpp deleted file mode 100644 index b921dc8b8..000000000 --- a/C++/addTwoNumbers.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { - ListNode dummy(INT_MIN); - ListNode *p = &dummy; - int carry = 0; - - for(; l1 || l2; p = p->next) { - const int v1 = (l1)? l1->val : 0; - const int v2 = (l2)? l2->val : 0; - p->next = new ListNode((v1 + v2 + carry) % 10); - carry = (v1 + v2 + carry) / 10; - if(l1) l1 = l1->next; - if(l2) l2 = l2->next; - } - - if(carry) - p->next = new ListNode(carry); - - return dummy.next; - } -}; diff --git a/C++/additive-number.cpp b/C++/additive-number.cpp new file mode 100644 index 000000000..4be80dd35 --- /dev/null +++ b/C++/additive-number.cpp @@ -0,0 +1,52 @@ +// Time: O(n^3) +// Space: O(n) + +class Solution { +public: + bool isAdditiveNumber(string num) { + for (int i = 1; i < num.length(); ++i) { + for (int j = i + 1; j < num.length(); ++j) { + string s1 = num.substr(0, i), s2 = num.substr(i, j - i); + if ((s1.length() > 1 && s1[0] == '0') || + (s2.length() > 1 && s2[0] == '0')) { + continue; + } + + string next = add(s1, s2); + string cur = s1 + s2 + next; + while (cur.length() < num.length()) { + s1 = s2; + s2 = next; + next = add(s1, s2); + cur += next; + } + if (cur == num) { + return true; + } + } + } + return false; + } + +private: + string add(const string& m, const string& n) { + string res; + int res_length = max(m.length(), n.length()) ; + + int carry = 0; + for (int i = 0; i < res_length; ++i) { + int m_digit_i = i < m.length() ? m[m.length() - 1 - i] - '0' : 0; + int n_digit_i = i < n.length() ? n[n.length() - 1 - i] - '0' : 0; + int sum = carry + m_digit_i + n_digit_i; + carry = sum / 10; + sum %= 10; + res.push_back('0' + sum); + } + if (carry) { + res.push_back('0' + carry); + } + reverse(res.begin(), res.end()); + + return res; + } +}; diff --git a/C++/alien-dictionary.cpp b/C++/alien-dictionary.cpp new file mode 100644 index 000000000..f7a8bc8f4 --- /dev/null +++ b/C++/alien-dictionary.cpp @@ -0,0 +1,222 @@ +// Time: O(n) +// Space: O(|V|+|E|) = O(26 + 26^2) = O(1) + +// BFS solution. +class Solution { +public: + string alienOrder(vector& words) { + unordered_set nodes; + unordered_map> in_degree, out_degree; + queue zero_in_degree_queue; + for (const auto& word : words) { + for (const auto& c : word) { + nodes.emplace(c); + } + } + for (int i = 1; i < words.size(); ++i) { + if (words[i - 1].length() > words[i].length() && + words[i - 1].substr(0, words[i].length()) == words[i]) { + return ""; + } + findEdges(words[i - 1], words[i], &in_degree, &out_degree); + } + for (const auto& node : nodes) { + if (in_degree.find(node) == in_degree.end()) { + zero_in_degree_queue.emplace(node); + } + } + + // BFS + string result; + while (!zero_in_degree_queue.empty()) { + const auto& precedence = zero_in_degree_queue.front(); + zero_in_degree_queue.pop(); + result.push_back(precedence); + + if (out_degree.find(precedence) != out_degree.end()) { + for (const auto& c : out_degree[precedence]) { + in_degree[c].erase(precedence); + if (in_degree[c].empty()) { + zero_in_degree_queue.emplace(c); + } + } + out_degree.erase(precedence); + } + } + + if (!out_degree.empty()) { + return ""; + } + + return result; + } + +private: + // Construct the graph. + void findEdges(const string &word1, const string &word2, + unordered_map> *in_degree, + unordered_map> *out_degree) { + const int len = min(word1.length(), word2.length()); + for (int i = 0; i < len; ++i) { + if (word1[i] != word2[i]) { + (*in_degree)[word2[i]].emplace(word1[i]); + (*out_degree)[word1[i]].emplace(word2[i]); + break; + } + } + } +}; + +// DFS solution. +class Solution2 { +public: + string alienOrder(vector& words) { + // Find ancestors of each node by DFS. + unordered_set nodes; + unordered_map> ancestors; + for (int i = 0; i < words.size(); ++i) { + for (const auto& c : words[i]) { + nodes.emplace(c); + } + if (i > 0) { + findEdges(words[i - 1], words[i], &ancestors); + } + } + + // Output topological order by DFS. + string result; + unordered_map visited; + for (const auto& node : nodes) { + if (topSortDFS(node, node, &ancestors, &visited, &result)) { + return ""; + } + } + + return result; + } + +private: + // Construct the graph. + void findEdges(const string &word1, const string &word2, + unordered_map> *ancestors) { + const int len = min(word1.length(), word2.length()); + for (int i = 0; i < len; ++i) { + if (word1[i] != word2[i]) { + (*ancestors)[word2[i]].emplace_back(word1[i]); + break; + } + } + } + + // Topological sort, return whether there is a cycle. + bool topSortDFS(const char& root, + const char& node, + unordered_map> *ancestors, + unordered_map *visited, + string *result) { + if (visited->emplace(make_pair(node, root)).second) { + for (auto& ancestor: (*ancestors)[node]) { + if (topSortDFS(root, ancestor, ancestors, visited, result)) { + return true; + } + } + result->push_back(node); + } else if ((*visited)[node] == root) { + // Visited from the same root in the DFS path. + // So it is cyclic. + return true; + } + return false; + } +}; + +// DFS with adjacency matrix solution. +class Solution3 { +public: + string alienOrder(vector& words) { + string result; + vector> graph(26, vector(26)); + findDependency(words, &graph); + findOrder(&graph, &result); + return result; + } + +private: + void findEdges(const string &word1, const string &word2, vector> *graph) { + const int len = min(word1.length(), word2.length()); + for (int i = 0; i < len; ++i) { + if (word1[i] != word2[i]) { + (*graph)[word1[i] - 'a'][word2[i] - 'a'] = true; + break; + } + } + } + + // Construct the graph. + void findDependency(const vector& words, vector> *graph) { + for (const auto& c : words[0]) { + (*graph)[c - 'a'][c - 'a'] = true; + } + for (int i = 1; i < words.size(); ++i) { + for (const auto& c : words[i]) { + (*graph)[c - 'a'] [c - 'a'] = true; + } + findEdges(words[i - 1], words[i], graph); + } + } + + // Topological sort, return whether there is a cycle. + bool topSortDFS(string *result, vector *visited, + vector> *graph, const int root) { + if ((*visited)[root]) { + result->clear(); + return true; + } + (*visited)[root] = true; + for (int i = 0; i < 26; ++i) { + if (i != root && (*graph)[root][i]) { + if (topSortDFS(result, visited, graph, i)) { + return true; + } + } + } + (*graph)[root][root] = false; + result->push_back(root + 'a'); + return false; + } + + void findOrder(vector> *graph, string *result) { + for (int i = 0; i < 26; ++i) { + // Find a root node. + bool root_node = (*graph)[i][i]; + if ((*graph)[i][i]) { + for (int j = 0; j < 26; ++j) { + if (j != i && (*graph)[j][i]) { + root_node = false; + break; + } + } + } + if (root_node) { + string reversed_order = ""; + vector visited(26, false); + if (topSortDFS(&reversed_order, &visited, graph, i)) { + result->clear(); + return; + } else { + result->append(reversed_order); + } + } + } + + // If there is any unvisited node, return "". + for (int i = 0; i < 26; ++i) { + if ((*graph)[i][i]) { + result->clear(); + return; + } + } + // The order should be reversed. + reverse(result->begin(), result->end()); + } +}; diff --git a/C++/all-oone-data-structure.cpp b/C++/all-oone-data-structure.cpp new file mode 100644 index 000000000..f3f81ccb5 --- /dev/null +++ b/C++/all-oone-data-structure.cpp @@ -0,0 +1,79 @@ +// Time: O(1), per operation +// Space: O(k) + +class AllOne { +public: + /** Initialize your data structure here. */ + AllOne() { + + } + + /** Inserts a new key with value 1. Or increments an existing key by 1. */ + void inc(string key) { + if (!bucketOfKey_.count(key)) { + bucketOfKey_[key] = buckets_.insert(buckets_.begin(), {0, {key}}); + } + + auto next = bucketOfKey_[key], bucket = next++; + if (next == buckets_.end() || next->value > bucket->value + 1) { + next = buckets_.insert(next, {bucket->value + 1, {}}); + } + next->keys.insert(key); + bucketOfKey_[key] = next; + + bucket->keys.erase(key); + if (bucket->keys.empty()) { + buckets_.erase(bucket); + } + } + + /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */ + void dec(string key) { + if (!bucketOfKey_.count(key)) { + return; + } + + auto prev = bucketOfKey_[key], bucket = prev--; + bucketOfKey_.erase(key); + if (bucket->value > 1) { + if (bucket == buckets_.begin() || prev->value < bucket->value - 1) { + prev = buckets_.insert(bucket, {bucket->value - 1, {}}); + } + prev->keys.insert(key); + bucketOfKey_[key] = prev; + } + + bucket->keys.erase(key); + if (bucket->keys.empty()) { + buckets_.erase(bucket); + } + } + + /** Returns one of the keys with maximal value. */ + string getMaxKey() { + return buckets_.empty() ? "" : *(buckets_.rbegin()->keys.begin()); + } + + /** Returns one of the keys with Minimal value. */ + string getMinKey() { + return buckets_.empty() ? "" : *(buckets_.begin()->keys.begin()); + } + +private: + struct Bucket { + int value; + unordered_set keys; + }; + list buckets_; + unordered_map::iterator> bucketOfKey_; +}; + +/** + * Your AllOne object will be instantiated and called as such: + * AllOne obj = new AllOne(); + * obj.inc(key); + * obj.dec(key); + * string param_3 = obj.getMaxKey(); + * string param_4 = obj.getMinKey(); + */ + diff --git a/C++/anagrams.cpp b/C++/anagrams.cpp index 1ca89dc01..dbac16f6a 100644 --- a/C++/anagrams.cpp +++ b/C++/anagrams.cpp @@ -1,22 +1,26 @@ -// Time Complexity: O(klogk * n) ~= O(n), k is length of string, n is number of strings -// Space Complexity: O(k * n) ~= O(n) +// Time: O(n * glogg), g is the max size of groups. +// Space: O(n) class Solution { - public: - vector anagrams(vector &strs) { - vector ans; - unordered_map > group; - for(auto s : strs) { - string k = s; - sort(k.begin(), k.end()); - group[k].push_back(s); - } +public: + vector> groupAnagrams(vector& strs) { + unordered_map> groups; + for (const auto& str : strs) { + string tmp{str}; + sort(tmp.begin(), tmp.end()); + groups[tmp].emplace_back(str); + } - for(auto it = group.cbegin(); it != group.cend(); ++it) { - if(it->second.size() > 1) - ans.insert(ans.end(), it->second.begin(), it->second.end()); + vector> anagrams; + for (const auto& kvp : groups) { + vector group; + for (const auto& str : kvp.second) { + group.emplace_back(str); } - - return ans; + sort(group.begin(), group.end()); + anagrams.emplace_back(move(group)); } -};` + + return anagrams; + } +}; diff --git a/C++/android-unlock-patterns.cpp b/C++/android-unlock-patterns.cpp new file mode 100644 index 000000000..6e49d0f97 --- /dev/null +++ b/C++/android-unlock-patterns.cpp @@ -0,0 +1,208 @@ +// Time: O(9^2 * 2^9) +// Space: O(9 * 2^9) + +// DP solution. +class Solution { +public: + int numberOfPatterns(int m, int n) { + // dp[i][j]: i is the set of the numbers in binary representation, + // dp[i][j] is the number of ways ending with the number j. + vector> dp(1 << 9 , vector(9, 0)); + for (int i = 0; i < 9; ++i) { + dp[merge(0, i)][i] = 1; + } + + int res = 0; + for (int used = 0; used < dp.size(); ++used) { + const auto number = number_of_keys(used); + if (number > n) { + continue; + } + for (int i = 0; i < 9; ++i) { + if (!contain(used, i)) { + continue; + } + if (m <= number && number <= n) { + res += dp[used][i]; + } + + const auto x1 = i / 3; + const auto y1 = i % 3; + for (int j = 0; j < 9; ++j) { + if (contain(used, j)) { + continue; + } + const auto x2 = j / 3; + const auto y2 = j % 3; + if (((x1 == x2 && abs(y1 - y2) == 2) || + (y1 == y2 && abs(x1 - x2) == 2) || + (abs(x1 - x2) == 2 && abs(y1 - y2) == 2)) && + !contain(used, convert((x1 + x2) / 2, (y1 + y2) / 2))) { + continue; + } + dp[merge(used, j)][j] += dp[used][i]; + } + } + } + + return res; + } + +private: + inline int merge(int i, int j) { + return i | (1 << j); + } + + inline int number_of_keys(int i) { + int number = 0; + for (; i; i &= i - 1) { + ++number; + } + return number; + } + + inline bool contain(int i, int j) { + return i & (1 << j); + } + + inline int convert(int i, int j) { + return 3 * i + j; + } +}; + + +// Time: O(9^2 * 2^9) +// Space: O(9 * 2^9) +// DP solution. +class Solution2 { +public: + int numberOfPatterns(int m, int n) { + // dp[i][j]: i is the set of the numbers in binary representation, + // dp[i][j] is the number of ways ending with the number j. + vector> dp(1 << 9 , vector(9, 0)); + for (int i = 0; i < 9; ++i) { + dp[merge(0, i)][i] = 1; + } + + int res = 0; + for (int used = 0; used < dp.size(); ++used) { + const auto number = number_of_keys(used); + if (number > n) { + continue; + } + for (int i = 0; i < 9; ++i) { + if (!contain(used, i)) { + continue; + } + + const auto x1 = i / 3; + const auto y1 = i % 3; + for (int j = 0; j < 9; ++j) { + if (i == j || !contain(used, j)) { + continue; + } + const auto x2 = j / 3; + const auto y2 = j % 3; + if (((x1 == x2 && abs(y1 - y2) == 2) || + (y1 == y2 && abs(x1 - x2) == 2) || + (abs(x1 - x2) == 2 && abs(y1 - y2) == 2)) && + !contain(used, convert((x1 + x2) / 2, (y1 + y2) / 2))) { + continue; + } + dp[used][i] += dp[exclude(used, i)][j]; + } + if (m <= number && number <= n) { + res += dp[used][i]; + } + } + } + + return res; + } + +private: + inline int merge(int i, int j) { + return i | (1 << j); + } + + inline int number_of_keys(int i) { + int number = 0; + for (; i; i &= i - 1) { + ++number; + } + return number; + } + + inline bool contain(int i, int j) { + return i & (1 << j); + } + + inline int exclude(int i, int j) { + return i & ~(1 << j); + } + + inline int convert(int i, int j) { + return 3 * i + j; + } +}; + + +// Time: O(9!) +// Space: O(9) +// Backtracking solution. +class Solution3 { +public: + int numberOfPatterns(int m, int n) { + int number = 0; + // 1, 3, 5, 7 + number += 4 * numberOfPatternsHelper(m, n, 1, merge(0, 0), 0); + // 2, 4, 6, 8 + number += 4 * numberOfPatternsHelper(m, n, 1, merge(0, 1), 1); + // 5 + number += numberOfPatternsHelper(m, n, 1, merge(0, 4), 4); + return number; + } + +private: + int numberOfPatternsHelper(int m, int n, int level, int used, int i) { + int number = 0; + if (level > n) { + return number; + } + if (level >= m) { + ++number; + } + + const auto x1 = i / 3; + const auto y1 = i % 3; + for (int j = 0; j < 9; ++j) { + if (contain(used, j)) { + continue; + } + const auto x2 = j / 3; + const auto y2 = j % 3; + if (((x1 == x2 && abs(y1 - y2) == 2) || + (y1 == y2 && abs(x1 - x2) == 2) || + (abs(x1 - x2) == 2 && abs(y1 - y2) == 2)) && + !contain(used, convert((x1 + x2) / 2, (y1 + y2) / 2))) { + continue; + } + number += numberOfPatternsHelper(m, n, level + 1, merge(used, j), j); + } + + return number; + } + +private: + inline int merge(int i, int j) { + return i | (1 << j); + } + + inline bool contain(int i, int j) { + return i & (1 << j); + } + + inline int convert(int i, int j) { + return 3 * i + j; + } +}; diff --git a/C++/arithmetic-slices-ii-subsequence.cpp b/C++/arithmetic-slices-ii-subsequence.cpp new file mode 100644 index 000000000..5e20aacf1 --- /dev/null +++ b/C++/arithmetic-slices-ii-subsequence.cpp @@ -0,0 +1,21 @@ +// Time: O(n^2) +// Space: O(n * d) + +class Solution { +public: + int numberOfArithmeticSlices(vector& A) { + int result = 0; + vector> dp(A.size()); + for (int i = 1; i < A.size(); ++i) { + for (int j = 0; j < i; ++j) { + const auto diff = static_cast(A[i]) - A[j]; + ++dp[i][diff]; + if (dp[j].count(diff)) { + dp[i][diff] += dp[j][diff]; + result += dp[j][diff]; + } + } + } + return result; + } +}; diff --git a/C++/arithmetic-slices.cpp b/C++/arithmetic-slices.cpp new file mode 100644 index 000000000..f6430fbac --- /dev/null +++ b/C++/arithmetic-slices.cpp @@ -0,0 +1,16 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int numberOfArithmeticSlices(vector& A) { + int res = 0, i = 0; + for (int i = 0; i + 2 < A.size(); ++i) { + const auto start = i; + while (i + 2 < A.size() && A[i + 2] + A[i] == 2 * A[i + 1]) { + res += (i++) - start + 1; + } + } + return res; + } +}; diff --git a/C++/arranging-coins.cpp b/C++/arranging-coins.cpp new file mode 100644 index 000000000..f25a3e364 --- /dev/null +++ b/C++/arranging-coins.cpp @@ -0,0 +1,27 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int arrangeCoins(int n) { + return static_cast((sqrt(8.0 * n + 1) - 1) / 2); + } +}; + +// Time: O(logn) +// Space: O(1) +class Solution2 { +public: + int arrangeCoins(int n) { + long long left = 1, right = n; + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (2L * n < mid * (mid + 1)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left - 1; + } +}; diff --git a/C++/array-nesting.cpp b/C++/array-nesting.cpp new file mode 100644 index 000000000..2dc891643 --- /dev/null +++ b/C++/array-nesting.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int arrayNesting(vector& nums) { + auto result = 0; + for (const auto& num : nums) { + if (num != numeric_limits::max()) { + auto start = num, count = 0; + while (nums[start] != numeric_limits::max()) { + auto temp = start; + start = nums[start]; + nums[temp] = numeric_limits::max(); + ++count; + } + result = max(result, count); + } + } + return result; + } +}; diff --git a/C++/array-partition-i.cpp b/C++/array-partition-i.cpp new file mode 100644 index 000000000..2bd831e8f --- /dev/null +++ b/C++/array-partition-i.cpp @@ -0,0 +1,34 @@ +// Time: O(r), r is the range size of the integers +// Space: O(r) + +class Solution { +public: + int arrayPairSum(vector& nums) { + const auto LEFT = -10000; + const auto RIGHT = 10000; + vector lookup(RIGHT - LEFT + 1, 0); + for (const auto& num: nums) { + ++lookup[num - LEFT]; + } + auto r = 0, result = 0; + for (int i = LEFT; i <= RIGHT; ++i) { + result += (lookup[i - LEFT] + 1 - r) / 2 * i; + r = (lookup[i - LEFT] + r) % 2; + } + return result; + } +}; + +// Time: O(nlogn) +// Space: O(1) +class Solution2 { +public: + int arrayPairSum(vector& nums) { + sort(nums.begin(), nums.end()); + auto result = 0; + for (auto i = 0; i < nums.size(); i += 2) { + result += nums[i]; + } + return result; + } +}; diff --git a/C++/assign-cookies.cpp b/C++/assign-cookies.cpp new file mode 100644 index 000000000..3daae8a7c --- /dev/null +++ b/C++/assign-cookies.cpp @@ -0,0 +1,22 @@ +// Time: O(nlogn) +// Space: O(1) + +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + + int result = 0; + for (int i = 0, j = 0; j < s.size(); ++j) { + if (i == g.size()) { + break; + } + if (s[j] >= g[i]) { + ++i; + ++result; + } + } + return result; + } +}; diff --git a/C++/asteroid-collision.cpp b/C++/asteroid-collision.cpp new file mode 100644 index 000000000..6a647dff4 --- /dev/null +++ b/C++/asteroid-collision.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector asteroidCollision(vector& asteroids) { + vector result; + for (const auto& asteroid : asteroids) { + bool is_exploded = false; + while (!result.empty() && asteroid < 0 && 0 < result.back()) { + if (result.back() < -asteroid) { + result.pop_back(); + continue; + } else if (result.back() == -asteroid) { + result.pop_back(); + } + is_exploded = true; + break; + } + if (!is_exploded) { + result.emplace_back(asteroid); + } + } + return result; + } +}; diff --git a/C++/atoi.cpp b/C++/atoi.cpp deleted file mode 100644 index f2256ec0e..000000000 --- a/C++/atoi.cpp +++ /dev/null @@ -1,35 +0,0 @@ - -// LeetCode, String to Integer (atoi) -// Complexity: -// O(n) time -// O(1) space - -class Solution { -public: - int atoi(const char *str) { - int num = 0; - int sign = 1; - const int n = strlen(str); - int i = 0; - while (str[i] == ' ' && i < n) i++; - // parse sign - if (str[i] == '+') i++; - if (str[i] == '-') { - sign = -1; - i++; - } - - for (; i < n; i++) { - // handle non-digital character - if (str[i] < '0' || str[i] > '9') - break; - // handle overflow - if ( num > INT_MAX / 10 - || (num == INT_MAX / 10 && (str[i] - '0') > INT_MAX % 10)) { - return sign == -1 ? INT_MIN : INT_MAX; - } - num = num * 10 + str[i] - '0'; - } - return num * sign; - } -}; \ No newline at end of file diff --git a/C++/average-of-levels-in-binary-tree.cpp b/C++/average-of-levels-in-binary-tree.cpp new file mode 100644 index 000000000..731edd9ee --- /dev/null +++ b/C++/average-of-levels-in-binary-tree.cpp @@ -0,0 +1,40 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector averageOfLevels(TreeNode* root) { + vector result; + queue q; + q.emplace(root); + while (!q.empty()) { + long long sum = 0, count = 0; + queue next; + while (!q.empty()) { + auto n = q.front(); + q.pop(); + sum += n->val; + ++count; + if (n->left) { + next.emplace(n->left); + } + if (n->right) { + next.emplace(n->right); + } + } + swap(q, next); + result.emplace_back(sum * 1.0 / count); + } + return result; + } +}; + diff --git a/C++/base-7.cpp b/C++/base-7.cpp new file mode 100644 index 000000000..e568211c3 --- /dev/null +++ b/C++/base-7.cpp @@ -0,0 +1,31 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + string convertToBase7(int num) { + if (num < 0) { + return string("-").append(convertToBase7(-num)); + } + string result; + while (num) { + result.append(to_string(num % 7)); + num /= 7; + } + reverse(result.begin(), result.end()); + return result.empty() ? "0" : result; + } +}; + +class Solution2 { +public: + string convertToBase7(int num) { + if (num < 0) { + return string("-").append(convertToBase7(-num)); + } + if (num < 7) { + return to_string(num); + } + return convertToBase7(num / 7).append(to_string(num % 7)); + } +}; diff --git a/C++/baseball-game.cpp b/C++/baseball-game.cpp new file mode 100644 index 000000000..b696962d5 --- /dev/null +++ b/C++/baseball-game.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int calPoints(vector& ops) { + vector records; + for (const auto& op : ops) { + if (op == "+") { + records.emplace_back(records[records.size() - 2] + records.back()); + } else if (op == "D") { + records.emplace_back(2 * records.back()); + } else if (op == "C") { + records.pop_back(); + } else { + records.emplace_back(stoi(op)); + } + } + return accumulate(records.begin(), records.end(), 0); + } +}; diff --git a/C++/basic-calculator-ii.cpp b/C++/basic-calculator-ii.cpp new file mode 100644 index 000000000..e9cb14484 --- /dev/null +++ b/C++/basic-calculator-ii.cpp @@ -0,0 +1,59 @@ +// Time: O(n) +// Space: O(n) + +// Support +, -, *, /. +class Solution { +public: + int calculate(string s) { + stack operands; + stack operators; + string operand; + for (int i = s.length() - 1; i >= 0; --i) { + if (isdigit(s[i])) { + operand.push_back(s[i]); + if (i == 0 || !isdigit(s[i - 1])) { + reverse(operand.begin(), operand.end()); + operands.emplace(stol(operand)); + operand.clear(); + } + } else if (s[i] == ')' || s[i] == '*' || + s[i] == '/') { + operators.emplace(s[i]); + } else if (s[i] == '+' || s[i] == '-') { + while (!operators.empty() && (operators.top() == '*' || + operators.top() == '/')) { + compute(operands, operators); + } + operators.emplace(s[i]); + } else if (s[i] == '(') { + // operators at least one element, i.e. ')'. + while (operators.top() != ')') { + compute(operands, operators); + } + operators.pop(); + } + } + while (!operators.empty()) { + compute(operands, operators); + } + return operands.top(); + } + + void compute(stack& operands, stack& operators) { + const int64_t left = operands.top(); + operands.pop(); + const int64_t right = operands.top(); + operands.pop(); + const char op = operators.top(); + operators.pop(); + if (op == '+') { + operands.emplace(left + right); + } else if (op == '-') { + operands.emplace(left - right); + } else if (op == '*') { + operands.emplace(left * right); + } else if (op == '/') { + operands.emplace(left / right); + } + } +}; diff --git a/C++/basic-calculator.cpp b/C++/basic-calculator.cpp new file mode 100644 index 000000000..1201fe524 --- /dev/null +++ b/C++/basic-calculator.cpp @@ -0,0 +1,106 @@ +// Time: O(n) +// Space: O(n) + +// Support +, -, *, /. +class Solution { +public: + int calculate(string s) { + stack operands; + stack operators; + string operand; + for (int i = s.length() - 1; i >= 0; --i) { + if (isdigit(s[i])) { + operand.push_back(s[i]); + if (i == 0 || !isdigit(s[i - 1])) { + reverse(operand.begin(), operand.end()); + operands.emplace(stol(operand)); + operand.clear(); + } + } else if (s[i] == ')' || s[i] == '*' || + s[i] == '/') { + operators.emplace(s[i]); + } else if (s[i] == '+' || s[i] == '-') { + while (!operators.empty() && (operators.top() == '*' || + operators.top() == '/')) { + compute(operands, operators); + } + operators.emplace(s[i]); + } else if (s[i] == '(') { + // operators at least one element, i.e. ')'. + while (operators.top() != ')') { + compute(operands, operators); + } + operators.pop(); + } + } + while (!operators.empty()) { + compute(operands, operators); + } + return operands.top(); + } + + void compute(stack& operands, stack& operators) { + const int64_t left = operands.top(); + operands.pop(); + const int64_t right = operands.top(); + operands.pop(); + const char op = operators.top(); + operators.pop(); + if (op == '+') { + operands.emplace(left + right); + } else if (op == '-') { + operands.emplace(left - right); + } else if (op == '*') { + operands.emplace(left * right); + } else if (op == '/') { + operands.emplace(left / right); + } + } +}; + +// Time: O(n) +// Space: O(n) +// Only support +, -. +class Solution2 { +public: + int calculate(string s) { + stack operands; + stack operators; + string operand; + for (int i = s.length() - 1; i >= 0; --i) { + if (isdigit(s[i])) { + operand.push_back(s[i]); + if (i == 0 || !isdigit(s[i - 1])) { + reverse(operand.begin(), operand.end()); + operands.emplace(stoi(operand)); + operand.clear(); + } + } else if (s[i] == ')' || s[i] == '+' || s[i] == '-') { + operators.emplace(s[i]); + } else if (s[i] == '(') { + while (operators.top() != ')') { + compute(operands, operators); + } + operators.pop(); + } + } + while (!operators.empty()) { + compute(operands, operators); + } + return operands.top(); + } + + void compute(stack& operands, stack& operators) { + const int left = operands.top(); + operands.pop(); + const int right = operands.top(); + operands.pop(); + const char op = operators.top(); + operators.pop(); + if (op == '+') { + operands.emplace(left + right); + } else if (op == '-') { + operands.emplace(left - right); + } + } +}; diff --git a/C++/battleships-in-a-board.cpp b/C++/battleships-in-a-board.cpp new file mode 100644 index 000000000..f3bd89683 --- /dev/null +++ b/C++/battleships-in-a-board.cpp @@ -0,0 +1,21 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + int countBattleships(vector>& board) { + if (board.empty() || board[0].empty()) { + return 0; + } + + int cnt = 0; + for (int i = 0; i < board.size(); ++i) { + for (int j = 0; j < board[0].size(); ++j) { + cnt += board[i][j] == 'X' && + (i == 0 || board[i - 1][j] != 'X') && + (j == 0 || board[i][j - 1] != 'X'); + } + } + return cnt; + } +}; diff --git a/C++/beautiful-arrangement-ii.cpp b/C++/beautiful-arrangement-ii.cpp new file mode 100644 index 000000000..26afe6cca --- /dev/null +++ b/C++/beautiful-arrangement-ii.cpp @@ -0,0 +1,17 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector constructArray(int n, int k) { + vector result; + int left = 1, right = n; + while (left <= right) { + result.emplace_back(k % 2 ? left++ : right--); + if (k > 1) { + --k; + } + } + return result; + } +}; diff --git a/C++/beautiful-arrangement.cpp b/C++/beautiful-arrangement.cpp new file mode 100644 index 000000000..b2ca85574 --- /dev/null +++ b/C++/beautiful-arrangement.cpp @@ -0,0 +1,27 @@ +// Time: O(n!) +// Space: O(n) + +class Solution { +public: + int countArrangement(int N) { + vector arrangement(N); + iota(arrangement.begin(), arrangement.end(), 1); + return countArrangementHelper(N, &arrangement); + } + +private: + int countArrangementHelper(int n, vector *arrangement) { + if (n <= 0) { + return 1; + } + int count = 0; + for (int i = 0; i < n; ++i) { + if ((*arrangement)[i] % n == 0 || n % (*arrangement)[i] == 0) { + swap((*arrangement)[i], (*arrangement)[n - 1]); + count += countArrangementHelper(n - 1, arrangement); + swap((*arrangement)[i], (*arrangement)[n - 1]); + } + } + return count; + } +}; diff --git a/C++/best-meeting-point.cpp b/C++/best-meeting-point.cpp new file mode 100644 index 000000000..dc83344b0 --- /dev/null +++ b/C++/best-meeting-point.cpp @@ -0,0 +1,30 @@ +// Time: O(m * n) +// Space: O(m + n) + +class Solution { +public: + int minTotalDistance(vector>& grid) { + vector x, y; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + if (grid[i][j]) { + x.emplace_back(i); + y.emplace_back(j); + } + } + } + nth_element(x.begin(), x.begin() + x.size() / 2, x.end()); + nth_element(y.begin(), y.begin() + y.size() / 2, y.end()); + const int mid_x = x[x.size() / 2]; + const int mid_y = y[y.size() / 2]; + int sum = 0; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + if (grid[i][j]) { + sum += abs(mid_x - i) + abs(mid_y - j); + } + } + } + return sum; + } +}; diff --git a/C++/best-time-to-buy-and-sell-stock-with-cooldown.cpp b/C++/best-time-to-buy-and-sell-stock-with-cooldown.cpp new file mode 100644 index 000000000..b68cc89bb --- /dev/null +++ b/C++/best-time-to-buy-and-sell-stock-with-cooldown.cpp @@ -0,0 +1,44 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maxProfit(vector& prices) { + if (prices.empty()) { + return 0; + } + vector buy(2), sell(2), coolDown(2); + buy[0] = -prices[0]; + for (int i = 1; i < prices.size(); ++i) { + // Bought before or buy today. + buy[i % 2] = max(buy[(i - 1) % 2], coolDown[(i - 1) % 2] - prices[i]); + // Sell today. + sell[i % 2] = buy[(i - 1) % 2] + prices[i]; + // Sold before yesterday or sold yesterday. + coolDown[i % 2] = max(coolDown[(i - 1) % 2], sell[(i - 1) % 2]); + } + return max(coolDown[(prices.size() - 1) % 2], sell[(prices.size() - 1) % 2]); + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + int maxProfit(vector& prices) { + if (prices.empty()) { + return 0; + } + vector buy(prices.size()), sell(prices.size()), coolDown(prices.size()); + buy[0] = -prices[0]; + for (int i = 1; i < prices.size(); ++i) { + // Bought before or buy today. + buy[i] = max(buy[i - 1], coolDown[i - 1] - prices[i]); + // Sell today. + sell[i] = buy[i - 1] + prices[i]; + // Sold before yesterday or sold yesterday. + coolDown[i] = max(coolDown[i - 1], sell[i - 1]); + } + return max(coolDown[prices.size() - 1], sell[prices.size() - 1]); + } +}; diff --git a/C++/best-time-to-buy-and-sell-stock-with-transaction-fee.cpp b/C++/best-time-to-buy-and-sell-stock-with-transaction-fee.cpp new file mode 100644 index 000000000..a4e840a92 --- /dev/null +++ b/C++/best-time-to-buy-and-sell-stock-with-transaction-fee.cpp @@ -0,0 +1,14 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maxProfit(vector& prices, int fee) { + int cash = 0, hold = -prices[0]; + for (int i = 1; i < prices.size(); ++i) { + cash = max(cash, hold + prices[i] - fee); + hold = max(hold, cash - prices[i]); + } + return cash; + } +}; diff --git a/C++/best-time-to-buy-and-sell-stock.cpp b/C++/best-time-to-buy-and-sell-stock.cpp new file mode 100644 index 000000000..9105909a9 --- /dev/null +++ b/C++/best-time-to-buy-and-sell-stock.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maxProfit(vector &prices) { + if (prices.empty()) { + return 0; + } + + int hold1 = numeric_limits::min(); + int release1 = numeric_limits::min(); + + for (const auto& p : prices) { + hold1 = max(hold1, -p); + release1 = max(release1, hold1 + p); + } + + return release1; + } +}; diff --git a/C++/binary-number-with-alternating-bits.cpp b/C++/binary-number-with-alternating-bits.cpp new file mode 100644 index 000000000..35309ddfd --- /dev/null +++ b/C++/binary-number-with-alternating-bits.cpp @@ -0,0 +1,18 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + bool hasAlternatingBits(int n) { + auto curr = n % 2; + n /= 2; + while (n > 0) { + if (curr == n % 2) { + return false; + } + curr = n % 2; + n /= 2; + } + return true; + } +}; diff --git a/C++/binary-search-tree-iterator.cpp b/C++/binary-search-tree-iterator.cpp new file mode 100644 index 000000000..0bcf46624 --- /dev/null +++ b/C++/binary-search-tree-iterator.cpp @@ -0,0 +1,49 @@ +// Time: O(1), amortized +// Space: O(h) + +/** + * Definition for binary tree + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class BSTIterator { +public: + BSTIterator(TreeNode *root) : cur_(root) { + } + + /** @return whether we have a next smallest number */ + bool hasNext() { + return !s_.empty() || cur_ != nullptr; + } + + /** @return the next smallest number */ + int next() { + // Go to the left most descendant. + while (cur_ != nullptr) { + s_.emplace(cur_); + cur_ = cur_->left; + } + cur_ = s_.top(); // Left most node. + s_.pop(); + + const auto *node = cur_; + cur_ = cur_->right; // Visit right child. + + return node->val; + } + +private: + stack s_; + TreeNode *cur_; +}; + +/** + * Your BSTIterator will be called like this: + * BSTIterator i = BSTIterator(root); + * while (i.hasNext()) cout << i.next(); + */ + diff --git a/C++/binary-tree-inorder-traversal.cpp b/C++/binary-tree-inorder-traversal.cpp new file mode 100644 index 000000000..28c341587 --- /dev/null +++ b/C++/binary-tree-inorder-traversal.cpp @@ -0,0 +1,66 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector inorderTraversal(TreeNode* root) { + vector res; + TreeNode *curr = root; + while (curr) { + if (!curr->left) { + res.emplace_back(curr->val); + curr = curr->right; + } else { + TreeNode *node = curr->left; + while (node->right && node->right != curr) { + node = node->right; + } + if (!node->right) { + node->right = curr; + curr = curr->left; + } else { + res.emplace_back(curr->val); + node->right = nullptr; + curr = curr->right; + } + } + } + return res; + } +}; + +// Time: O(n) +// Space: O(h) +class Solution2 { +public: + vector inorderTraversal(TreeNode* root) { + vector res; + stack> s; + s.emplace(root, false); + while (!s.empty()) { + bool visited; + tie(root, visited) = s.top(); + s.pop(); + if (root == nullptr) { + continue; + } + if (visited) { + res.emplace_back(root->val); + } else { + s.emplace(root->right, false); + s.emplace(root, true); + s.emplace(root->left, false); + } + } + return res; + } +}; diff --git a/C++/binary-tree-level-order-traversal.cpp b/C++/binary-tree-level-order-traversal.cpp new file mode 100644 index 000000000..96e751a8c --- /dev/null +++ b/C++/binary-tree-level-order-traversal.cpp @@ -0,0 +1,42 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector> levelOrder(TreeNode* root) { + vector> result; + queue que; + + if (root != nullptr) { + que.emplace(root); + } + + while (!que.empty()) { + vector level; + int size = que.size(); + for (int i = 0; i < size; i++) { + auto *front = que.front(); + que.pop(); + level.emplace_back(front->val); + if (front->left != nullptr) { + que.emplace(front->left); + } + if (front->right != nullptr) { + que.emplace(front->right); + } + } + result.emplace_back(move(level)); + } + + return result; + } +}; diff --git a/C++/binary-tree-longest-consecutive-sequence-ii.cpp b/C++/binary-tree-longest-consecutive-sequence-ii.cpp new file mode 100644 index 000000000..a1b18a229 --- /dev/null +++ b/C++/binary-tree-longest-consecutive-sequence-ii.cpp @@ -0,0 +1,46 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int longestConsecutive(TreeNode* root) { + int max_len = 0; + longestConsecutiveHelper(root, &max_len); + return max_len; + } + + pair longestConsecutiveHelper(TreeNode *root, int *max_len) { + if (!root) { + return {0, 0}; + } + const pair left_len = longestConsecutiveHelper(root->left, max_len); + const pair right_len = longestConsecutiveHelper(root->right, max_len); + + int cur_inc_len = 1, cur_dec_len = 1; + if (root->left) { + if (root->left->val == root->val + 1) { + cur_inc_len = max(cur_inc_len, left_len.first + 1); + } else if (root->left->val == root->val - 1){ + cur_dec_len = max(cur_dec_len, left_len.second + 1); + } + } + if (root->right) { + if (root->right->val == root->val + 1) { + cur_inc_len = max(cur_inc_len, right_len.first + 1); + } else if (root->right->val == root->val - 1) { + cur_dec_len = max(cur_dec_len, right_len.second + 1); + } + } + *max_len = max(*max_len, cur_dec_len + cur_inc_len - 1); + return {cur_inc_len, cur_dec_len}; + } +}; diff --git a/C++/binary-tree-longest-consecutive-sequence.cpp b/C++/binary-tree-longest-consecutive-sequence.cpp new file mode 100644 index 000000000..75fc8356c --- /dev/null +++ b/C++/binary-tree-longest-consecutive-sequence.cpp @@ -0,0 +1,39 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int longestConsecutive(TreeNode* root) { + int max_len = 0; + longestConsecutiveHelper(root, &max_len); + return max_len; + } + + int longestConsecutiveHelper(TreeNode *root, int *max_len) { + if (!root) { + return 0; + } + + const int left_len = longestConsecutiveHelper(root->left, max_len); + const int right_len = longestConsecutiveHelper(root->right, max_len); + + int cur_len = 1; + if (root->left && root->left->val == root->val + 1) { + cur_len = max(cur_len, left_len + 1); + } + if (root->right && root->right->val == root->val + 1) { + cur_len = max(cur_len, right_len + 1); + } + *max_len = max(*max_len, max(cur_len, max(left_len, right_len))); + return cur_len; + } +}; diff --git a/C++/binary-tree-paths.cpp b/C++/binary-tree-paths.cpp new file mode 100644 index 000000000..44dd1a57f --- /dev/null +++ b/C++/binary-tree-paths.cpp @@ -0,0 +1,47 @@ +// Time: O(n * h) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector binaryTreePaths(TreeNode* root) { + vector result; + vector path; + binaryTreePathsRecu(root, &path, &result); + return result; + } + + void binaryTreePathsRecu(TreeNode *node, vector *path, vector *result) { + if (!node) { + return; + } + + if (!node->left && !node->right) { + string ans = ""; + for (const auto& n : *path) { + ans.append(to_string(n->val).append("->")); + } + result->emplace_back(move(ans.append(to_string(node->val)))); + } + + if (node->left) { + path->emplace_back(node); + binaryTreePathsRecu(node->left, path, result); + path->pop_back(); + } + + if (node->right) { + path->emplace_back(node); + binaryTreePathsRecu(node->right, path, result); + path->pop_back(); + } + } +}; diff --git a/C++/binary-tree-postorder-traversal.cpp b/C++/binary-tree-postorder-traversal.cpp new file mode 100644 index 000000000..c3e127e7b --- /dev/null +++ b/C++/binary-tree-postorder-traversal.cpp @@ -0,0 +1,81 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector postorderTraversal(TreeNode* root) { + vector res; + TreeNode dummy(INT_MIN); + dummy.left = root; + auto *cur = &dummy; + while (cur) { + if (!cur->left) { + cur = cur->right; + } else { + auto *node = cur->left; + while (node->right && node->right != cur) { + node = node->right; + } + if (!node->right) { + node->right = cur; + cur = cur->left; + } else { + const auto& v = trace_back(cur->left, node); + res.insert(res.end(), v.cbegin(), v.cend()); + node->right = nullptr; + cur = cur->right; + } + } + } + return res; + } + +private: + vector trace_back(const TreeNode *from, const TreeNode *to) { + vector res; + auto *cur = from; + while (cur != to) { + res.emplace_back(cur->val); + cur = cur->right; + } + res.emplace_back(to->val); + reverse(res.begin(), res.end()); + return res; + } +}; + +// Time: O(n) +// Space: O(h) +class Solution2 { +public: + vector postorderTraversal(TreeNode* root) { + vector res; + stack> s; + s.emplace(root, false); + while (!s.empty()) { + bool visited; + tie(root, visited) = s.top(); + s.pop(); + if (root == nullptr) { + continue; + } + if (visited) { + res.emplace_back(root->val); + } else { + s.emplace(root, true); + s.emplace(root->right, false); + s.emplace(root->left, false); + } + } + return res; + } +}; diff --git a/C++/binary-tree-preorder-traversal.cpp b/C++/binary-tree-preorder-traversal.cpp new file mode 100644 index 000000000..007fbab11 --- /dev/null +++ b/C++/binary-tree-preorder-traversal.cpp @@ -0,0 +1,66 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector preorderTraversal(TreeNode* root) { + vector res; + auto *curr = root; + while (curr) { + if (!curr->left) { + res.emplace_back(curr->val); + curr = curr->right; + } else { + auto *node = curr->left; + while (node->right && node->right != curr) { + node = node->right; + } + if (!node->right) { + res.emplace_back(curr->val); + node->right = curr; + curr = curr->left; + } else { + node->right = nullptr; + curr = curr->right; + } + } + } + return res; + } +}; + +// Time: O(n) +// Space: O(h) +class Solution2 { +public: + vector preorderTraversal(TreeNode* root) { + vector res; + stack> s; + s.emplace(root, false); + while (!s.empty()) { + bool visited; + tie(root, visited) = s.top(); + s.pop(); + if (root == nullptr) { + continue; + } + if (visited) { + res.emplace_back(root->val); + } else { + s.emplace(root->right, false); + s.emplace(root->left, false); + s.emplace(root, true); + } + } + return res; + } +}; diff --git a/C++/binary-tree-tilt.cpp b/C++/binary-tree-tilt.cpp new file mode 100644 index 000000000..9511fcb34 --- /dev/null +++ b/C++/binary-tree-tilt.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int findTilt(TreeNode* root) { + int tilt = 0; + postOrderTraverse(root, &tilt); + return tilt; + } +private: + int postOrderTraverse(TreeNode* root, int *tilt) { + if (!root) { + return 0; + } + auto left = postOrderTraverse(root->left, tilt); + auto right = postOrderTraverse(root->right, tilt); + *tilt += abs(left - right); + return left + right + root->val; + } +}; diff --git a/C++/binary-tree-vertical-order-traversal.cpp b/C++/binary-tree-vertical-order-traversal.cpp new file mode 100644 index 000000000..2d7036587 --- /dev/null +++ b/C++/binary-tree-vertical-order-traversal.cpp @@ -0,0 +1,40 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector> verticalOrder(TreeNode* root) { + unordered_map> cols; + vector> queue{{root, 0}}; + for (int i = 0; i < queue.size(); ++i) { + TreeNode *node; + int j; + tie(node, j) = queue[i]; + if (node) { + cols[j].emplace_back(node->val); + queue.push_back({node->left, j - 1}); + queue.push_back({node->right, j + 1}); + } + } + int min_idx = numeric_limits::max(), + max_idx = numeric_limits::min(); + for (const auto& kvp : cols) { + min_idx = min(min_idx, kvp.first); + max_idx = max(max_idx, kvp.first); + } + vector> res; + for (int i = min_idx; !cols.empty() && i <= max_idx; ++i) { + res.emplace_back(move(cols[i])); + } + return res; + } +}; diff --git a/C++/binary-watch.cpp b/C++/binary-watch.cpp new file mode 100644 index 000000000..f033592ae --- /dev/null +++ b/C++/binary-watch.cpp @@ -0,0 +1,28 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + vector readBinaryWatch(int num) { + vector result; + for (int h = 0; h < 12; ++h) { + for (int m = 0; m < 60; ++m) { + if (bit_count(h) + bit_count(m) == num) { + const auto hour = to_string(h); + const auto minute = m < 10 ? "0" + to_string(m) : to_string(m); + result.emplace_back(hour + ":" + minute); + } + } + } + return result; + } + +private: + int bit_count(int bits) { + int count = 0; + for (; bits; bits &= bits - 1) { + ++count; + } + return count; + } +}; diff --git a/C++/bitwise-and-of-numbers-range.cpp b/C++/bitwise-and-of-numbers-range.cpp new file mode 100644 index 000000000..a05ce4491 --- /dev/null +++ b/C++/bitwise-and-of-numbers-range.cpp @@ -0,0 +1,12 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int rangeBitwiseAnd(int m, int n) { + while (m < n) { // Remove the last bit 1 until n <= m. + n &= n - 1; + } + return n; + } +}; diff --git a/C++/bomb-enemy.cpp b/C++/bomb-enemy.cpp new file mode 100644 index 000000000..d3b58e527 --- /dev/null +++ b/C++/bomb-enemy.cpp @@ -0,0 +1,50 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + int maxKilledEnemies(vector>& grid) { + int result = 0; + if (grid.empty() || grid[0].empty()) { + return result; + } + + vector> down{grid.size(), vector(grid[0].size())}; + vector> right{grid.size(), vector(grid[0].size())}; + for (int i = grid.size() - 1; i >= 0; --i) { + for (int j = grid[0].size() - 1; j >= 0; --j) { + if (grid[i][j] != 'W') { + if (i + 1 < grid.size()) { + down[i][j] = down[i + 1][j]; + } + if (j + 1 < grid[0].size()) { + right[i][j] = right[i][j + 1]; + } + if (grid[i][j] == 'E') { + ++down[i][j]; + ++right[i][j]; + } + } + } + } + + int left = 0; + vector up(grid[0].size()); + for (int i = 0; i < grid.size(); ++i) { + left = 0; + for (int j = 0; j < grid[0].size(); ++j) { + if (grid[i][j] == 'W') { + up[j] = 0; + left = 0; + } else if (grid[i][j] == 'E') { + ++up[j]; + ++left; + } else { + result = max(result, left + up[j] + right[i][j] + down[i][j]); + } + } + } + + return result; + } +}; diff --git a/C++/boundary-of-binary-tree.cpp b/C++/boundary-of-binary-tree.cpp new file mode 100644 index 000000000..a372556b4 --- /dev/null +++ b/C++/boundary-of-binary-tree.cpp @@ -0,0 +1,65 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector boundaryOfBinaryTree(TreeNode* root) { + if (!root) { + return {}; + } + + vector nodes; + nodes.emplace_back(root->val); + leftBoundary(root->left, &nodes); + leaves(root->left, &nodes); + leaves(root->right, &nodes); + rightBoundary(root->right, &nodes); + return nodes; + } + +private: + void leftBoundary(TreeNode *root, vector *nodes) { + if (!root || (!root->left && !root->right)) { + return; + } + nodes->emplace_back(root->val); + if (!root->left) { + leftBoundary(root->right, nodes); + } else { + leftBoundary(root->left, nodes); + } + } + + void rightBoundary(TreeNode *root, vector *nodes) { + if (!root || (!root->right && !root->left)) { + return; + } + if (!root->right) { + rightBoundary(root->left, nodes); + } else { + rightBoundary(root->right, nodes); + } + nodes->emplace_back(root->val); + } + + void leaves(TreeNode *root, vector *nodes) { + if (!root) { + return; + } + if (!root->left && !root->right) { + nodes->emplace_back(root->val); + return; + } + leaves(root->left, nodes); + leaves(root->right, nodes); + } +}; diff --git a/C++/brick-wall.cpp b/C++/brick-wall.cpp new file mode 100644 index 000000000..55a8d5e83 --- /dev/null +++ b/C++/brick-wall.cpp @@ -0,0 +1,16 @@ +// Time: O(n), n is the total number of the bricks +// Space: O(m), m is the total number different widths + +class Solution { +public: + int leastBricks(vector>& wall) { + unordered_map widths; + auto result = wall.size(); + for (const auto& row : wall) { + for (auto i = 0, width = 0; i < row.size() - 1; ++i) { + result = min(result, wall.size() - (++widths[width += row[i]])); + } + } + return result; + } +}; diff --git a/C++/buildTreeWithPostOrder.cpp b/C++/buildTreeWithPostOrder.cpp deleted file mode 100644 index 7510393a9..000000000 --- a/C++/buildTreeWithPostOrder.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(logn) - -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { - public: - TreeNode *buildTree(vector &inorder, vector &postorder) { - return buildTree(begin(inorder), end(inorder), begin(postorder), end(postorder)); - } - private: - template - TreeNode *buildTree(InputIterator in_first, InputIterator in_last, InputIterator post_first, InputIterator post_last) { - if(in_first == in_last) - return NULL; - if(post_first == post_last) - return NULL; - - auto root = new TreeNode(*prev(post_last)); - auto inRootPos = find(in_first, in_last, *prev(post_last)); - auto leftSize = distance(in_first, inRootPos); - root->left = buildTree(in_first, inRootPos, post_first, next(post_first, leftSize)); - root->right = buildTree(next(inRootPos), in_last, next(post_first, leftSize), prev(post_last)); - - return root; - } - -}; diff --git a/C++/buildTreeWithPreOrder.cpp b/C++/buildTreeWithPreOrder.cpp deleted file mode 100644 index e5c1b0dde..000000000 --- a/C++/buildTreeWithPreOrder.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(logn) - -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { - public: - TreeNode* buildTree(vector& preorder, vector& inorder) { - return buildTree(begin(preorder), end(preorder), begin(inorder), end(inorder)); - } - - private: - template - TreeNode* buildTree(InputIterator pre_first, InputIterator pre_last, InputIterator in_first, InputIterator in_last) { - if(pre_first == pre_last) - return NULL; - if(in_first == in_last) - return NULL; - - auto root = new TreeNode(*pre_first); - auto inRootPos = find(in_first, in_last, *pre_first); - auto leftSize = distance(in_first, inRootPos); - root->left = buildTree(next(pre_first), next(pre_first, leftSize + 1), in_first, inRootPos); - root->right = buildTree(next(pre_first, leftSize + 1), pre_last, next(inRootPos), in_last); - - return root; - } -}; diff --git a/C++/bulb-switcher-ii.cpp b/C++/bulb-switcher-ii.cpp new file mode 100644 index 000000000..fca08182a --- /dev/null +++ b/C++/bulb-switcher-ii.cpp @@ -0,0 +1,14 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int flipLights(int n, int m) { + if (m == 0) return 1; + if (n == 1) return 2; + if (m == 1 && n == 2) return 3; + if (m == 1 || n == 2) return 4; + if (m == 2) return 7; + return 8; + } +}; diff --git a/C++/bulb-switcher.cpp b/C++/bulb-switcher.cpp new file mode 100644 index 000000000..f640a2f85 --- /dev/null +++ b/C++/bulb-switcher.cpp @@ -0,0 +1,10 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int bulbSwitch(int n) { + // The number of full squares. + return static_cast(sqrt(n)); + } +}; diff --git a/C++/bulls-and-cows.cpp b/C++/bulls-and-cows.cpp new file mode 100644 index 000000000..373ec2c6d --- /dev/null +++ b/C++/bulls-and-cows.cpp @@ -0,0 +1,48 @@ +// Time: O(n) +// Space: O(10) = O(1) + +// One pass solution. +class Solution { +public: + string getHint(string secret, string guess) { + unordered_map s_lookup, g_lookup; + int A = 0, B = 0; + const int n = min(secret.length(), guess.length()); + for (int i = 0; i < n; ++i) { + const char s = secret[i]; + const char g = guess[i]; + if (s == g) { + ++A; + } else { + (s_lookup[g] > 0) ? --s_lookup[g], ++B : ++g_lookup[g]; + (g_lookup[s] > 0) ? --g_lookup[s], ++B : ++s_lookup[s]; + } + } + return to_string(A).append("A").append(to_string(B)).append("B"); + } +}; + +// Two pass solution. +class Solution2 { +public: + string getHint(string secret, string guess) { + unordered_map lookup; + int A = 0, B = 0; + for (const auto& s : secret) { + ++lookup[s]; + } + for (const auto& g : guess) { + if (lookup[g]) { + --lookup[g]; + ++B; + } + } + const int n = min(secret.length(), guess.length()); + for (int i = 0; i < n; ++i) { + if (secret[i] == guess[i]) { + ++A, --B; + } + } + return to_string(A).append("A").append(to_string(B)).append("B"); + } +}; diff --git a/C++/burst-balloons.cpp b/C++/burst-balloons.cpp new file mode 100644 index 000000000..91f5e5dde --- /dev/null +++ b/C++/burst-balloons.cpp @@ -0,0 +1,29 @@ +// Time: O(n^3) +// Space: O(n^2) + +class Solution { +public: + int maxCoins(vector& nums) { + vector coins; + coins.emplace_back(1); + for (const auto& n : nums) { + if (n > 0) { + coins.emplace_back(n); + } + } + coins.emplace_back(1); + + vector> max_coins(coins.size(), vector(coins.size())); + for (int k = 2; k < coins.size(); ++k) { + for (int left = 0; left < coins.size() - k; ++left) { + for (int i = left + 1, right = left + k; i < right; ++i) { + max_coins[left][right] = max(max_coins[left][right], + coins[left] * coins[i] * coins[right] + + max_coins[left][i] + max_coins[i][right]); + } + } + } + + return max_coins[0][coins.size() - 1]; + } +}; diff --git a/C++/can-i-win.cpp b/C++/can-i-win.cpp new file mode 100644 index 000000000..4906b6232 --- /dev/null +++ b/C++/can-i-win.cpp @@ -0,0 +1,35 @@ +// Time: O(n!) +// Space: O(n) + +class Solution { +public: + bool canIWin(int maxChoosableInteger, int desiredTotal) { + if ((1 + maxChoosableInteger) * (maxChoosableInteger / 2) < desiredTotal) { + return false; + } + unordered_map lookup; + return canIWinHelper(maxChoosableInteger, desiredTotal, 0, &lookup); + } + +private: + int canIWinHelper(int maxChoosableInteger, int desiredTotal, + int visited, unordered_map *lookup) { + + if (lookup->find(visited) != lookup->end()) { + return (*lookup)[visited]; + } + int mask = 1; + for (int i = 0; i < maxChoosableInteger; ++i) { + if (!(visited & mask)) { + if (i + 1 >= desiredTotal || + !canIWinHelper(maxChoosableInteger, desiredTotal - (i + 1), visited | mask, lookup)) { + (*lookup)[visited] = true; + return true; + } + } + mask <<= 1; + } + (*lookup)[visited] = false; + return false; + } +}; diff --git a/C++/can-place-flowers.cpp b/C++/can-place-flowers.cpp new file mode 100644 index 000000000..76c0dbc48 --- /dev/null +++ b/C++/can-place-flowers.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool canPlaceFlowers(vector& flowerbed, int n) { + for (int i = 0; i < flowerbed.size(); ++i) { + if (flowerbed[i] == 0 && (i == 0 || flowerbed[i - 1] == 0) && + (i == flowerbed.size() - 1 || flowerbed[i + 1] == 0)) { + flowerbed[i] = 1; + --n; + } + if (n <= 0) { + return true; + } + } + return false; + } +}; + diff --git a/C++/candy-crush.cpp b/C++/candy-crush.cpp new file mode 100644 index 000000000..702541a4b --- /dev/null +++ b/C++/candy-crush.cpp @@ -0,0 +1,48 @@ +// Time: O((R * C)^2) +// Space: O(1) + +class Solution { +public: + vector> candyCrush(vector>& board) { + const auto R = board.size(), C = board[0].size(); + bool changed = true; + + while (changed) { + changed = false; + + for (int r = 0; r < R; ++r) { + for (int c = 0; c + 2 < C; ++c) { + auto v = abs(board[r][c]); + if (v != 0 && v == abs(board[r][c + 1]) && v == abs(board[r][c + 2])) { + board[r][c] = board[r][c + 1] = board[r][c + 2] = -v; + changed = true; + } + } + } + + for (int r = 0; r + 2 < R; ++r) { + for (int c = 0; c < C; ++c) { + auto v = abs(board[r][c]); + if (v != 0 && v == abs(board[r + 1][c]) && v == abs(board[r + 2][c])) { + board[r][c] = board[r + 1][c] = board[r + 2][c] = -v; + changed = true; + } + } + } + + for (int c = 0; c < C; ++c) { + int empty_r = R - 1; + for (int r = R - 1; r >= 0; --r) { + if (board[r][c] > 0) { + board[empty_r--][c] = board[r][c]; + } + } + for (int r = empty_r; r >= 0; --r) { + board[r][c] = 0; + } + } + } + + return board; + } +}; diff --git a/C++/candy.cpp b/C++/candy.cpp index e1f297fc1..fb0cc4180 100644 --- a/C++/candy.cpp +++ b/C++/candy.cpp @@ -1,28 +1,20 @@ -// Time Complexity: O(n) -// Space Complexity: O(n) +// Time: O(n) +// Space: O(n) class Solution { - public: - int candy(vector &ratings) { - const int n = ratings.size(); - vector increment(n, 0); - - // left to right - for(int i = 1, inc = 0; i < n; ++i) { - if(ratings[i] > ratings[i - 1]) - increment[i] = max(++inc, increment[i]); - else - inc = 0; +public: + int candy(vector& ratings) { + vector candies(ratings.size(), 1); + for (int i = 1; i < ratings.size(); ++i) { + if (ratings[i] > ratings[i - 1]) { + candies[i] = candies[i - 1] + 1; } - - // right to left - for(int i = n - 2, inc = 0; i >= 0; --i) { - if(ratings[i] > ratings[i + 1]) - increment[i] = max(++inc, increment[i]); - else - inc = 0; + } + for (int i = ratings.size() - 2; i >= 0; --i) { + if (ratings[i] > ratings[i + 1] && candies[i] <= candies[i + 1]) { + candies[i] = candies[i + 1] + 1; } - - return accumulate(increment.begin(), increment.end(), n); } + return accumulate(candies.cbegin(), candies.cend(), 0); + } }; diff --git a/C++/cherry-pickup.cpp b/C++/cherry-pickup.cpp new file mode 100644 index 000000000..5c44956c3 --- /dev/null +++ b/C++/cherry-pickup.cpp @@ -0,0 +1,39 @@ +// Time: O(n^3) +// Space: O(n^2) + +class Solution { +public: + int cherryPickup(vector>& grid) { + // dp holds the max # of cherries two k-length paths can pickup. + // The two k-length paths arrive at (i, k - i) and (j, k - j), + // respectively. + const int n = grid.size(); + vector> dp(n, vector(n, -1)); + dp[0][0] = grid[0][0]; + + const int max_len = 2 * (n - 1); + for (int k = 1; k <= max_len; ++k) { + for (int i = min(k, n - 1); i >= max(0, k - n + 1); --i) { // 0 <= i < n, 0 <= k-i < n + for (int j = min(k , n - 1); j >= i; --j) { // i <= j < n, 0 <= k-j < n + if (grid[i][k - i] == -1 || + grid[j][k - j] == -1) { + dp[i][j] = -1; + continue; + } + int cnt = grid[i][k - i] + ((i == j) ? 0 : grid[j][k - j]); + int max_cnt = -1; + static const vector> directions{{0, 0}, {-1, 0}, {0, -1}, {-1, -1}}; + for (const auto& direction : directions) { + const auto ii = i + direction.first; + const auto jj = j + direction.second; + if (ii >= 0 && jj >= 0 && dp[ii][jj] >= 0) { + max_cnt = max(max_cnt, dp[ii][jj] + cnt); + } + } + dp[i][j] = max_cnt; + } + } + } + return max(dp[n - 1][n - 1], 0); + } +}; diff --git a/C++/circular-array-loop.cpp b/C++/circular-array-loop.cpp new file mode 100644 index 000000000..fe2d41662 --- /dev/null +++ b/C++/circular-array-loop.cpp @@ -0,0 +1,40 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool circularArrayLoop(vector& nums) { + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] == 0) { + continue; + } + int slow = i, fast = i; + while (nums[next(nums, slow)] * nums[i] > 0 && + nums[next(nums, fast)] * nums[i] > 0 && + nums[next(nums, next(nums, fast))] * nums[i] > 0) { + + slow = next(nums, slow); + fast = next(nums, next(nums, fast)); + if (slow == fast) { + if (slow == next(nums, slow)) { + break; + } + return true; + } + } + slow = i; + int val = nums[i]; + while (nums[slow] * val > 0) { + int tmp = next(nums, slow); + nums[slow] = 0; + slow = tmp; + } + } + return false; + } + +private: + int next(const vector& nums, int i) { + return ((i + nums[i]) + nums.size()) % nums.size(); + } +}; diff --git a/C++/closest-binary-search-tree-value-ii.cpp b/C++/closest-binary-search-tree-value-ii.cpp new file mode 100644 index 000000000..6b0da1019 --- /dev/null +++ b/C++/closest-binary-search-tree-value-ii.cpp @@ -0,0 +1,70 @@ +// Time: O(h + k) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector closestKValues(TreeNode* root, double target, int k) { + // The forward or backward iterator. + const auto backward = [](const vector& s) { return s.back()->left; }; + const auto forward = [](const vector& s) { return s.back()->right; }; + const auto closest = [&target](const TreeNode* a, const TreeNode* b) { + return abs(a->val - target) < abs(b->val - target); + }; + + // Build the stack to the closest node. + vector s; + while (root) { + s.emplace_back(root); + root = target < root->val ? root->left : root->right; + } + + // Get the stack to the next smaller node. + vector forward_stack(s.cbegin(), next(min_element(s.cbegin(), s.cend(), closest))); + vector backward_stack(forward_stack); + nextNode(backward_stack, backward, forward); + + // Get the closest k values by advancing the iterators of the stacks. + vector result; + for (int i = 0; i < k; ++i) { + if (!forward_stack.empty() && + (backward_stack.empty() || closest(forward_stack.back(), backward_stack.back()))) { + result.emplace_back(forward_stack.back()->val); + nextNode(forward_stack, forward, backward); + } else if (!backward_stack.empty() && + (forward_stack.empty() || !closest(forward_stack.back(), backward_stack.back()))) { + result.emplace_back(backward_stack.back()->val); + nextNode(backward_stack, backward, forward); + } + } + return result; + } + + // Helper to make a stack to the next node. + template + void nextNode(vector& s, const T& child1, const U& child2) { + if (!s.empty()) { + if (child2(s)) { + s.emplace_back(child2(s)); + while (child1(s)) { + s.emplace_back(child1(s)); + } + } else { + auto child = s.back(); + s.pop_back(); + while (!s.empty() && child == child2(s)) { + child = s.back(); + s.pop_back(); + } + } + } + } +}; diff --git a/C++/closest-binary-search-tree-value.cpp b/C++/closest-binary-search-tree-value.cpp new file mode 100644 index 000000000..0ab4ebb70 --- /dev/null +++ b/C++/closest-binary-search-tree-value.cpp @@ -0,0 +1,34 @@ +// Time: O(h) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int closestValue(TreeNode* root, double target) { + double gap = numeric_limits::max(); + int closest = numeric_limits::max(); + + while (root) { + if (abs(static_cast(root->val) - target) < gap) { + gap = abs(root->val - target); + closest = root->val; + } + if (target == root->val) { + break; + } else if (target < root->val) { + root = root->left; + } else { + root = root->right; + } + } + return closest; + } +}; diff --git a/C++/closest-leaf-in-a-binary-tree.cpp b/C++/closest-leaf-in-a-binary-tree.cpp new file mode 100644 index 000000000..8fecbb19c --- /dev/null +++ b/C++/closest-leaf-in-a-binary-tree.cpp @@ -0,0 +1,63 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int findClosestLeaf(TreeNode* root, int k) { + unordered_map> neighbors; + unordered_set leaves; + traverse(root, &neighbors, &leaves); + vector q{k}; + unordered_set lookup{k}; + while (!q.empty()) { + vector next_q; + for (const auto& u : q) { + if (leaves.count(u)) { + return u; + } + for (const auto& v : neighbors[u]) { + if (lookup.count(v)) { + continue; + } + lookup.emplace(v); + next_q.emplace_back(v); + } + } + swap(q, next_q); + } + return 0; + } + +private: + void traverse(TreeNode *node, + unordered_map> *neighbors, + unordered_set *leaves) { + + if (!node) { + return; + } + if (!node->left && !node->right) { + leaves->emplace(node->val); + return; + } + if (node->left) { + (*neighbors)[node->val].emplace_back(node->left->val); + (*neighbors)[node->left->val].emplace_back(node->val); + traverse(node->left, neighbors, leaves); + } + if (node->right) { + (*neighbors)[node->val].emplace_back(node->right->val); + (*neighbors)[node->right->val].emplace_back(node->val); + traverse(node->right, neighbors, leaves); + } + } +}; diff --git a/C++/coin-change-2.cpp b/C++/coin-change-2.cpp new file mode 100644 index 000000000..a35a5c633 --- /dev/null +++ b/C++/coin-change-2.cpp @@ -0,0 +1,16 @@ +// Time: O(n * m) +// Space: O(m) + +class Solution { +public: + int change(int amount, vector& coins) { + vector dp(amount + 1); + dp[0] = 1; + for (const auto& coin : coins) { + for (int i = coin; i <= amount; ++i) { + dp[i] += dp[i - coin]; + } + } + return dp[amount]; + } +}; diff --git a/C++/coin-change.cpp b/C++/coin-change.cpp new file mode 100644 index 000000000..ff87539f0 --- /dev/null +++ b/C++/coin-change.cpp @@ -0,0 +1,21 @@ +// Time: O(n * k), n is the number of coins, k is the amount of money +// Space: O(k) + +// DP solution. (164ms) +class Solution { +public: + int coinChange(vector& coins, int amount) { + vector amounts(amount + 1, numeric_limits::max()); + amounts[0] = 0; + for (int i = 0; i <= amount; ++i) { + if (amounts[i] != numeric_limits::max()) { + for (const auto& coin : coins) { + if (coin <= numeric_limits::max() - i && i + coin <= amount) { + amounts[i + coin] = min(amounts[i + coin], amounts[i] + 1); + } + } + } + } + return amounts[amount] == numeric_limits::max() ? -1 : amounts[amount]; + } +}; diff --git a/C++/coin-path.cpp b/C++/coin-path.cpp new file mode 100644 index 000000000..e0536c3e1 --- /dev/null +++ b/C++/coin-path.cpp @@ -0,0 +1,38 @@ +// Time: O(n * B) +// Space: O(n) + +class Solution { +public: + vector cheapestJump(vector& A, int B) { + vector result; + if (A.empty() || A.back() == -1) { + return result; + } + const int n = A.size(); + vector dp(n, numeric_limits::max()), next(n, -1); + dp[n - 1] = A[n - 1]; + for (int i = n - 2; i >= 0; --i) { + if (A[i] == -1) { + continue; + } + for (int j = i + 1; j <= min(i + B, n - 1); ++j) { + if (dp[j] == numeric_limits::max()) { + continue; + } + if (A[i] + dp[j] < dp[i]) { + dp[i] = A[i] + dp[j]; + next[i] = j; + } + } + } + if (dp[0] == numeric_limits::max()) { + return result; + } + int k = 0; + while (k != -1) { + result.emplace_back(k + 1); + k = next[k]; + } + return result; + } +}; diff --git a/C++/combination-sum-iii.cpp b/C++/combination-sum-iii.cpp new file mode 100644 index 000000000..b9009b338 --- /dev/null +++ b/C++/combination-sum-iii.cpp @@ -0,0 +1,27 @@ +// Time: O(k * C(n, k)) +// Space: O(k) + +class Solution { +public: + vector > combinationSum3(int k, int n) { + vector> res; + vector combination; + combinationSum3(res, combination, 1, k, n); + return res; + } +private: + void combinationSum3(vector > &res, vector &combination, int start, int k, int n) { + if (!k && !n) { + res.push_back(combination); + return; + } else if (k < 0) { + return; + } + + for (int i = start; i < 10 && n >= k * i + k * (k - 1) / 2; ++i) { + combination.push_back(i); + combinationSum3(res, combination, i + 1, k - 1, n - i); + combination.pop_back(); + } + } +}; diff --git a/C++/combination-sum-iv.cpp b/C++/combination-sum-iv.cpp new file mode 100644 index 000000000..e7cc8b806 --- /dev/null +++ b/C++/combination-sum-iv.cpp @@ -0,0 +1,19 @@ +// Time: O(nlogn + n * t), t is the value of target. +// Space: O(t) + +class Solution { +public: + int combinationSum4(vector& nums, int target) { + vector dp(target + 1, 0); + dp[0] = 1; + sort(nums.begin(), nums.end()); + + for (int i = 1; i <= target; ++i) { + for (int j = 0; j < nums.size() && nums[j] <= i; ++j) { + dp[i] += dp[i - nums[j]]; + } + } + + return dp[target]; + } +}; diff --git a/C++/compare-version-numbers.cpp b/C++/compare-version-numbers.cpp new file mode 100644 index 000000000..e15efbc72 --- /dev/null +++ b/C++/compare-version-numbers.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int compareVersion(string version1, string version2) { + const int n1 = version1.length(), n2 = version2.length(); + for (int i = 0, j = 0; i < n1 || j < n2; ++i, ++j) { + int v1 = 0, v2 = 0; + while (i < n1 && version1[i] != '.') { + v1 = v1 * 10 + version1[i++] - '0'; + } + while (j < n2 && version2[j] != '.') { + v2 = v2 * 10 + version2[j++] - '0'; + } + if (v1 != v2) { + return v1 > v2 ? 1 : -1; + } + } + return 0; + } +}; diff --git a/C++/complex-number-multiplication.cpp b/C++/complex-number-multiplication.cpp new file mode 100644 index 000000000..d3127e59b --- /dev/null +++ b/C++/complex-number-multiplication.cpp @@ -0,0 +1,18 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + string complexNumberMultiply(string a, string b) { + int ra, ia, rb, ib; + char op; + stringstream ssa(a), ssb(b); + ssa >> ra >> op >> ia; + ssb >> rb >> op >> ib; + string result = to_string(ra * rb - ia * ib); + result += "+"; + result += to_string(ra * ib + rb * ia); + result += "i"; + return result; + } +}; diff --git a/C++/concatenated-words.cpp b/C++/concatenated-words.cpp new file mode 100644 index 000000000..ecb47e897 --- /dev/null +++ b/C++/concatenated-words.cpp @@ -0,0 +1,29 @@ +// Time: O(n * l^2) +// Space: O(n * l) + +class Solution { +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set lookup(words.begin(), words.end()); + vector result; + for (const auto& word : words) { + vector dp(word.length() + 1); + dp[0] = true; + for (int i = 0; i < word.length(); ++i) { + if (!dp[i]) { + continue; + } + for (int j = i + 1; j <= word.length(); ++j) { + if (j - i < word.length() && lookup.count(word.substr(i, j - i))) { + dp[j] = true; + } + } + if (dp[word.length()]) { + result.emplace_back(word); + break; + } + } + } + return result; + } +}; diff --git a/C++/construct-binary-tree-from-inorder-and-postorder-traversal.cpp b/C++/construct-binary-tree-from-inorder-and-postorder-traversal.cpp new file mode 100644 index 000000000..399af20c8 --- /dev/null +++ b/C++/construct-binary-tree-from-inorder-and-postorder-traversal.cpp @@ -0,0 +1,43 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* buildTree(vector& inorder, vector& postorder) { + unordered_map in_entry_idx_map; + for (size_t i = 0; i < inorder.size(); ++i) { + in_entry_idx_map.emplace(inorder[i], i); + } + return ReconstructPostInOrdersHelper(postorder, 0, postorder.size(), inorder, 0, inorder.size(), + in_entry_idx_map); + } + + TreeNode * ReconstructPostInOrdersHelper(const vector& postorder, size_t post_s, size_t post_e, + const vector& inorder, size_t in_s, size_t in_e, + const unordered_map& in_entry_idx_map) { + if (post_s == post_e || in_s == in_e) { + return nullptr; + } + + auto idx = in_entry_idx_map.at(postorder[post_e - 1]); + auto left_tree_size = idx - in_s; + + TreeNode *node = new TreeNode(postorder[post_e - 1]); + // Recursively builds the left subtree. + node->left =ReconstructPostInOrdersHelper(postorder, post_s, post_s + left_tree_size, + inorder, in_s, idx, in_entry_idx_map); + // Recursively builds the right subtree. + node->right = ReconstructPostInOrdersHelper(postorder, post_s + left_tree_size, post_e - 1, + inorder, idx + 1, in_e, in_entry_idx_map); + return node; + } +}; diff --git a/C++/construct-binary-tree-from-preorder-and-inorder-traversal.cpp b/C++/construct-binary-tree-from-preorder-and-inorder-traversal.cpp new file mode 100644 index 000000000..f6281ebbb --- /dev/null +++ b/C++/construct-binary-tree-from-preorder-and-inorder-traversal.cpp @@ -0,0 +1,43 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* buildTree(vector& preorder, vector& inorder) { + unordered_map in_entry_idx_map; + for (size_t i = 0; i < inorder.size(); ++i) { + in_entry_idx_map.emplace(inorder[i], i); + } + return ReconstructPreInOrdersHelper(preorder, 0, preorder.size(), inorder, 0, inorder.size(), + in_entry_idx_map); + } + + // Reconstructs the binary tree from pre[pre_s : pre_e - 1] and + // in[in_s : in_e - 1]. + TreeNode *ReconstructPreInOrdersHelper(const vector& preorder, size_t pre_s, size_t pre_e, + const vector& inorder, size_t in_s, size_t in_e, + const unordered_map& in_entry_idx_map) { + if (pre_s == pre_e || in_s == in_e) { + return nullptr; + } + + auto idx = in_entry_idx_map.at(preorder[pre_s]); + auto left_tree_size = idx - in_s; + + auto node = new TreeNode(preorder[pre_s]); + node->left = ReconstructPreInOrdersHelper(preorder, pre_s + 1, pre_s + 1 + left_tree_size, + inorder, in_s, idx, in_entry_idx_map); + node->right = ReconstructPreInOrdersHelper(preorder, pre_s + 1 + left_tree_size, pre_e, + inorder, idx + 1, in_e, in_entry_idx_map); + return node; + } +}; diff --git a/C++/construct-binary-tree-from-string.cpp b/C++/construct-binary-tree-from-string.cpp new file mode 100644 index 000000000..0f2d1ce36 --- /dev/null +++ b/C++/construct-binary-tree-from-string.cpp @@ -0,0 +1,43 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* str2tree(string s) { + int i = 0; + return s.empty() ? nullptr : str2treeHelper(s, &i); + } + +private: + TreeNode* str2treeHelper(const string& s, int *i) { + auto start = *i; + if (s[*i] == '-') { + ++(*i); + } + while (*i < s.length() && isdigit(s[*i])) { + ++(*i); + } + + auto node = new TreeNode(stoi(s.substr(start, *i - start))); + if (*i < s.length() && s[*i] == '(') { + ++(*i); + node->left = str2treeHelper(s, i); + ++(*i); + } + if (*i < s.length() && s[*i] == '(') { + ++(*i); + node->right = str2treeHelper(s, i); + ++(*i); + } + return node; + } +}; diff --git a/C++/construct-string-from-binary-tree.cpp b/C++/construct-string-from-binary-tree.cpp new file mode 100644 index 000000000..36d5fe510 --- /dev/null +++ b/C++/construct-string-from-binary-tree.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + string tree2str(TreeNode* t) { + if (!t) { + return ""; + } + + auto s = to_string(t->val); + + if (t->left || t->right) { + s += "(" + tree2str(t->left) + ")"; + } + + if (t->right) { + s += "(" + tree2str(t->right) + ")"; + } + + return s; + } +}; diff --git a/C++/construct-the-rectangle.cpp b/C++/construct-the-rectangle.cpp new file mode 100644 index 000000000..0940be3de --- /dev/null +++ b/C++/construct-the-rectangle.cpp @@ -0,0 +1,13 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + vector constructRectangle(int area) { + int w = sqrt(area); + while (area % w) { + --w; + } + return {area / w, w}; + } +}; diff --git a/C++/contain-virus.cpp b/C++/contain-virus.cpp new file mode 100644 index 000000000..57d2bc5e5 --- /dev/null +++ b/C++/contain-virus.cpp @@ -0,0 +1,101 @@ +// Time: O((m * n)^(4/3)), days = O((m * n)^(1/3)) +// Space: O(m * n) + +class Solution { +public: + int containVirus(vector>& grid) { + int result = 0; + while (true) { + P_SET lookup; + vector regions, frontiers; + vector perimeters; + for (int r = 0; r < grid.size(); ++r) { + for (int c = 0; c < grid[r].size(); ++c) { + const auto& p = make_pair(r, c); + if (grid[r][c] == 1 && lookup.count(p) == 0) { + regions.emplace_back(); + frontiers.emplace_back(); + perimeters.emplace_back(); + dfs(grid, p, &lookup, ®ions, &frontiers, &perimeters); + } + } + } + if (regions.empty()) { + break; + } + + int triage_idx = 0; + for (int i = 0; i < frontiers.size(); ++i) { + if (frontiers[i].size() > frontiers[triage_idx].size()) { + triage_idx = i; + } + } + for (int i = 0; i < regions.size(); ++i) { + if (i == triage_idx) { + result += perimeters[i]; + for (const auto& p : regions[i]) { + grid[p.first][p.second] = -1; + } + continue; + } + for (const auto& p : regions[i]) { + for (const auto& d : directions) { + int nr = p.first + d.first; + int nc = p.second + d.second; + if (nr < 0 || nr >= grid.size() || + nc < 0 || nc >= grid[nr].size()) { + continue; + } + if (grid[nr][nc] == 0) { + grid[nr][nc] = 1; + } + } + } + } + } + + return result; + } + +private: + template + struct PairHash { + size_t operator()(const pair& p) const { + size_t seed = 0; + seed ^= std::hash{}(p.first) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= std::hash{}(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2); + return seed; + } + }; + using P = pair; + using P_SET = unordered_set>; + + void dfs(const vector>& grid, + const P& p, + P_SET *lookup, + vector *regions, + vector *frontiers, + vector *perimeters) { + + if (lookup->count(p)) { + return; + } + lookup->emplace(p); + regions->back().emplace(p); + for (const auto& d : directions) { + int nr = p.first + d.first; + int nc = p.second + d.second; + if (nr < 0 || nr >= grid.size() || + nc < 0 || nc >= grid[nr].size()) { + continue; + } + if (grid[nr][nc] == 1) { + dfs(grid, make_pair(nr, nc), lookup, regions, frontiers, perimeters); + } else if (grid[nr][nc] == 0) { + frontiers->back().emplace(nr, nc); + ++perimeters->back(); + } + } + } + const vector

directions = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; +}; diff --git a/C++/container-with-most-water.cpp b/C++/container-with-most-water.cpp new file mode 100644 index 000000000..acaa98efe --- /dev/null +++ b/C++/container-with-most-water.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maxArea(vector& height) { + int i = 0, j = height.size() - 1, max_area = 0; + while (i < j) { + max_area = max(max_area, min(height[i], height[j]) * (j - i)); + if (height[i] > height[j]) { + --j; + } else if (height[i] < height[j]) { + ++i; + } else { // height[i] == height[j]. + ++i, --j; + } + } + return max_area; + } +}; diff --git a/C++/contains-duplicate-ii.cpp b/C++/contains-duplicate-ii.cpp new file mode 100644 index 000000000..b70ad1928 --- /dev/null +++ b/C++/contains-duplicate-ii.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + bool containsNearbyDuplicate(vector& nums, int k) { + unordered_map lookup; + for (int i = 0; i < nums.size(); ++i) { + if (lookup.find(nums[i]) == lookup.end()) { + lookup[nums[i]] = i; + } else { + // It the value occurs before, check the difference. + if (i - lookup[nums[i]] <= k) { + return true; + } + // Update the index of the value. + lookup[nums[i]] = i; + } + } + return false; + } +}; diff --git a/C++/contains-duplicate-iii.cpp b/C++/contains-duplicate-iii.cpp new file mode 100644 index 000000000..a8e790d61 --- /dev/null +++ b/C++/contains-duplicate-iii.cpp @@ -0,0 +1,32 @@ +// Time: O(nlogk) +// Space: O(k) + +class Solution { +public: + bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) { + if (k < 0 || t < 0) { + return false; + } + + queue window; + multiset bst; + for (int i = 0; i < nums.size(); ++i) { + // Only keep at most k elements. + if (bst.size() > k) { + int num = window.front(); + window.pop(); + bst.erase(bst.find(num)); + } + // Every search costs time: O(logk). + const auto it = bst.lower_bound(nums[i] - t); + if (it == bst.cend() || (*it - nums[i]) > t) { + // Not found. + window.emplace(nums[i]); + bst.emplace(nums[i]); + } else { + return true; + } + } + return false; + } +}; diff --git a/C++/contains-duplicate.cpp b/C++/contains-duplicate.cpp new file mode 100644 index 000000000..524f4067c --- /dev/null +++ b/C++/contains-duplicate.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + bool containsDuplicate(vector& nums) { + unordered_set nums_set(nums.begin(), nums.end()); + return nums_set.size() != nums.size(); + } +}; + +// Time: O(nlogn) +// Space: O(1) +class Solution2 { +public: + bool containsDuplicate(vector& nums) { + sort(nums.begin(), nums.end()); + return unique(nums.begin(), nums.end()) != nums.end(); + } +}; diff --git a/C++/contiguous-array.cpp b/C++/contiguous-array.cpp new file mode 100644 index 000000000..cd067f052 --- /dev/null +++ b/C++/contiguous-array.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int findMaxLength(vector& nums) { + int result = 0, count = 0; + unordered_map lookup; + lookup[0] = -1; + for (int i = 0; i < nums.size(); ++i) { + count += nums[i] == 1 ? 1 : -1; + if (lookup.count(count)) { + result = max(result, i - lookup[count]); + } else { + lookup[count] = i; + } + } + return result; + } +}; diff --git a/C++/continuous-subarray-sum.cpp b/C++/continuous-subarray-sum.cpp new file mode 100644 index 000000000..9b0155131 --- /dev/null +++ b/C++/continuous-subarray-sum.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(k) + +class Solution { +public: + bool checkSubarraySum(vector& nums, int k) { + int count = 0; + unordered_map lookup; + lookup[0] = -1; + for (int i = 0; i < nums.size(); ++i) { + count += nums[i]; + if (k != 0) { + count %= k; + } + if (lookup.count(count)) { + if (i - lookup[count] > 1) { + return true; + } + } else { + lookup[count] = i; + } + } + return false; + } +}; diff --git a/C++/convert-a-number-to-hexadecimal.cpp b/C++/convert-a-number-to-hexadecimal.cpp new file mode 100644 index 000000000..8808b9328 --- /dev/null +++ b/C++/convert-a-number-to-hexadecimal.cpp @@ -0,0 +1,25 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + string toHex(int num) { + if (!num) { + return "0"; + } + + string result; + while (num && result.length() != sizeof(int) * 2) { + int hex = num & 15; + if (hex < 10) { + result.push_back('0' + hex); + } else { + result.push_back('a' + hex - 10); + } + num >>= 4; + } + reverse(result.begin(), result.end()); + + return result; + } +}; diff --git a/C++/convert-bst-to-greater-tree.cpp b/C++/convert-bst-to-greater-tree.cpp new file mode 100644 index 000000000..c66042d2a --- /dev/null +++ b/C++/convert-bst-to-greater-tree.cpp @@ -0,0 +1,35 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* convertBST(TreeNode* root) { + int cur_sum = 0; + convertBSTHelper(root, &cur_sum); + return root; + } + +private: + void convertBSTHelper(TreeNode* root, int *cur_sum) { + if (!root) { + return; + } + + if (root->right) { + convertBSTHelper(root->right, cur_sum); + } + root->val = (*cur_sum += root->val); + if (root->left) { + convertBSTHelper(root->left, cur_sum); + } + } +}; diff --git a/C++/convert-sorted-array-to-binary-search-tree.cpp b/C++/convert-sorted-array-to-binary-search-tree.cpp new file mode 100644 index 000000000..35f3ad883 --- /dev/null +++ b/C++/convert-sorted-array-to-binary-search-tree.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(logn) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* sortedArrayToBST(vector& nums) { + return sortedArrayToBSTHelper(nums, 0, nums.size() - 1); + } + +private: + TreeNode *sortedArrayToBSTHelper(vector &nums, int start, int end) { + if (start <= end) { + TreeNode *node = new TreeNode(nums[start + (end - start) / 2]); + node->left = sortedArrayToBSTHelper(nums, start, start + (end - start) / 2 - 1); + node->right = sortedArrayToBSTHelper(nums, start + (end - start) / 2 + 1, end); + return node; + } + return nullptr; + } +}; diff --git a/C++/convert-sorted-list-to-binary-search-tree.cpp b/C++/convert-sorted-list-to-binary-search-tree.cpp new file mode 100644 index 000000000..d173c96c6 --- /dev/null +++ b/C++/convert-sorted-list-to-binary-search-tree.cpp @@ -0,0 +1,47 @@ +// Time: O(n) +// Space: O(logn) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* sortedListToBST(ListNode* head) { + auto curr = head; + int n = 0; + while (curr) { + curr = curr->next; + ++n; + } + return BuildBSTFromSortedDoublyListHelper(&head, 0, n); + } + + TreeNode * BuildBSTFromSortedDoublyListHelper(ListNode **head, int s, int e) { + if (s == e) { + return nullptr; + } + + int m = s + ((e - s) / 2); + auto left = BuildBSTFromSortedDoublyListHelper(head, s, m); + auto curr = new TreeNode((*head)->val); + + *head = (*head)->next; + curr->left = left; + curr->right = BuildBSTFromSortedDoublyListHelper(head, m + 1, e); + return curr; + } +}; diff --git a/C++/convex-polygon.cpp b/C++/convex-polygon.cpp new file mode 100644 index 000000000..3582c3fdb --- /dev/null +++ b/C++/convex-polygon.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isConvex(vector>& points) { + const auto det = [](const vector>& A) { + return A[0][0]*A[1][1] - A[0][1]*A[1][0]; + }; + long n = points.size(), prev = 0, curr; + for (int i = 0; i < n; ++i) { + vector> A; + for (int j = 1; j < 3; ++j) { + A.push_back({points[(i + j) % n][0] - points[i][0], points[(i + j) % n][1] - points[i][1]}); + } + if (curr = det(A)) { + if (curr * prev < 0) { + return false; + } + prev = curr; + } + } + return true; + } +}; diff --git a/C++/copy-list-with-random-pointer.cpp b/C++/copy-list-with-random-pointer.cpp new file mode 100644 index 000000000..e894b1c75 --- /dev/null +++ b/C++/copy-list-with-random-pointer.cpp @@ -0,0 +1,40 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list with a random pointer. + * struct RandomListNode { + * int label; + * RandomListNode *next, *random; + * RandomListNode(int x) : label(x), next(NULL), random(NULL) {} + * }; + */ +class Solution { +public: + RandomListNode *copyRandomList(RandomListNode *head) { + // Insert the copied node after the original one. + for (auto *curr = head; curr; curr = curr->next->next) { + auto *node = new RandomListNode(curr->label); + node->next = curr->next; + curr->next = node; + } + + // Update random node. + for (auto *curr = head; curr; curr = curr->next->next) { + if (curr->random) { + curr->next->random = curr->random->next; + } + } + + // Seperate the copied nodes from original ones. + RandomListNode dummy(0); + for (auto *curr = head, *copy_curr = &dummy; + curr; + copy_curr = copy_curr->next, curr = curr->next) { + copy_curr->next = curr->next; + curr->next = curr->next->next; + } + + return dummy.next; + } +}; diff --git a/C++/copyRandomList.cpp b/C++/copyRandomList.cpp deleted file mode 100644 index ae69f7482..000000000 --- a/C++/copyRandomList.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list with a random pointer. - * struct RandomListNode { - * int label; - * RandomListNode *next, *random; - * RandomListNode(int x) : label(x), next(NULL), random(NULL) {} - * }; - */ -class Solution { - public: - RandomListNode *copyRandomList(RandomListNode *head) { - // insert the copied node after the original one - for(RandomListNode *cur = head; cur; cur = cur->next->next) { - RandomListNode *node = new RandomListNode(cur->label); - node->next = cur->next; - cur->next = node; - } - - // update random node - for(RandomListNode *cur = head; cur; cur = cur->next->next) { - if(cur->random) { - cur->next->random = cur->random->next; - } - } - - // seperate the copied nodes from original ones - RandomListNode dummy(INT_MIN); - for( RandomListNode *cur = head, *copy_cur = &dummy; - cur; - copy_cur = copy_cur->next, cur = cur->next) { - copy_cur->next = cur->next; - cur->next = cur->next->next; - } - - return dummy.next; - } -}; diff --git a/C++/coundAndSay.cpp b/C++/coundAndSay.cpp deleted file mode 100644 index d1285589d..000000000 --- a/C++/coundAndSay.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(n) - -class Solution { - public: - string countAndSay(int n) { - string s{"1"}; - while(--n) { - s = getNext(s); - } - return s; - } - - private: - string getNext(const string &s) { - stringstream ss; - for(auto i = s.begin(); i != s.end();) { - auto j = find_if(i, s.end(), bind1st(not_equal_to(), *i)); - ss << distance(i, j) << *i; - i = j; - } - return ss.str(); - } -}; diff --git a/C++/count-and-say.cpp b/C++/count-and-say.cpp new file mode 100644 index 000000000..491b0f2d9 --- /dev/null +++ b/C++/count-and-say.cpp @@ -0,0 +1,25 @@ +// Time: O(n * 2^n) +// Space: O(2^n) + +class Solution { +public: + string countAndSay(int n) { + string seq{"1"}; + for (int i = 0; i < n - 1; ++i) { + seq = getNext(seq); + } + return seq; + } + +private: + string getNext(const string& seq) { + string next_seq; + for(auto i = seq.cbegin(); i != seq.cend();) { + auto j = find_if(i, seq.cend(), bind1st(not_equal_to(), *i)); + next_seq.append(to_string(distance(i, j))); + next_seq.push_back(*i); + i = j; + } + return next_seq; + } +}; diff --git a/C++/count-binary-substrings.cpp b/C++/count-binary-substrings.cpp new file mode 100644 index 000000000..defb0a3a3 --- /dev/null +++ b/C++/count-binary-substrings.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int countBinarySubstrings(string s) { + auto result = 0, prev = 0, curr = 1; + for (int i = 1; i < s.length(); ++i) { + if (s[i - 1] != s[i]) { + result += min(prev, curr); + prev = curr, curr = 1; + } else { + ++curr; + } + } + result += min(prev, curr); + return result; + } +}; diff --git a/C++/count-complete-tree-nodes.cpp b/C++/count-complete-tree-nodes.cpp new file mode 100644 index 000000000..ec755d366 --- /dev/null +++ b/C++/count-complete-tree-nodes.cpp @@ -0,0 +1,59 @@ +// Time: O(h * logn) = O((logn)^2) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int countNodes(TreeNode* root) { + if (root == nullptr) { + return 0; + } + + TreeNode *node = root; + int level = 0; + while (node->left != nullptr) { + node = node->left; + ++level; + } + + // Binary search. + int left = pow(2, level), right = pow(2, level + 1); + while (left < right) { + int mid = left + (right - left) / 2; + if (!exist(root, mid)) { + right = mid; + } else { + left = mid + 1; + } + } + return left - 1; + } + + // Check if the nth node exist. + bool exist(TreeNode *root, int n) { + int k = 1; + while (k <= n) { + k <<= 1; + } + k >>= 2; + + TreeNode *node = root; + while (k > 0) { + if ((n & k) == 0) { + node = node->left; + } else { + node = node->right; + } + k >>= 1; + } + return node != nullptr; + } +}; diff --git a/C++/count-different-palindromic-subsequences.cpp b/C++/count-different-palindromic-subsequences.cpp new file mode 100644 index 000000000..7301aaa3f --- /dev/null +++ b/C++/count-different-palindromic-subsequences.cpp @@ -0,0 +1,89 @@ +// Time: O(n^2) +// Space: O(n) +class Solution { +public: + int countPalindromicSubsequences(string S) { + static const int P = 1e9 + 7; + static const string chars = "abcd"; + vector>> dp(3, vector>(S.size(), vector(4))); + for (int len = 1; len <= S.size(); ++len) { + for (int i = 0; i + len <= S.size(); ++i) { + for (const auto& c : chars) { + dp[len % 3][i][c - 'a'] = 0; + if (len == 1) { + dp[len % 3][i][c - 'a'] = S[i] == c; + } else { + if (S[i] != c) { + dp[len % 3][i][c - 'a'] = dp[(len - 1) % 3][i + 1][c - 'a']; + } else if (S[i + len - 1] != c) { + dp[len % 3][i][c - 'a'] = dp[(len - 1) % 3][i][c - 'a']; + } else { + dp[len % 3][i][c - 'a'] = 2; + if (len > 2) { + for (const auto& cc : chars) { + dp[len % 3][i][c - 'a'] += dp[(len - 2) % 3][i + 1][cc - 'a']; + dp[len % 3][i][c - 'a'] %= P; + } + } + } + } + } + } + } + int result = 0; + for (const auto& c : chars) { + result = (result + dp[S.size() % 3][0][c - 'a']) % P; + } + return result; + } +}; + +// Time: O(n^2) +// Space: O(n^2) +class Solution2 { +public: + int countPalindromicSubsequences(string S) { + vector> prv(S.length(), vector(4, -1)); + vector> nxt(S.length(), vector(4, -1)); + vector last(4, -1); + for (int i = 0; i < S.length(); ++i) { + last[S[i] - 'a'] = i; + prv[i] = last; + } + last = vector(4, -1); + for (int i = S.length() - 1; i >= 0; --i) { + last[S[i] - 'a'] = i; + nxt[i] = last; + } + vector> lookup(S.length(), vector(S.length(), -1)); + return dp(0, S.length() - 1, prv, nxt, &lookup) - 1; + } + +private: + int dp(const int i, const int j, + const vector>& prv, + const vector>& nxt, + vector> *lookup) { + + if ((*lookup)[i][j] != -1) { + return (*lookup)[i][j]; + } + auto result = 1; + if (i <= j) { + for (int x = 0; x < 4; ++x) { + auto i0 = nxt[i][x]; + auto j0 = prv[j][x]; + if (i <= i0 && i0 <= j) { + result = (result + 1) % P; + } + if (i0 != -1 && j0 != -1 && i0 < j0) { + result = (result + dp(i0 + 1, j0 - 1, prv, nxt, lookup)) % P; + } + } + } + result %= P; + (*lookup)[i][j] = result; + return result; + } + static const int P = 1e9 + 7; +}; diff --git a/C++/count-numbers-with-unique-digits.cpp b/C++/count-numbers-with-unique-digits.cpp new file mode 100644 index 000000000..6b9b1e216 --- /dev/null +++ b/C++/count-numbers-with-unique-digits.cpp @@ -0,0 +1,18 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int countNumbersWithUniqueDigits(int n) { + if (n == 0) { + return 1; + } + int count = 10; // f(1) = 10 + for (int k = 2, fk = 9; k <= n; ++k) { + // f(k) = f(k - 1) * (10 - (k - 1)) + fk *= 10 - (k - 1); + count += fk; + } + return count; // sum(f(k), k=1~n) + } +}; diff --git a/C++/count-of-range-sum.cpp b/C++/count-of-range-sum.cpp new file mode 100644 index 000000000..15e48abef --- /dev/null +++ b/C++/count-of-range-sum.cpp @@ -0,0 +1,86 @@ +// Time: O(nlogn) +// Space: O(n) + +// Divide and Conquer solution. +class Solution { +public: + int countRangeSum(vector& nums, int lower, int upper) { + vector sums(nums.size() + 1); + for (int i = 0; i < nums.size(); ++i) { + sums[i + 1] = sums[i] + nums[i]; + } + return countAndMergeSort(&sums, 0, sums.size(), lower, upper); + } + + int countAndMergeSort(vector *sums, int start, int end, int lower, int upper) { + if (end - start <= 1) { // The number of range [start, end) of which size is less than 2 is always 0. + return 0; + } + int mid = start + (end - start) / 2; + int count = countAndMergeSort(sums, start, mid, lower, upper) + + countAndMergeSort(sums, mid, end, lower, upper); + int j = mid, k = mid, r = mid; + vector tmp; + for (int i = start; i < mid; ++i) { + // Count the number of range sums that lie in [lower, upper]. + while (k < end && (*sums)[k] - (*sums)[i] < lower) { + ++k; + } + while (j < end && (*sums)[j] - (*sums)[i] <= upper) { + ++j; + } + count += j - k; + + // Merge the two sorted arrays into tmp. + while (r < end && (*sums)[r] < (*sums)[i]) { + tmp.emplace_back((*sums)[r++]); + } + tmp.emplace_back((*sums)[i]); + } + // Copy tmp back to sums. + copy(tmp.begin(), tmp.end(), sums->begin() + start); + return count; + } +}; + +// Divide and Conquer solution. +class Solution2 { +public: + int countRangeSum(vector& nums, int lower, int upper) { + vector sums(nums.size() + 1); + for (int i = 0; i < nums.size(); ++i) { + sums[i + 1] = sums[i] + nums[i]; + } + return countAndMergeSort(&sums, 0, sums.size() - 1, lower, upper); + } + + int countAndMergeSort(vector *sums, int start, int end, int lower, int upper) { + if (end - start <= 0) { // The number of range [start, end] of which size is less than 2 is always 0. + return 0; + } + int mid = start + (end - start) / 2; + int count = countAndMergeSort(sums, start, mid, lower, upper) + + countAndMergeSort(sums, mid + 1, end, lower, upper); + int j = mid + 1, k = mid + 1, r = mid + 1; + vector tmp; + for (int i = start; i <= mid; ++i) { + // Count the number of range sums that lie in [lower, upper]. + while (k <= end && (*sums)[k] - (*sums)[i] < lower) { + ++k; + } + while (j <= end && (*sums)[j] - (*sums)[i] <= upper) { + ++j; + } + count += j - k; + + // Merge the two sorted arrays into tmp. + while (r <= end && (*sums)[r] < (*sums)[i]) { + tmp.emplace_back((*sums)[r++]); + } + tmp.emplace_back((*sums)[i]); + } + // Copy tmp back to sums. + copy(tmp.begin(), tmp.end(), sums->begin() + start); + return count; + } +}; diff --git a/C++/count-of-smaller-numbers-after-self.cpp b/C++/count-of-smaller-numbers-after-self.cpp new file mode 100644 index 000000000..dcfe10ed2 --- /dev/null +++ b/C++/count-of-smaller-numbers-after-self.cpp @@ -0,0 +1,162 @@ +// Time: O(nlogn) +// Space: O(n) + +// BST solution. (40ms) +class Solution { +public: + class BSTreeNode { + public: + int val, count; + BSTreeNode *left, *right; + BSTreeNode(int val, int count) { + this->val = val; + this->count = count; + this->left = this->right = nullptr; + } + }; + + vector countSmaller(vector& nums) { + vector res(nums.size()); + + BSTreeNode *root = nullptr; + + // Insert into BST and get left count. + for (int i = nums.size() - 1; i >= 0; --i) { + BSTreeNode *node = new BSTreeNode(nums[i], 0); + root = insertNode(root, node); + res[i] = query(root, nums[i]); + } + + return res; + } + + // Insert node into BST. + BSTreeNode* insertNode(BSTreeNode* root, BSTreeNode* node) { + if (root == nullptr) { + return node; + } + BSTreeNode* curr = root; + while (curr) { + // Insert left if smaller. + if (node->val < curr->val) { + ++curr->count; // Increase the number of left children. + if (curr->left != nullptr) { + curr = curr->left; + } else { + curr->left = node; + break; + } + } else { // Insert right if larger or equal. + if (curr->right != nullptr) { + curr = curr->right; + } else { + curr->right = node; + break; + } + } + } + return root; + } + + // Query the smaller count of the value. + int query(BSTreeNode* root, int val) { + if (root == nullptr) { + return 0; + } + int count = 0; + BSTreeNode* curr = root; + while (curr) { + // Insert left. + if (val < curr->val) { + curr = curr->left; + } else if (val > curr->val) { + count += 1 + curr->count; // Count the number of the smaller nodes. + curr = curr->right; + } else { // Equal. + return count + curr->count; + } + } + return 0; + } +}; + +// Time: O(nlogn) +// Space: O(n) +// BIT solution. (56ms) +class Solution2 { +public: + vector countSmaller(vector& nums) { + // Get the place (position in the ascending order) of each number. + vector sorted_nums(nums), places(nums.size()); + sort(sorted_nums.begin(), sorted_nums.end()); + for (int i = 0; i < nums.size(); ++i) { + places[i] = + lower_bound(sorted_nums.begin(), sorted_nums.end(), nums[i]) - + sorted_nums.begin(); + } + // Count the smaller elements after the number. + vector bit(nums.size() + 1), ans(nums.size()); + for (int i = nums.size() - 1; i >= 0; --i) { + ans[i] = query(bit, places[i]); + add(bit, places[i] + 1, 1); + } + return ans; + } + +private: + void add(vector& bit, int i, int val) { + for (; i < bit.size(); i += lower_bit(i)) { + bit[i] += val; + } + } + + int query(const vector& bit, int i) { + int sum = 0; + for (; i > 0; i -= lower_bit(i)) { + sum += bit[i]; + } + return sum; + } + + int lower_bit(int i) { + return i & -i; + } +}; + +// Time: O(nlogn) +// Space: O(n) +// Divide and Conquer solution. (80ms) +class Solution3 { +public: + vector countSmaller(vector& nums) { + vector counts(nums.size()); + vector> num_idxs; + for (int i = 0; i < nums.size(); ++i) { + num_idxs.emplace_back(nums[i], i); + } + countAndMergeSort(&num_idxs, 0, num_idxs.size() - 1, &counts); + return counts; + } + + void countAndMergeSort(vector> *num_idxs, int start, int end, vector *counts) { + if (end - start <= 0) { // The number of range [start, end] of which size is less than 2 doesn't need sort. + return; + } + int mid = start + (end - start) / 2; + countAndMergeSort(num_idxs, start, mid, counts); + countAndMergeSort(num_idxs, mid + 1, end, counts); + + int r = mid + 1; + vector> tmp; + for (int i = start; i <= mid; ++i) { + // Merge the two sorted arrays into tmp. + while (r <= end && (*num_idxs)[r].first < (*num_idxs)[i].first) { + tmp.emplace_back((*num_idxs)[r++]); + } + tmp.emplace_back((*num_idxs)[i]); + (*counts)[(*num_idxs)[i].second] += r - (mid + 1); + } + // Copy tmp back to num_idxs. + copy(tmp.begin(), tmp.end(), num_idxs->begin() + start); + } +}; diff --git a/C++/count-primes.cpp b/C++/count-primes.cpp new file mode 100644 index 000000000..0a6378427 --- /dev/null +++ b/C++/count-primes.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int countPrimes(int n) { + if (n <= 2) { + return 0; + } + + auto num = n / 2; + vector is_prime(n, true); + + for (int i = 3; i * i < n; i += 2) { + if (!is_prime[i]) { + continue; + } + + for (int j = i * i; j < n; j += 2 * i) { + if (!is_prime[j]) { + continue; + } + + --num; + is_prime[j] = false; + } + } + + return num; + } +}; diff --git a/C++/count-the-repetitions.cpp b/C++/count-the-repetitions.cpp new file mode 100644 index 000000000..feb30272f --- /dev/null +++ b/C++/count-the-repetitions.cpp @@ -0,0 +1,30 @@ +// Time: O(s1 * min(s2, n1)) +// Space: O(s2) + +class Solution { +public: + int getMaxRepetitions(string s1, int n1, string s2, int n2) { + vector repeatCount(s2.size() + 1, 0); + unordered_map lookup; + int j = 0, count = 0; + for (int k = 1; k <= n1; ++k) { + for (int i = 0; i < s1.size(); ++i) { + if (s1[i] == s2[j]) { + j = (j + 1) % s2.size(); + count += (j == 0); + } + } + + if (lookup.find(j) != lookup.end()) { // cyclic + int i = lookup[j]; + int prefixCount = repeatCount[i]; + int patternCount = (count - repeatCount[i]) * ((n1 - i) / (k - i)); + int suffixCount = repeatCount[i + (n1 - i) % (k - i)] - repeatCount[i]; + return (prefixCount + patternCount + suffixCount) / n2; + } + lookup[j] = k; + repeatCount[k] = count; + } + return repeatCount[n1] / n2; // not cyclic iff n1 <= s2 + } +}; diff --git a/C++/count-univalue-subtrees.cpp b/C++/count-univalue-subtrees.cpp new file mode 100644 index 000000000..885d96cd2 --- /dev/null +++ b/C++/count-univalue-subtrees.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int countUnivalSubtrees(TreeNode* root) { + int count = 0; + isUnivalSubtrees(root, &count); + return count; + } + + bool isUnivalSubtrees(TreeNode* root, int *count) { + if (root == nullptr) { + return true; + } + bool left = isUnivalSubtrees(root->left, count); + bool right = isUnivalSubtrees(root->right, count); + if (isSame(root, root->left, left) && + isSame(root, root->right, right)) { + ++(*count); + return true; + } + return false; + } + + bool isSame(TreeNode* root, TreeNode* child, bool is_uni) { + return child == nullptr || (is_uni && root->val == child->val); + } +}; diff --git a/C++/counting-bits.cpp b/C++/counting-bits.cpp new file mode 100644 index 000000000..bdc3f7c71 --- /dev/null +++ b/C++/counting-bits.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector countBits(int num) { + vector res{0}; + for (int i = 1; i <= num; ++i) { + res.emplace_back((i & 1) + res[i >> 1]); + } + return res; + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + vector countBits(int num) { + vector res{0}; + for (int i = 0, cnt = res.size(); + res.size() <= num; + i = (i + 1) % cnt) { + if (i == 0) { + cnt = res.size(); + } + res.emplace_back(res[i] + 1); + } + return res; + } +}; diff --git a/C++/course-schedule-ii.cpp b/C++/course-schedule-ii.cpp new file mode 100644 index 000000000..198122315 --- /dev/null +++ b/C++/course-schedule-ii.cpp @@ -0,0 +1,52 @@ +// Time: O(|V| + |E||) +// Space: O(|E|) + +// Topological sort solution. +class Solution { +public: + vector findOrder(int numCourses, vector>& prerequisites) { + vector res; + // Store courses with in-degree zero. + queue zeroInDegree; + + // in-degree, out-degree + unordered_map> inDegree; + unordered_map> outDegree; + for (int i = 0; i < prerequisites.size(); ++i) { + inDegree[prerequisites[i].first].insert(prerequisites[i].second); + outDegree[prerequisites[i].second].insert(prerequisites[i].first); + } + + // Put all the courses with in-degree zero into queue. + for(int i = 0; i < numCourses; ++i) { + if(inDegree.find(i) == inDegree.end()) { + zeroInDegree.push(i); + } + } + + // V+E + while(!zeroInDegree.empty()) { + // Take the course which prerequisites are all taken. + int prerequisite = zeroInDegree.front(); + res.emplace_back(prerequisite); + zeroInDegree.pop(); + for (const auto & course: outDegree[prerequisite]) { + // Update info of all the courses with the taken prerequisite. + inDegree[course].erase(prerequisite); + // If all the prerequisites are taken, add the course to the queue. + if (inDegree[course].empty()) { + zeroInDegree.push(course); + } + } + // Mark the course as taken. + outDegree.erase(prerequisite); + } + + // All of the courses have been taken. + if (!outDegree.empty()) { + return {}; + } + + return res; + } +}; diff --git a/C++/course-schedule-iii.cpp b/C++/course-schedule-iii.cpp new file mode 100644 index 000000000..9a996fa62 --- /dev/null +++ b/C++/course-schedule-iii.cpp @@ -0,0 +1,23 @@ +// Time: O(nlogn) +// Space: O(k), k is the number of courses you can take + +class Solution { +public: + int scheduleCourse(vector>& courses) { + sort(courses.begin(), courses.end(), + [](const vector& a, const vector& b) { + return a[1] < b[1]; + }); + priority_queue max_heap; + int now = 0; + for (const auto& course : courses) { + max_heap.emplace(course[0]); + now += course[0]; + if (now > course[1]) { + now -= max_heap.top(), max_heap.pop(); + } + } + return heap.size(); + } +}; + diff --git a/C++/course-schedule.cpp b/C++/course-schedule.cpp new file mode 100644 index 000000000..2cf78f602 --- /dev/null +++ b/C++/course-schedule.cpp @@ -0,0 +1,50 @@ +// Time: O(|V| + |E|) +// Space: O(|E|) + +// Topological sort solution. +class Solution { +public: + bool canFinish(int numCourses, vector>& prerequisites) { + // Store courses with in-degree zero. + queue zeroInDegree; + + // in-degree, out-degree + unordered_map> inDegree; + unordered_map> outDegree; + for (int i = 0; i < prerequisites.size(); ++i) { + inDegree[prerequisites[i][0]].insert(prerequisites[i][1]); + outDegree[prerequisites[i][1]].insert(prerequisites[i][0]); + } + + // Put all the courses with in-degree zero into queue. + for(int i = 0; i < numCourses; ++i) { + if(inDegree.find(i) == inDegree.end()) { + zeroInDegree.push(i); + } + } + + // V+E + while(!zeroInDegree.empty()) { + // Take the course which prerequisites are all taken. + int prerequisite = zeroInDegree.front(); + zeroInDegree.pop(); + for (const auto & course: outDegree[prerequisite]) { + // Update info of all the courses with the taken prerequisite. + inDegree[course].erase(prerequisite); + // If all the prerequisites are taken, add the course to the queue. + if (inDegree[course].empty()) { + zeroInDegree.push(course); + } + } + // Mark the course as taken. + outDegree.erase(prerequisite); + } + + // All of the courses have been taken. + if (!outDegree.empty()) { + return false; + } + + return true; + } +}; diff --git a/C++/create-maximum-number.cpp b/C++/create-maximum-number.cpp new file mode 100644 index 000000000..4ebd28884 --- /dev/null +++ b/C++/create-maximum-number.cpp @@ -0,0 +1,84 @@ +// Time: O(k * (m + n + k)) ~ O(k * (m + n + k^2)) +// Space: O(m + n + k^2) + +// DP + Greedy solution. +class Solution { +public: + vector maxNumber(vector& nums1, vector& nums2, int k) { + const int m = nums1.size(), n = nums2.size(); + vector> max_numbers1(k + 1), max_numbers2(k + 1); + maxNumberDP(nums1, max(0, k - n), min(k, m), &max_numbers1); // O(k * m) time, O(m + k^2) space. + maxNumberDP(nums2, max(0, k - m), min(k, n), &max_numbers2); // O(k * n) time, O(n + k^2) space. + + vector res(k); + for (int i = max(0, k - n); i <= min(k, m); ++i) { // k * O(k) ~ k * O(k^2) time + vector tmp(k); + merge(max_numbers1[i], max_numbers2[k - i], &tmp); + if (tmp > res) { + res = move(tmp); + } + } + return res; + } + +private: + void maxNumberDP(vector nums, int start, int end, vector> *max_numbers) { + (*max_numbers)[end] = maxNumber(nums, end); + for (int i = end - 1; i >= start; --i) { + (*max_numbers)[i] = deleteNumber((*max_numbers)[i + 1]); + } + } + + // Time: O(n) + // Space: O(n) + vector maxNumber(const vector& nums, int k) { + vector res; + int drop = nums.size() - k; + for (const auto& num : nums) { + while (drop > 0 && !res.empty() && res.back() < num) { + res.pop_back(); + --drop; + } + res.emplace_back(num); + } + res.resize(k); + return res; + } + + // Time: O(n) + // Space: O(n) + vector deleteNumber(const vector& nums) { + vector res(nums); + for (int i = 0; i < res.size(); ++i) { + if (i == res.size() - 1 || res[i] < res[i + 1]) { + res.erase(res.begin() + i); + break; + } + } + return res; + } + + // Time: O(k) ~ O(k^2) + // Space: O(1) + void merge(const vector& vec1, const vector& vec2, vector *res) { + auto first1 = vec1.begin(), last1 = vec1.end(), + first2 = vec2.begin(), last2 = vec2.end(); + auto result = res->begin(); + while (first1 != last1 || first2 != last2) { + if (greater(first1, last1, first2, last2)) { + *result++ = *first1++; + } else { + *result++ = *first2++; + } + } + } + + template + bool greater(IT first1, IT last1, IT first2, IT last2) { + while (first1 != last1 && first2 != last2 && *first1 == *first2) { + ++first1; + ++first2; + } + return (first2 == last2) || (first1 != last1 && *first1 > *first2); + } +}; diff --git a/C++/cut-off-trees-for-golf-event.cpp b/C++/cut-off-trees-for-golf-event.cpp new file mode 100644 index 000000000..68555feaf --- /dev/null +++ b/C++/cut-off-trees-for-golf-event.cpp @@ -0,0 +1,153 @@ +// Time: O(t * (logt + m * n)), t is the number of trees +// Space: O(t + m * n) + +// Solution Reference: +// 1. https://discuss.leetcode.com/topic/103532/my-python-solution-inspired-by-a-algorithm/2 +// 2. https://discuss.leetcode.com/topic/103562/python-solution-based-on-wufangjie-s-hadlock-s-algorithm +// 3. https://en.wikipedia.org/wiki/A*_search_algorithm +// 4. https://cg2010studio.files.wordpress.com/2011/12/dijkstra-vs-a-star.png +class Solution { +public: + int cutOffTree(vector>& forest) { + const auto m = forest.size(), n = forest[0].size(); + priority_queue>, + vector>>, + greater>> > min_heap; + + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (forest[i][j] > 1) { + min_heap.emplace(forest[i][j], make_pair(i, j)); + } + } + } + + pair start; + int result = 0; + while (!min_heap.empty()) { + auto tree = min_heap.top(); min_heap.pop(); + int step = minStep(forest, start, tree.second, m, n); + if (step < 0) { + return -1; + } + result += step; + start = tree.second; + } + return result; + } + +private: + int minStep(const vector>& forest, + const pair& start, + const pair& end, + const int m, const int n) { + + int min_steps = abs(start.first - end.first) + abs(start.second - end.second); + unordered_set lookup; + vector> closer{start}, detour; + while (true) { + if (closer.empty()) { // cannot find a path in the closer expansions + if (detour.empty()) { // no other possible path + return -1; + } + // try other possible paths in detour expansions with extra 2-step cost + min_steps += 2; + swap(closer, detour); + } + int i, j; + tie(i, j) = closer.back(); closer.pop_back(); + if (make_pair(i, j) == end) { + return min_steps; + } + if (!lookup.count(i * n + j)) { + lookup.emplace(i * n + j); + vector> expansions = {{i + 1, j}, {i - 1, j}, {i, j + 1}, {i, j - 1}}; + for (const auto& expansion : expansions) { + int I, J; + tie(I, J) = expansion; + if (0 <= I && I < m && 0 <= J && J < n && + forest[I][J] && !lookup.count(I * n + J)) { + bool is_closer = dot({I - i, J - j}, {end.first - i, end.second - j}) > 0; + is_closer ? closer.emplace_back(I, J) : detour.emplace_back(I, J); + } + } + } + } + + return min_steps; + } + + inline int dot(const pair& a, const pair& b) { + return a.first * b.first + a.second * b.second; + } +}; + + +// Time: O(t * (logt + m * n)), t is the number of trees +// Space: O(t + m * n) +class Solution2 { +public: + int cutOffTree(vector>& forest) { + const auto m = forest.size(), n = forest[0].size(); + priority_queue>, + vector>>, + greater>> > min_heap; + + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (forest[i][j] > 1) { + min_heap.emplace(forest[i][j], make_pair(i, j)); + } + } + } + + pair start; + int result = 0; + while (!min_heap.empty()) { + auto tree = min_heap.top(); min_heap.pop(); + int step = minStep(forest, start, tree.second, m, n); + if (step < 0) { + return -1; + } + result += step; + start = tree.second; + } + return result; + } + +private: + int minStep(const vector>& forest, + const pair& start, + const pair& end, + const int m, const int n) { + + int min_steps = 0; + unordered_set lookup; + queue> q; + q.emplace(start); + lookup.emplace(start.first * n + start.second); + while (!q.empty()) { + int size = q.size(); + for (int i = 0; i < size; ++i) { + auto curr = q.front(); q.pop(); + if (curr == end) { + return min_steps; + } + static const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + for (const auto& direction : directions) { + int i = curr.first + direction.first; + int j = curr.second + direction.second; + if (i < 0 || i >= m || j < 0 || j >= n || + !forest[i][j] || lookup.count(i * n + j)) { + continue; + } + q.emplace(i, j); + lookup.emplace(i * n + j); + } + } + ++min_steps; + } + return -1; + } +}; diff --git a/C++/daily-temperatures.cpp b/C++/daily-temperatures.cpp new file mode 100644 index 000000000..18a0d1bf6 --- /dev/null +++ b/C++/daily-temperatures.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector dailyTemperatures(vector& temperatures) { + vector result(temperatures.size()); + stack stk; + for (int i = 0; i < temperatures.size(); ++i) { + while (!stk.empty() && + temperatures[stk.top()] < temperatures[i]) { + const auto idx = stk.top(); stk.pop(); + result[idx] = i - idx; + } + stk.emplace(i); + } + return result; + } +}; diff --git a/C++/data-stream-as-disjoint-intervals.cpp b/C++/data-stream-as-disjoint-intervals.cpp new file mode 100644 index 000000000..4561488a1 --- /dev/null +++ b/C++/data-stream-as-disjoint-intervals.cpp @@ -0,0 +1,165 @@ +// Time: addNum: O(logn), getIntervals: O(n), n is the number of disjoint intervals. +// Space: O(n) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +// Using set. +class SummaryRanges { +public: + /** Initialize your data structure here. */ + SummaryRanges() { + + } + + void addNum(int val) { + auto it = intervals_.upper_bound(Interval(val, val)); + int start = val, end = val; + if (it != intervals_.begin() && prev(it)->end + 1 >= val) { + --it; + } + while (it != intervals_.end() && end + 1 >= it->start) { + start = min(start, it->start); + end = max(end, it->end); + it = intervals_.erase(it); + } + intervals_.insert(it, Interval(start, end)); + } + + vector getIntervals() { + return {intervals_.cbegin(), intervals_.cend()}; + } + +private: + struct Compare { + bool operator() (const Interval& a, const Interval& b) { + return a.start < b.start; + } + }; + set intervals_; +}; + + +// Using map. +class SummaryRanges { +public: + /** Initialize your data structure here. */ + SummaryRanges() { + + } + + void addNum(int val) { + auto it = intervals_.upper_bound(val); + int start = val, end = val; + if (it != intervals_.begin() && prev(it)->second + 1 >= val) { + --it; + } + while (it != intervals_.end() && end + 1 >= it->first) { + start = min(start, it->first); + end = max(end, it->second); + it = intervals_.erase(it); + } + intervals_[start] = end; + } + + vector getIntervals() { + vector result; + for (const auto& kvp : intervals_) { + result.emplace_back(kvp.first, kvp.second); + } + return result; + } + +private: + map intervals_; +}; + + +// Time: addNum: O(n), getIntervals: O(n), n is the number of disjoint intervals. +// Space: O(n) +class SummaryRanges2 { +public: +public: + /** Initialize your data structure here. */ + SummaryRanges2() { + + } + + void addNum(int val) { + auto it = upper_bound(intervals_.begin(), intervals_.end(), Interval(val, val), Compare()); + int start = val, end = val; + if (it != intervals_.begin() && prev(it)->end + 1 >= val) { + --it; + } + while (it != intervals_.end() && end + 1 >= it->start) { + start = min(start, it->start); + end = max(end, it->end); + it = intervals_.erase(it); + } + intervals_.insert(it, Interval(start, end)); + } + + vector getIntervals() { + return intervals_; + } + +private: + struct Compare { + bool operator() (const Interval& a, const Interval& b) { + return a.start < b.start; + } + }; + vector intervals_; +}; + + +// Time: addNum: O(logs), getIntervals: O(s), s is the data stream's size. +// Space: O(s) +class SummaryRanges3 { +public: + /** Initialize your data structure here. */ + SummaryRanges3() { + + } + + void addNum(int val) { + nums_.emplace(val); + } + + vector getIntervals() { + vector result; + if (nums_.empty()) { + return result; + } + auto start = *nums_.begin(), end = *nums_.begin(); + for (auto it = next(nums_.begin()); it != nums_.end(); ++it) { + if (it != nums_.end() && *it == end + 1) { + end = *it; + } else { + result.emplace_back(start, end); + if (it != nums_.end()) { + start = end = *it; + } + } + } + result.emplace_back(start, end); + return result; + } + +private: + set nums_; +}; + +/** + * Your SummaryRanges object will be instantiated and called as such: + * SummaryRanges obj = new SummaryRanges(); + * obj.addNum(val); + * vector param_2 = obj.getIntervals(); + */ + diff --git a/C++/decode-string.cpp b/C++/decode-string.cpp new file mode 100644 index 000000000..07bee9973 --- /dev/null +++ b/C++/decode-string.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(h), h is the depth of the recursion + +class Solution { +public: + string decodeString(string s) { + string curr; + stack nums; + stack strs; + int n = 0; + for (const auto& c: s) { + if (isdigit(c)) { + n = n * 10 + c - '0'; + } else if (c == '[') { + nums.emplace(n); + n = 0; + strs.emplace(curr); + curr.clear(); + } else if (c == ']') { + for (; nums.top() > 0; --nums.top()) { + strs.top() += curr; + } + nums.pop(); + curr = strs.top(); + strs.pop(); + } else { + curr += c; + } + } + return strs.empty() ? curr : strs.top(); + } +}; diff --git a/C++/decode-ways-ii.cpp b/C++/decode-ways-ii.cpp new file mode 100644 index 000000000..40e586fb5 --- /dev/null +++ b/C++/decode-ways-ii.cpp @@ -0,0 +1,35 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int numDecodings(string s) { + static const int M = 1000000007; + static const int W = 3; + vector dp(W); + dp[0] = 1; + dp[1] = s[0] == '*' ? 9 : (s[0] != '0' ? dp[0] : 0); + for (int i = 1; i < s.length(); ++i) { + if (s[i] == '*') { + dp[(i + 1) % W] = 9 * dp[i % W]; + if (s[i - 1] == '1') { + dp[(i + 1) % W] = (dp[(i + 1) % W] + 9 * dp[(i - 1) % W]) % M; + } else if (s[i - 1] == '2') { + dp[(i + 1) % W] = (dp[(i + 1) % W] + 6 * dp[(i - 1) % W]) % M; + } else if (s[i - 1] == '*') { + dp[(i + 1) % W] = (dp[(i + 1) % W] + 15 * dp[(i - 1) % W]) % M; + } + } else { + dp[(i + 1) % W] = s[i] != '0' ? dp[i % W] : 0; + if (s[i - 1] == '1') { + dp[(i + 1) % W] = (dp[(i + 1) % W] + dp[(i - 1) % W]) % M; + } else if (s[i - 1] == '2' && s[i] <= '6') { + dp[(i + 1) % W] = (dp[(i + 1) % W] + dp[(i - 1) % W]) % M; + } else if (s[i - 1] == '*') { + dp[(i + 1) % W] = (dp[(i + 1) % W] + (s[i] <= '6' ? 2 : 1) * dp[(i - 1) % W]) % M; + } + } + } + return static_cast(dp[s.length() % W]); + } +}; diff --git a/C++/decode-ways.cpp b/C++/decode-ways.cpp new file mode 100644 index 000000000..38f4d9368 --- /dev/null +++ b/C++/decode-ways.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int numDecodings(string s) { + if (s.empty()) { + return 0; + } + + int prev = 0; // f[n - 2] + int cur = 1; // f[n - 1] + + for (int i = 0; i < s.length(); ++i) { + if (s[i] == '0') { + cur = 0; // f[n - 1] = 0 + } + if (i == 0 || + !(s[i - 1] == '1' || (s[i - 1] == '2' && s[i] <= '6'))) { + prev = 0; // f[n - 2] = 0 + } + + int tmp = cur; + cur += prev; // f[n] = f[n - 1] + f[n - 2] + prev = tmp; + } + + return cur; + } +}; diff --git a/C++/degree-of-an-array.cpp b/C++/degree-of-an-array.cpp new file mode 100644 index 000000000..4f8ca21a9 --- /dev/null +++ b/C++/degree-of-an-array.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int findShortestSubArray(vector& nums) { + unordered_map left, right; + unordered_map counts; + for (int i = 0; i < nums.size(); ++i) { + if (left.count(nums[i]) == 0) { + left[nums[i]] = i; + } + right[nums[i]] = i; + ++counts[nums[i]]; + } + auto degree = max_element(counts.begin(), counts.end(), + [](const pair& a, + const pair& b) { + return a.second < b.second; + })->second; + auto result = numeric_limits::max(); + for (const auto& kvp : counts) { + if (kvp.second == degree) { + result = min(result, right[kvp.first] - left[kvp.first] + 1); + } + } + return result; + } +}; diff --git a/C++/delete-and-earn.cpp b/C++/delete-and-earn.cpp new file mode 100644 index 000000000..d4e2b2505 --- /dev/null +++ b/C++/delete-and-earn.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int deleteAndEarn(vector& nums) { + vector vals(10001); + for (const auto& num : nums) { + vals[num] += num; + } + int val_i = vals[0], val_i_1 = 0, val_i_2 = 0; + for (int i = 1; i < vals.size(); ++i) { + val_i_2 = val_i_1; + val_i_1 = val_i; + val_i = max(vals[i] + val_i_2, val_i_1); + } + return val_i; + } +}; diff --git a/C++/delete-node-in-a-bst.cpp b/C++/delete-node-in-a-bst.cpp new file mode 100644 index 000000000..237fb89b7 --- /dev/null +++ b/C++/delete-node-in-a-bst.cpp @@ -0,0 +1,43 @@ +// Time: O(h) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* deleteNode(TreeNode* root, int key) { + if (!root) { + return nullptr; + } + if (root->val > key) { + root->left = deleteNode(root->left, key); + } else if (root->val < key) { + root->right = deleteNode(root->right, key); + } else { + if (!root->left) { + auto right = root->right; + delete root; + return right; + } else if (!root->right) { + auto left = root->left; + delete root; + return left; + } else { + auto successor = root->right; + while (successor->left) { + successor = successor->left; + } + root->val = successor->val; + root->right = deleteNode(root->right, successor->val); + } + } + return root; + } +}; diff --git a/C++/delete-node-in-a-linked-list.cpp b/C++/delete-node-in-a-linked-list.cpp new file mode 100644 index 000000000..17f100faf --- /dev/null +++ b/C++/delete-node-in-a-linked-list.cpp @@ -0,0 +1,23 @@ +// Time: O(1) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + void deleteNode(ListNode* node) { + if (!node || !node->next) { + return; + } + auto node_to_delete = node->next; + node->val = node->next->val; + node->next = node->next->next; + delete node_to_delete; + } +}; diff --git a/C++/delete-operation-for-two-strings.cpp b/C++/delete-operation-for-two-strings.cpp new file mode 100644 index 000000000..46a33c247 --- /dev/null +++ b/C++/delete-operation-for-two-strings.cpp @@ -0,0 +1,19 @@ +// Time: O(m * n) +// Space: O(n) + +class Solution { +public: + int minDistance(string word1, string word2) { + const auto m = word1.length(); + const auto n = word2.length(); + + vector> dp(2, vector(n + 1)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + dp[(i + 1) % 2][j + 1] = max(max(dp[i % 2][j + 1], dp[(i + 1) % 2][j]), + dp[i % 2][j] + (word1[i] == word2[j])); + } + } + return m + n - 2 * dp[m % 2][n]; + } +}; diff --git a/C++/deleteDuplicatesII.cpp b/C++/deleteDuplicatesII.cpp deleted file mode 100644 index f1e228b71..000000000 --- a/C++/deleteDuplicatesII.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *deleteDuplicates(ListNode *head) { - if(!head) - return NULL; - ListNode dummy(INT_MIN); - dummy.next = head; - ListNode *pre2nd = &dummy; - ListNode *pre1st = head; - ListNode *cur = pre1st->next; - bool isDup = false; - - while(pre1st) { - if(cur && pre1st->val == cur->val) { - pre2nd->next = cur; // remove previous first node - delete pre1st; - pre1st = NULL; - isDup = true; - } - else if(isDup){ - pre2nd->next = cur; // remove previous first node - delete pre1st; - pre1st = NULL; - isDup = false; - } - - if(pre1st) pre2nd = pre1st; - pre1st = cur; - if(cur) cur = cur->next; - } - - return dummy.next; - } -}; diff --git a/C++/design-compressed-string-iterator.cpp b/C++/design-compressed-string-iterator.cpp new file mode 100644 index 000000000..729715b34 --- /dev/null +++ b/C++/design-compressed-string-iterator.cpp @@ -0,0 +1,39 @@ +// Time: O(1) +// Space: O(1) + +class StringIterator { +public: + StringIterator(string compresult_sedString) + : result_(compresult_sedString), + num_(0), + ch_(' ') { + + } + + char next() { + if (!hasNext()) { + return ' '; + } + if (num_ == 0) { + result_ >> ch_ >> num_; + } + --num_; + return ch_; + } + + bool hasNext() { + return !result_.eof() || num_ != 0; + } + +private: + istringstream result_; + int num_; + char ch_; +}; + +/** + * Your StringIterator object will be instantiated and called as such_: + * StringIterator obj = new StringIterator(compresult_sedString); + * ch_ar param_1 = obj.next(); + * bool param_2 = obj.hasNext(); + */ diff --git a/C++/design-excel-sum-formula.cpp b/C++/design-excel-sum-formula.cpp new file mode 100644 index 000000000..2a627293e --- /dev/null +++ b/C++/design-excel-sum-formula.cpp @@ -0,0 +1,95 @@ +// Time: set: O((r * c)^2) +// get: O(1) +// sum: O((r * c)^2) +// Space: O(r * c) + +class Excel { +public: + Excel(int H, char W) : Exl_(H + 1, vector(W - 'A' + 1)) { + } + + // Time: O((r * c)^2) + void set(int r, char c, int v) { + auto col = c - 'A'; + reset_dependency(r, col); + update_others(r, col, v); + } + + // Time: O(1) + int get(int r, char c) { + return Exl_[r][c - 'A']; + } + + // Time: O((r * c)^2) + int sum(int r, char c, vector strs) { + auto col = c - 'A'; + reset_dependency(r, col); + auto result = calc_and_update_dependency(r, col, strs); + update_others(r, col, result); + return result; + } + +private: + // Time: O(r * c) + void reset_dependency(int r, int col) { + auto key = r * 26 + col; + if (bward_.count(key)) { + for (const auto& k : bward_[key]) { + fward_[k].erase(key); + } + bward_.erase(key); + } + } + + // Time: O(r * c * l), l is the length of strs + int calc_and_update_dependency(int r, int col, const vector& strs) { + auto result = 0; + for (const auto& s : strs) { + int p = s.find(':'), left, right, top, bottom; + left = s[0] - 'A'; + right = s[p + 1] - 'A'; + top = (p == string::npos) ? stoi(s.substr(1)) : stoi(s.substr(1, p - 1)); + bottom = stoi(s.substr(p + 2)); + for (int i = top; i <= bottom; ++i) { + for (int j = left; j <= right; ++j) { + result += Exl_[i][j]; + ++fward_[i * 26 + j][r * 26 + col]; + bward_[r * 26 + col].emplace(i * 26 + j); + } + } + } + return result; + } + + // Time: O((r * c)^2) + void update_others(int r, int col, int v) { + auto prev = Exl_[r][col]; + Exl_[r][col] = v; + queue> q; + q.emplace(make_pair(r * 26 + col, v - prev)); + while (!q.empty()) { + int key, diff; + tie(key, diff) = q.front(), q.pop(); + if (fward_.count(key)) { + for (auto it = fward_[key].begin(); it != fward_[key].end(); ++it) { + int k, count; + tie(k, count) = *it; + q.emplace(make_pair(k, diff * count)); + Exl_[k / 26][k % 26] += diff * count; + } + } + } + } + + unordered_map> fward_; + unordered_map> bward_; + vector> Exl_; +}; + +/** + * Your Excel object will be instantiated and called as such: + * Excel obj = new Excel(H, W); + * obj.set(r,c,v); + * int param_2 = obj.get(r,c); + * int param_3 = obj.sum(r,c,strs); + */ diff --git a/C++/design-hit-counter.cpp b/C++/design-hit-counter.cpp new file mode 100644 index 000000000..22038d828 --- /dev/null +++ b/C++/design-hit-counter.cpp @@ -0,0 +1,45 @@ +// Time: O(1), amortized +// Space: O(k), k is the count of seconds. + +class HitCounter { +public: + /** Initialize your data structure here. */ + HitCounter() : count_(0) { + + } + + /** Record a hit. + @param timestamp - The current timestamp (in seconds granularity). */ + void hit(int timestamp) { + getHits(timestamp); + if (!dq_.empty() && dq_.back().first == timestamp) { + ++dq_.back().second; + } else { + dq_.emplace_back(timestamp, 1); + } + ++count_; + } + + /** Return the number of hits in the past 5 minutes. + @param timestamp - The current timestamp (in seconds granularity). */ + int getHits(int timestamp) { + while (!dq_.empty() && dq_.front().first <= timestamp - k_) { + count_ -= dq_.front().second; + dq_.pop_front(); + } + return count_; + } + +private: + const int k_ = 300; + int count_; + deque> dq_; +}; + +/** + * Your HitCounter object will be instantiated and called as such: + * HitCounter obj = new HitCounter(); + * obj.hit(timestamp); + * int param_2 = obj.getHits(timestamp); + */ + diff --git a/C++/design-in-memory-file-system.cpp b/C++/design-in-memory-file-system.cpp new file mode 100644 index 000000000..65423bd9f --- /dev/null +++ b/C++/design-in-memory-file-system.cpp @@ -0,0 +1,93 @@ +// Time: ls: O(l + klogk), l is the path length, k is the number of entries in the last level directory +// mkdir: O(l) +// addContentToFile: O(l + c), c is the content size +// readContentFromFile: O(l + c) +// Space: O(n + s), n is the number of dir/file nodes, s is the total content size. + +class FileSystem { +public: + FileSystem() : root_(new TrieNode()) { + + } + + vector ls(string path) { + auto curr = getNode(path); + + if (curr->isFile) { + return {split(path, '/').back()}; + } + + vector result; + for (const auto& child : curr->children) { + result.emplace_back(child.first); + } + sort(result.begin(), result.end()); + return result; + } + + void mkdir(string path) { + auto curr = putNode(path); + curr->isFile = false; + } + + void addContentToFile(string filePath, string content) { + auto curr = putNode(filePath); + curr->isFile = true; + curr->content += content; + } + + string readContentFromFile(string filePath) { + return getNode(filePath)->content; + } + +private: + struct TrieNode { + bool isFile; + unordered_map children; + string content; + }; + + TrieNode *root_; + + TrieNode *getNode(const string& path) { + vector strs = split(path, '/'); + auto curr = root_; + for (const auto& str : strs) { + curr = curr->children[str]; + } + return curr; + } + + TrieNode *putNode(const string& path) { + vector strs = split(path, '/'); + auto curr = root_; + for (const auto& str : strs) { + if (!curr->children.count(str)) { + curr->children[str] = new TrieNode(); + } + curr = curr->children[str]; + } + return curr; + } + + vector split(const string& s, const char delim) { + vector tokens; + stringstream ss(s); + string token; + while (getline(ss, token, delim)) { + if (!token.empty()) { + tokens.emplace_back(token); + } + } + return tokens; + } +}; + +/** + * Your FileSystem object will be instantiated and called as such: + * FileSystem obj = new FileSystem(); + * vector param_1 = obj.ls(path); + * obj.mkdir(path); + * obj.addContentToFile(filePath,content); + * string param_4 = obj.readContentFromFile(filePath); + */ diff --git a/C++/design-log-storage-system.cpp b/C++/design-log-storage-system.cpp new file mode 100644 index 000000000..cba11e80c --- /dev/null +++ b/C++/design-log-storage-system.cpp @@ -0,0 +1,44 @@ +// Time: put: O(logn), n is the size of the total logs +// retrieve: O(logn + d), d is the size of the found logs +// Space: O(n) + +class LogSystem { +public: + LogSystem() { + granularity_["Year"] = 4; + granularity_["Month"] = 7; + granularity_["Day"] = 10; + granularity_["Hour"] = 13; + granularity_["Minute"] = 16; + granularity_["Second"] = 19; + } + + void put(int id, string timestamp) { + lookup_.emplace(timestamp, id); + } + + vector retrieve(string s, string e, string gra) { + s = s.substr(0, granularity_[gra]) + s_filter_.substr(granularity_[gra]); + e = e.substr(0, granularity_[gra]) + e_filter_.substr(granularity_[gra]); + + vector result; + auto end = lookup_.upper_bound(e); + for (auto it = lookup_.lower_bound(s); it != end; ++it) { + result.emplace_back(it->second); + } + return result; + } + +private: + string s_filter_ = "0001:01:01:00:00:00"; + string e_filter_ = "9999:12:31:23:59:59"; + unordered_map granularity_; + multimap lookup_; +}; + +/** + * Your LogSystem object will be instantiated and called as such: + * LogSystem obj = new LogSystem(); + * obj.put(id,timestamp); + * vector param_2 = obj.retrieve(s,e,gra); + */ diff --git a/C++/design-phone-directory.cpp b/C++/design-phone-directory.cpp new file mode 100644 index 000000000..19f77a75b --- /dev/null +++ b/C++/design-phone-directory.cpp @@ -0,0 +1,56 @@ +// init: Time: O(n), Space: O(n) +// get: Time: O(1), Space: O(1) +// check: Time: O(1), Space: O(1) +// release: Time: O(1), Space: O(1) + +class PhoneDirectory { +public: + /** Initialize your data structure here + @param maxNumbers - The maximum numbers that can be stored in the phone directory. */ + PhoneDirectory(int maxNumbers) : + curr_{0}, numbers_(maxNumbers), used_(maxNumbers) { // Time: O(n), Space: O(n) + + iota(numbers_.begin(), numbers_.end(), 0); + } + + /** Provide a number which is not assigned to anyone. + @return - Return an available number. Return -1 if none is available. */ + int get() { // Time: O(1), Space: O(1) + if (curr_ == numbers_.size()) { + return -1; + } + const auto number = numbers_[curr_++]; + used_[number] = true; + return number; + } + + /** Check if a number is available or not. */ + bool check(int number) { // Time: O(1), Space: O(1) + if (number < 0 || number >= numbers_.size()) { + return false; + } + return !used_[number]; + } + + /** Recycle or release a number. */ + void release(int number) { // Time: O(1), Space: O(1) + if (number < 0 || number >= numbers_.size() || !used_[number]) { + return; + } + used_[number] = false; + numbers_[--curr_] = number ; + } + +private: + int curr_; + vector numbers_; + vector used_; +}; + +/** + * Your PhoneDirectory object will be instantiated and called as such: + * PhoneDirectory obj = new PhoneDirectory(maxNumbers); + * int param_1 = obj.get(); + * bool param_2 = obj.check(number); + * obj.release(number); + */ diff --git a/C++/design-search-autocomplete-system.cpp b/C++/design-search-autocomplete-system.cpp new file mode 100644 index 000000000..a93f873d9 --- /dev/null +++ b/C++/design-search-autocomplete-system.cpp @@ -0,0 +1,92 @@ +// Time: O(p^2), p is the length of the prefix +// Space: O(p * t + s), t is the number of nodes of trie +// , s is the size of the sentences + +class AutocompleteSystem { +public: + AutocompleteSystem(vector sentences, vector times) : cur_node_(&trie_) { + for (int i = 0; i < sentences.size(); ++i) { + sentence_to_count_[sentences[i]] = times[i]; + trie_.insert(sentences[i], sentence_to_count_[sentences[i]]); + } + } + + vector input(char c) { + vector result; + if (c == '#') { + ++sentence_to_count_[search_]; + trie_.insert(search_, sentence_to_count_[search_]); + cur_node_ = &trie_; + search_.clear(); + } else { + search_.push_back(c); + if (cur_node_) { + if (!cur_node_->leaves_.count(c)) { + cur_node_ = nullptr; + return {}; + } + cur_node_ = cur_node_->leaves_[c]; + for (const auto& p : cur_node_->infos_) { + result.emplace_back(p.second); + } + } + } + return result; + } + +private: + class TrieNode { + public: + static const int TOP_COUNT = 3; + + ~TrieNode() { + for (auto& kv : leaves_) { + if (kv.second) { + delete kv.second; + } + } + } + + // Time: O(s) + void insert(const string& s, int times) { + auto* cur = this; + cur->add_info(s, times); + for (const auto& c : s) { + if (!cur->leaves_.count(c)) { + cur->leaves_[c] = new TrieNode; + } + cur = cur->leaves_[c]; + cur->add_info(s, times); + } + } + + // Time: O(1) + void add_info(const string& s, int times) { + auto it = find_if(infos_.begin(), infos_.end(), + [&s, ×](const pair& p){ return p.second == s;} ); + if (it != infos_.end()) { + it->first = -times; + } else { + infos_.emplace_back(-times, s); + } + sort(infos_.begin(), infos_.end()); + if (infos_.size() > TOP_COUNT) { + infos_.pop_back(); + } + } + + vector> infos_; + unordered_map leaves_; + }; + + TrieNode trie_; + TrieNode *cur_node_; + string search_; + unordered_map sentence_to_count_; +}; + +/** + * Your AutocompleteSystem object will be instantiated and called as such: + * AutocompleteSystem obj = new AutocompleteSystem(sentences, times); + * vector param_1 = obj.input(c); + */ \ No newline at end of file diff --git a/C++/design-snake-game.cpp b/C++/design-snake-game.cpp new file mode 100644 index 000000000..432e19114 --- /dev/null +++ b/C++/design-snake-game.cpp @@ -0,0 +1,67 @@ +// Time: O(1) per move +// Space: O(s), s is the current length of the snake. + +class SnakeGame { +public: + /** Initialize your data structure here. + @param width - screen width + @param height - screen height + @param food - A list of food positions + E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. */ + SnakeGame(int width, int height, vector> food) : + width_{width}, height_{height}, score_{0}, + food_{food.begin(), food.end()}, snake_{{0, 0}} { + + lookup_.emplace(0); + } + + /** Moves the snake. + @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + @return The game's score after the move. Return -1 if game over. + Game over when snake crosses the screen boundary or bites its body. */ + int move(string direction) { + const auto x = snake_.back().first + direction_[direction].first; + const auto y = snake_.back().second + direction_[direction].second; + const auto tail = snake_.back(); + + auto it = lookup_.find(hash(snake_.front().first, snake_.front().second)); + lookup_.erase(it); + snake_.pop_front(); + if (!valid(x, y)) { + return -1; + } else if (!food_.empty() && food_.front().first == x && food_.front().second == y) { + ++score_; + food_.pop_front(); + snake_.push_front(tail); + lookup_.emplace(hash(tail.first, tail.second)); + } + snake_.push_back({x, y}); + lookup_.emplace(hash(x, y)); + return score_; + } + +private: + bool valid(int x, int y) { + if (x < 0 || x >= height_ || y < 0 || y >= width_) { + return false; + } + return lookup_.find(hash(x, y)) == lookup_.end(); + } + + int hash(int x, int y) { + return x * width_ + y; + } + + int width_, height_, score_; + deque> food_, snake_; + unordered_multiset lookup_; + unordered_map> direction_ = {{"U", {-1, 0}}, {"L", {0, -1}}, + {"R", {0, 1}}, {"D", {1, 0}}}; +}; + +/** + * Your SnakeGame object will be instantiated and called as such: + * SnakeGame obj = new SnakeGame(width, height, food); + * int param_1 = obj.move(direction); + */ + diff --git a/C++/design-tic-tac-toe.cpp b/C++/design-tic-tac-toe.cpp new file mode 100644 index 000000000..c1c98efb0 --- /dev/null +++ b/C++/design-tic-tac-toe.cpp @@ -0,0 +1,46 @@ +// Time: O(1), per move. +// Space: O(n^2) + +class TicTacToe { +public: + /** Initialize your data structure here. */ + TicTacToe(int n) : rows_(n, {0, 0}), cols_(n, {0, 0}), + diagonal_(2, 0), anti_diagonal_(2, 0) { + } + + /** Player {player} makes a move at ({row}, {col}). + @param row The row of the board. + @param col The column of the board. + @param player The player, can be either 1 or 2. + @return The current winning condition, can be either: + 0: No one wins. + 1: Player 1 wins. + 2: Player 2 wins. */ + int move(int row, int col, int player) { + const auto i = player - 1; + ++rows_[row][i], ++cols_[col][i]; + if (row == col) { + ++diagonal_[i]; + } + if (col == rows_.size() - row - 1) { + ++anti_diagonal_[i]; + } + if (rows_[row][i] == rows_.size() || + cols_[col][i] == cols_.size() || + diagonal_[i] == rows_.size() || + anti_diagonal_[i] == cols_.size()) { + return player; + } + return 0; + } + +private: + vector> rows_, cols_; + vector diagonal_, anti_diagonal_; +}; + +/** + * Your TicTacToe object will be instantiated and called as such: + * TicTacToe obj = new TicTacToe(n); + * int param_1 = obj.move(row,col,player); + */ diff --git a/C++/design-twitter.cpp b/C++/design-twitter.cpp new file mode 100644 index 000000000..5a37925f6 --- /dev/null +++ b/C++/design-twitter.cpp @@ -0,0 +1,82 @@ +// Time: O(klogu), k is most recently number of tweets, +// u is the number of the user's following. +// Space: O(t + f), t is the total number of tweets, +// f is the total number of followings. + +class Twitter { +public: + /** Initialize your data structure here. */ + Twitter() : time_(0) { + + } + + /** Compose a new tweet. */ + void postTweet(int userId, int tweetId) { + messages_[userId].emplace_back(make_pair(++time_, tweetId)); + } + + /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */ + vector getNewsFeed(int userId) { + using RIT = deque>::reverse_iterator; + priority_queue> heap; + + if (messages_[userId].size()) { + heap.emplace(make_tuple(messages_[userId].rbegin()->first, + messages_[userId].rbegin(), + messages_[userId].rend())); + } + for (const auto& id : followings_[userId]) { + if (messages_[id].size()) { + heap.emplace(make_tuple(messages_[id].rbegin()->first, + messages_[id].rbegin(), + messages_[id].rend())); + } + } + vector res; + while (!heap.empty() && res.size() < number_of_most_recent_tweets_) { + const auto& top = heap.top(); + size_t t; + RIT begin, end; + tie(t, begin, end) = top; + heap.pop(); + + auto next = begin + 1; + if (next != end) { + heap.emplace(make_tuple(next->first, next, end)); + } + + res.emplace_back(begin->second); + } + return res; + } + + /** Follower follows a followee. If the operation is invalid, it should be a no-op. */ + void follow(int followerId, int followeeId) { + if (followerId != followeeId && !followings_[followerId].count(followeeId)) { + followings_[followerId].emplace(followeeId); + } + } + + /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */ + void unfollow(int followerId, int followeeId) { + if (followings_[followerId].count(followeeId)) { + followings_[followerId].erase(followeeId); + } + } + +private: + const size_t number_of_most_recent_tweets_ = 10; + unordered_map> followings_; + unordered_map>> messages_; + size_t time_; +}; + +/** + * Your Twitter object will be instantiated and called as such: + * Twitter obj = new Twitter(); + * obj.postTweet(userId,tweetId); + * vector param_2 = obj.getNewsFeed(userId); + * obj.follow(followerId,followeeId); + * obj.unfollow(followerId,followeeId); + */ + diff --git a/C++/detect-capital.cpp b/C++/detect-capital.cpp new file mode 100644 index 000000000..59f287a8f --- /dev/null +++ b/C++/detect-capital.cpp @@ -0,0 +1,10 @@ +// Time: O(l) +// Space: O(1) + +class Solution { +public: + bool detectCapitalUse(string word) { + int count = count_if(word.begin(), word.end(), [](char c){ return isupper(c); }); + return count == word.length() || count == 0 || (count == 1 && isupper(word[0])); + } +}; diff --git a/C++/detectCycle.cpp b/C++/detectCycle.cpp deleted file mode 100644 index 3e066a2da..000000000 --- a/C++/detectCycle.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *detectCycle(ListNode *head) { - ListNode *slow = head, *fast = head; - - while(fast && fast->next) { - slow = slow->next; - fast = fast->next->next; - - if(slow == fast) { - ListNode *slow2 = head; - while(slow2 != slow) { - slow2 = slow2->next; - slow = slow->next; - } - return slow2; - } - } - - return NULL; - } -}; diff --git a/C++/diagonal-traverse.cpp b/C++/diagonal-traverse.cpp new file mode 100644 index 000000000..989cc0aa6 --- /dev/null +++ b/C++/diagonal-traverse.cpp @@ -0,0 +1,39 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + vector findDiagonalOrder(vector>& matrix) { + if (matrix.empty() || matrix[0].empty()) { + return {}; + } + + vector result; + int row = 0, col = 0, d = 0; + vector> dirs = {{-1, 1}, {1, -1}}; + + for (int i = 0; i < matrix.size() * matrix[0].size(); ++i) { + result.emplace_back(matrix[row][col]); + row += dirs[d][0]; + col += dirs[d][1]; + + if (row >= static_cast(matrix.size())) { + row = matrix.size() - 1; + col += 2; + d = 1 - d; + } else if (col >= static_cast(matrix[0].size())) { + col = matrix[0].size() - 1; + row += 2; + d = 1 - d; + } else if (row < 0) { + row = 0; + d = 1 - d; + } else if (col < 0) { + col = 0; + d = 1 - d; + } + } + + return result; + } +}; diff --git a/C++/diameter-of-binary-tree.cpp b/C++/diameter-of-binary-tree.cpp new file mode 100644 index 000000000..c7c46d0f3 --- /dev/null +++ b/C++/diameter-of-binary-tree.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int diameterOfBinaryTree(TreeNode* root) { + int diameter = 1; + depth(root, &diameter); + return diameter - 1; + } + +private: + int depth(TreeNode *root, int *diameter) { + if (!root) { + return 0; + } + auto left = depth(root->left, diameter); + auto right = depth(root->right, diameter); + *diameter = max(*diameter, 1 + left + right); + return 1 + max(left, right); + } +}; diff --git a/C++/different-ways-to-add-parentheses.cpp b/C++/different-ways-to-add-parentheses.cpp new file mode 100644 index 000000000..91f62e9ae --- /dev/null +++ b/C++/different-ways-to-add-parentheses.cpp @@ -0,0 +1,76 @@ +// Time: O(n * (C(2n, n) - C(2n, n - 1))), this is at most +// Space: O(n * (C(2n, n) - C(2n, n - 1))) + +class Solution { + public: + vector diffWaysToCompute(string input) { + vector>> lookup(input.length() + 1, + vector>(input.length() + 1)); + return diffWaysToComputeRecu(input, 0, input.length(), lookup); + } + + vector diffWaysToComputeRecu(const string& input, + const int start, const int end, + vector>>& lookup) { + if (!lookup[start][end].empty()) { + return lookup[start][end]; + } + vector result; + for (int i = start; i < end; ++i) { + const auto cur = input[i]; + if (cur == '+' || cur == '-' || cur == '*') { + auto left = diffWaysToComputeRecu(input, start, i, lookup); + auto right = diffWaysToComputeRecu(input, i + 1, end, lookup); + for (const auto& num1 : left) { + for (const auto& num2 : right) { + if (cur == '+') { + result.emplace_back(num1 + num2); + } else if (cur == '-') { + result.emplace_back(num1 - num2); + } else { + result.emplace_back(num1 * num2); + } + } + } + } + } + // If the input string contains only number. + if (result.empty()) { + result.emplace_back(stoi(input.substr(start, end - start))); + } + lookup[start][end] = result; + return lookup[start][end]; + } +}; + +// Time: O(n * (C(2n, n) - C(2n, n - 1))), this is at least +// Space: O(C(2n, n) - C(2n, n - 1)) +class Solution2 { + public: + vector diffWaysToCompute(string input) { + vector result; + for (int i = 0; i < input.length(); ++i) { + const auto cur = input[i]; + if (cur == '+' || cur == '-' || cur == '*') { + auto left = diffWaysToCompute(input.substr(0, i)); + auto right = diffWaysToCompute(input.substr(i + 1)); + for (const auto& num1 : left) { + for (const auto& num2 : right) { + if (cur == '+') { + result.emplace_back(num1 + num2); + } else if (cur == '-') { + result.emplace_back(num1 - num2); + } else { + result.emplace_back(num1 * num2); + } + } + } + } + } + // If the input string contains only number. + if (result.empty()) { + result.emplace_back(stoi(input)); + } + return result; + } +}; diff --git a/C++/distribute-candies.cpp b/C++/distribute-candies.cpp new file mode 100644 index 000000000..ffbda99da --- /dev/null +++ b/C++/distribute-candies.cpp @@ -0,0 +1,13 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int distributeCandies(vector& candies) { + unordered_set lookup; + for (const auto& candy: candies) { + lookup.emplace(candy); + } + return min(lookup.size(), candies.size() / 2); + } +}; diff --git a/C++/divide-two-integers.cpp b/C++/divide-two-integers.cpp new file mode 100644 index 000000000..79baca979 --- /dev/null +++ b/C++/divide-two-integers.cpp @@ -0,0 +1,78 @@ +// Time: O(logn) = O(1) +// Space: O(1) + +// Only using integer type. +class Solution { +public: + int divide(int dividend, int divisor) { + // Handle corner case. + if (dividend == numeric_limits::min() && divisor == -1) { + return numeric_limits::max(); + } + + int a = dividend > 0 ? -dividend : dividend; + int b = divisor > 0 ? -divisor : divisor; + + int shift = 0; + while (b << shift < 0 && shift < 32) { + ++shift; + } + shift -= 1; + + int result = 0; + while (shift >= 0) { + if (a <= b << shift) { + a -= b << shift; + result += 1 << shift; + } + --shift; + } + + result = (dividend ^ divisor) >> 31 ? -result : result; + return result; + } +}; + +// Time: O(logn) = O(1) +// Space: O(1) +// Using long long type. +class Solution2 { +public: + int divide(int dividend, int divisor) { + long long result = 0; + long long a = llabs(dividend); + long long b = llabs(divisor); + + int shift = 31; + while (shift >= 0) { + if (a >= b << shift) { + a -= b << shift; + result += 1LL << shift; + } + --shift; + } + + result = ((dividend ^ divisor) >> 31) ? -result : result; + return min(result, static_cast(numeric_limits::max())); + } +}; + +// Time: O(logn) = O(1) +// Space: O(1) +// a / b = exp^(ln(a) - ln(b)) +class Solution3 { +public: + int divide(int dividend, int divisor) { + if (dividend == 0) { + return 0; + } + if (divisor == 0) { + return numeric_limits::max(); + } + + long long result = exp(log(fabs(dividend)) - log(fabs(divisor))); + + result = ((dividend ^ divisor) >> 31) ? -result : result; + return min(result, static_cast(numeric_limits::max())); + } +}; diff --git a/C++/divide.cpp b/C++/divide.cpp deleted file mode 100644 index 988507e84..000000000 --- a/C++/divide.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Time Complexity: O(logn) -// Space Complexity: O(1) - -class Solution { - public: - int divide(int dividend, int divisor) { - long long a = dividend >= 0 ? dividend : -(long long)dividend; - long long b = divisor >= 0 ? divisor : -(long long)divisor; - - long long result = 0; - while(a >= b) { - long long c = b; - int i = 0; - for(; a >= c; c <<= 1, ++i); - if(i > 0) { - a -= c >> 1; - result += 1 << (i - 1); - } - } - - return ((dividend ^ divisor) >> 31)? -result : result; - } -}; diff --git a/C++/dota2-senate.cpp b/C++/dota2-senate.cpp new file mode 100644 index 000000000..e81597cce --- /dev/null +++ b/C++/dota2-senate.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string predictPartyVictory(string senate) { + queue radiant, dire; + const auto& n = senate.length(); + for (int i = 0; i < n; ++i) { + (senate[i] == 'R') ? radiant.emplace(i) : dire.emplace(i); + } + while (!radiant.empty() && !dire.empty()) { + int r_idx = radiant.front(), d_idx = dire.front(); + radiant.pop(), dire.pop(); + (r_idx < d_idx) ? radiant.emplace(r_idx + n) : dire.emplace(d_idx + n); + } + return (radiant.size() > dire.size()) ? "Radiant" : "Dire"; + } +}; diff --git a/C++/elimination-game.cpp b/C++/elimination-game.cpp new file mode 100644 index 000000000..0541d375f --- /dev/null +++ b/C++/elimination-game.cpp @@ -0,0 +1,17 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int lastRemaining(int n) { + int start = 1; + + for (int step = 2, direction = 1; n > 1; + n /= 2, step *= 2, direction *= -1) { + + start += direction * (step * (n / 2) - step / 2); + } + + return start; + } +}; diff --git a/C++/employee-importance.cpp b/C++/employee-importance.cpp new file mode 100644 index 000000000..85c48ae24 --- /dev/null +++ b/C++/employee-importance.cpp @@ -0,0 +1,54 @@ +// Time: O(n) +// Space: O(h) + +/* +// Employee info +class Employee { +public: + // It's the unique ID of each node. + // unique id of this employee + int id; + // the importance value of this employee + int importance; + // the id of direct subordinates + vector subordinates; +}; +*/ +class Solution { +public: + int getImportance(vector employees, int id) { + return dfs(employees, id); + } + +private: + int dfs(const vector& employees, const int id) { + if (!employees[id - 1]) { + return 0; + } + auto result = employees[id - 1]->importance; + for (const auto& id : employees[id - 1]->subordinates) { + result += getImportance(employees, id); + } + return result; + } +}; + +// Time: O(n) +// Space: O(w), w is the max number of nodes in the levels of the tree +class Solution2 { +public: + int getImportance(vector employees, int id) { + auto result = 0; + queue q; + q.emplace(id); + while (!q.empty()) { + const auto curr = q.front(); q.pop(); + const auto& employee = employees[curr - 1]; + result += employee->importance; + for (const auto& id : employee->subordinates) { + q.emplace(id); + } + } + return result; + } +}; diff --git a/C++/encode-and-decode-strings.cpp b/C++/encode-and-decode-strings.cpp new file mode 100644 index 000000000..0722b0c5d --- /dev/null +++ b/C++/encode-and-decode-strings.cpp @@ -0,0 +1,42 @@ +// Time: O(n) +// Space: O(1) + +class Codec { +public: + + // Encodes a list of strings to a single string. + string encode(vector& strs) { + string s; + for (size_t i = 0; i < strs.size(); ++i) { + size_t len = strs[i].length(); + string tmp; + for (size_t i = 0, mask = 0xff; i < sizeof(size_t); ++i, mask <<= 8) { + tmp.push_back(len & mask); + } + reverse(tmp.begin(), tmp.end()); + s.append(tmp); + s.append(strs[i]); + } + + return s; + } + + // Decodes a single string to a list of strings. + vector decode(string s) { + vector strs; + size_t pos = 0; + + while (pos + sizeof(size_t) <= s.length()) { + size_t len = 0; + for (size_t i = 0; i < sizeof(size_t); ++i) { + len <<= 8; + len += static_cast(s[pos++]); + } + + strs.push_back(s.substr(pos, len)); + pos += len; + } + + return strs; + } +}; diff --git a/C++/encode-and-decode-tinyurl.cpp b/C++/encode-and-decode-tinyurl.cpp new file mode 100644 index 000000000..8a5cb1d12 --- /dev/null +++ b/C++/encode-and-decode-tinyurl.cpp @@ -0,0 +1,42 @@ +// Time: O(1) +// Space: O(n) + +class Solution { +public: + Solution() : gen_((random_device())()) { + } + + // Encodes a URL to a shortened URL. + string encode(string longUrl) { + string key = getRand(); + while (lookup_.count(key)) { + key = getRand(); + } + lookup_[key] = longUrl; + return "http://tinyurl.com/" + key; + } + + // Decodes a shortened URL to its original URL. + string decode(string shortUrl) { + return lookup_[shortUrl.substr(tiny_url.length())]; + } + +private: + string getRand() { + string random; + for (int i = 0; i < random_length; ++i) { + random += alphabet_[uniform_int_distribution{0, alphabet_.length() - 1}(gen_)]; + } + return random; + } + + const int random_length = 6; + const string tiny_url = "http://tinyurl.com/"; + const string alphabet_ = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + default_random_engine gen_; + unordered_map lookup_; +}; + +// Your Solution object will be instantiated and called as such: +// Solution solution; +// solution.decode(solution.encode(url)); diff --git a/C++/encode-string-with-shortest-length.cpp b/C++/encode-string-with-shortest-length.cpp new file mode 100644 index 000000000..44c312b7e --- /dev/null +++ b/C++/encode-string-with-shortest-length.cpp @@ -0,0 +1,35 @@ +// Time: O(n^3) on average +// Space: O(n^2) + +class Solution { +public: + string encode(string s) { + vector> dp(s.length(), vector(s.length())); + for (int len = 1; len <= s.length(); ++len) { + for (int i = 0; i + len - 1 < s.length(); ++i) { + int j = i + len - 1; + dp[i][j] = s.substr(i, len); + for (int k = i; k < j; ++k) { + if (dp[i][k].length() + dp[k + 1][j].length() < dp[i][j].length()) { + dp[i][j] = dp[i][k] + dp[k + 1][j]; + } + } + string encoded_string = encode_substr(dp, s, i, j); + if (encoded_string.length() < dp[i][j].length()) { + dp[i][j] = encoded_string; + } + } + } + return dp[0][s.length() - 1]; + } + +private: + string encode_substr(const vector>& dp, const string& s, int i, int j) { + string temp = s.substr(i, j - i + 1); + auto pos = (temp + temp).find(temp, 1); // O(n) on average + if (pos >= temp.length()) { + return temp; + } + return to_string(temp.length() / pos) + '[' + dp[i][i + pos - 1] + ']'; + } +}; diff --git a/C++/equal-tree-partition.cpp b/C++/equal-tree-partition.cpp new file mode 100644 index 000000000..2555131fd --- /dev/null +++ b/C++/equal-tree-partition.cpp @@ -0,0 +1,35 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool checkEqualTree(TreeNode* root) { + unordered_map lookup; + auto total = getSumHelper(root, &lookup); + if (total == 0) { + return lookup[total] > 1; + } + return total % 2 == 0 && lookup.count(total / 2); + } + +private: + int getSumHelper(TreeNode* node, unordered_map *lookup) { + if (!node) { + return 0; + } + int total = node->val + + getSumHelper(node->left, lookup) + + getSumHelper(node->right, lookup); + ++(*lookup)[total]; + return total; + } +}; diff --git a/C++/erect-the-fence.cpp b/C++/erect-the-fence.cpp new file mode 100644 index 000000000..e3dd4133a --- /dev/null +++ b/C++/erect-the-fence.cpp @@ -0,0 +1,56 @@ +// Time: O(nlogn) +// Space: O(n) + +/** + * Definition for a point. + * struct Point { + * int x; + * int y; + * Point() : x(0), y(0) {} + * Point(int a, int b) : x(a), y(b) {} + * }; + */ + +// Monotone Chain Algorithm +class Solution { +public: + vector outerTrees(vector& points) { + const auto orientation = [](const Point& p, const Point& q, const Point& r) { + return (q.y - p.y) * (r.x - q.x) - + (q.x - p.x) * (r.y - q.y); + }; + const auto cmp = [](const Point& p, const Point& q) { + return p.x == q.x ? p.y < q.y : p.x < q.x; + }; + const auto eq = [](const Point &p1, const Point &p2) { + return p1.x == p2.x && p1.y == p2.y; + }; + + vector hull; + sort(points.begin(), points.end(), cmp); + + for (int i = 0; i < points.size(); ++i) { + while (hull.size() >= 2 && + orientation(hull[hull.size() - 2], + hull[hull.size() - 1], + points[i]) > 0) { + hull.pop_back(); + } + hull.emplace_back(points[i]); + } + + for (int i = points.size() - 1; i >= 0; --i) { + while (hull.size() >= 2 && + orientation(hull[hull.size() - 2], + hull[hull.size() - 1], + points[i]) > 0) { + hull.pop_back(); + } + hull.emplace_back(points[i]); + } + + sort(hull.begin(), hull.end(), cmp); + hull.erase(unique(hull.begin(), hull.end(), eq), hull.end()); + return hull; + } +}; diff --git a/C++/evalRPN.cpp b/C++/evalRPN.cpp deleted file mode 100644 index 6f04b0e26..000000000 --- a/C++/evalRPN.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Time Space: O(n) -// Space Space: O(logn) - -class Solution { - public: - int evalRPN(vector &tokens) { - stack s; - for(auto tok : tokens) { - if(!is_operator(tok)) { - s.push(tok); - } - else { - int y = stoi(s.top()); - s.pop(); - int x = stoi(s.top()); - s.pop(); - if(tok[0] == '+') x += y; - else if (tok[0] == '-') x -= y; - else if (tok[0] == '*') x *= y; - else x /= y; - s.push(to_string(x)); - } - } - return stoi(s.top()); - } - private: - bool is_operator(const string &op) { - return op.length() == 1 && string("+-*/").find(op) != string::npos; - } -}; diff --git a/C++/evaluate-division.cpp b/C++/evaluate-division.cpp new file mode 100644 index 000000000..7db86be31 --- /dev/null +++ b/C++/evaluate-division.cpp @@ -0,0 +1,48 @@ +// Time: O(e + q * |V|!), |V| is the number of variables +// Space: O(e) + +class Solution { +public: + vector calcEquation(vector> equations, + vector& values, vector> query) { + + unordered_map> lookup; + for (int i = 0; i < values.size(); ++i) { + lookup[equations[i].first].emplace(equations[i].second, values[i]); + if (values[i] != 0) { + lookup[equations[i].second].emplace(equations[i].first, 1 / values[i]); + } + } + + vector result; + for (const auto& i : query) { + unordered_set visited; + const auto tmp = check(i.first, i.second, lookup, &visited); + if (tmp.first) { + result.emplace_back(tmp.second); + } else { + result.emplace_back(-1); + } + } + return result; + } + +private: + pair check(string up, string down, + unordered_map> &lookup, + unordered_set *visited) { + if (lookup[up].find(down) != lookup[up].end()) { + return {true, lookup[up][down]}; + } + for (const auto& q : lookup[up]) { + if (!visited->count(q.first)) { + visited->emplace(q.first); + const auto tmp = check(q.first, down, lookup, visited); + if (tmp.first) { + return {true, q.second * tmp.second}; + } + } + } + return {false, 0}; + } +}; diff --git a/C++/evaluate-reverse-polish-notation.cpp b/C++/evaluate-reverse-polish-notation.cpp new file mode 100644 index 000000000..6d1b33020 --- /dev/null +++ b/C++/evaluate-reverse-polish-notation.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int evalRPN(vector& tokens) { + if (tokens.empty()) { + return 0; + } + stack s; + for (const auto& tok : tokens) { + if (!is_operator(tok)) { + s.emplace(tok); + } else { + auto&& y = stoi(s.top()); + s.pop(); + auto&& x = stoi(s.top()); + s.pop(); + if (tok[0] == '+') { + x += y; + } else if (tok[0] == '-') { + x -= y; + } else if (tok[0] == '*') { + x *= y; + } else { + x /= y; + } + s.emplace(to_string(x)); + } + } + return stoi(s.top()); + } + +private: + bool is_operator(const string& op) { + return op.length() == 1 && string("+-*/").find(op) != string::npos; + } +}; diff --git a/C++/excel-sheet-column-number.cpp b/C++/excel-sheet-column-number.cpp new file mode 100644 index 000000000..a3b84c8cf --- /dev/null +++ b/C++/excel-sheet-column-number.cpp @@ -0,0 +1,14 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int titleToNumber(string s) { + int number = 0; + for (const auto& c : s) { + number *= 26; + number += c - 'A' + 1; + } + return number; + } +}; diff --git a/C++/excel-sheet-column-title.cpp b/C++/excel-sheet-column-title.cpp new file mode 100644 index 000000000..a3342a427 --- /dev/null +++ b/C++/excel-sheet-column-title.cpp @@ -0,0 +1,32 @@ +// Time: O(logn) +// Space: O(1) + +// Iterative solution. +class Solution { +public: + string convertToTitle(int n) { + string result; + int dvd{n}; + + while (dvd) { + result.push_back((dvd - 1) % 26 + 'A'); + dvd = (dvd - 1) / 26; + } + reverse(result.begin(), result.end()); + + return result; + } +}; + +// Time: O((logn)^2) +// Space: O(logn) +// Recursive solution. +class Solution2 { +public: + string convertToTitle(int n) { + if (n == 0) { + return ""; + } + return convertToTitle((n - 1) / 26) + static_cast((n - 1) % 26 + 'A'); + } +}; diff --git a/C++/exclusive-time-of-functions.cpp b/C++/exclusive-time-of-functions.cpp new file mode 100644 index 000000000..84329b6c4 --- /dev/null +++ b/C++/exclusive-time-of-functions.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector exclusiveTime(int n, vector& logs) { + vector result(n); + stack stk; + int prev = 0; + for (const auto& log : logs) { + vector tokens = split(log, ':'); + if (tokens[1] == "start") { + if (!stk.empty()) { + result[stk.top()] += stoi(tokens[2]) - prev; + } + stk.emplace(stoi(tokens[0])); + prev = stoi(tokens[2]); + } else { + result[stk.top()] += stoi(tokens[2]) - prev + 1; + stk.pop(); + prev = stoi(tokens[2]) + 1; + } + } + return result; + } + +private: + vector split(const string& s, const char delim) { + vector tokens; + stringstream ss(s); + string token; + while (getline(ss, token, delim)) { + tokens.emplace_back(token); + } + return tokens; + } +}; + diff --git a/C++/expression-add-operators.cpp b/C++/expression-add-operators.cpp new file mode 100644 index 000000000..71d9f46e0 --- /dev/null +++ b/C++/expression-add-operators.cpp @@ -0,0 +1,64 @@ +// Time: O(4^n) +// Space: O(n) + +class Solution { +public: + vector addOperators(string num, int target) { + vector result; + vector expr; + int val = 0; + string val_str; + for (int i = 0; i < num.length(); ++i) { + val = val * 10 + num[i] - '0'; + val_str.push_back(num[i]); + // Avoid overflow and "00...". + if (to_string(val) != val_str) { + break; + } + expr.emplace_back(val_str); + addOperatorsDFS(num, target, i + 1, 0, val, &expr, &result); + expr.pop_back(); + } + return result; + } + + void addOperatorsDFS(const string& num, const int& target, const int& pos, + const int& operand1, const int& operand2, + vector *expr, vector *result) { + if (pos == num.length() && operand1 + operand2 == target) { + result->emplace_back(join(*expr)); + } else { + int val = 0; + string val_str; + for (int i = pos; i < num.length(); ++i) { + val = val * 10 + num[i] - '0'; + val_str.push_back(num[i]); + // Avoid overflow and "00...". + if (to_string(val) != val_str) { + break; + } + + // Case '+': + expr->emplace_back("+" + val_str); + addOperatorsDFS(num, target, i + 1, operand1 + operand2, val, expr, result); + expr->pop_back(); + + // Case '-': + expr->emplace_back("-" + val_str); + addOperatorsDFS(num, target, i + 1, operand1 + operand2, -val, expr, result); + expr->pop_back(); + + // Case '*': + expr->emplace_back("*" + val_str); + addOperatorsDFS(num, target, i + 1, operand1, operand2 * val, expr, result); + expr->pop_back(); + } + } + } + + string join(const vector& expr) { + ostringstream stream; + copy(expr.cbegin(), expr.cend(), ostream_iterator(stream)); + return stream.str(); + } +}; diff --git a/C++/factor-combinations.cpp b/C++/factor-combinations.cpp new file mode 100644 index 000000000..a177f2aa1 --- /dev/null +++ b/C++/factor-combinations.cpp @@ -0,0 +1,26 @@ +// Time: O(nlogn) = logn * n^(1/2) * n^(1/4) * ... * 1 +// Space: O(logn) + +// DFS solution. +class Solution { + public: + vector> getFactors(int n) { + vector> result; + vector factors; + getResult(n, &result, &factors); + return result; + } + + void getResult(const int n, vector> *result, vector *factors) { + for (int i = factors->empty() ? 2 : factors->back(); i <= n / i; ++i) { + if (n % i == 0) { + factors->emplace_back(i); + factors->emplace_back(n / i); + result->emplace_back(*factors); + factors->pop_back(); + getResult(n / i, result, factors); + factors->pop_back(); + } + } + } + }; diff --git a/C++/factorial-trailing-zeroes.cpp b/C++/factorial-trailing-zeroes.cpp new file mode 100644 index 000000000..a9ea04b70 --- /dev/null +++ b/C++/factorial-trailing-zeroes.cpp @@ -0,0 +1,14 @@ +// Time: O(logn) = O(1) +// Space: O(1) + +class Solution { +public: + int trailingZeroes(int n) { + int number = 0; + while (n > 0) { + number += n / 5; + n /= 5; + } + return number; + } +}; diff --git a/C++/falling-squares.cpp b/C++/falling-squares.cpp new file mode 100644 index 000000000..0232da1da --- /dev/null +++ b/C++/falling-squares.cpp @@ -0,0 +1,204 @@ +// Time: O(nlogn) +// Space: O(n) + +// Segment Tree solution. +class Solution { +public: + vector fallingSquares(vector>& positions) { + set index; + for (const auto& position : positions) { + index.emplace(position.first); + index.emplace(position.first + position.second - 1); + } + SegmentTree tree(index.size()); + auto max_height = 0; + vector result; + for (const auto& position : positions) { + const auto L = distance(index.begin(), index.find(position.first)); + const auto R = distance(index.begin(), index.find(position.first + position.second - 1)); + const auto h = tree.query(L, R) + position.second; + tree.update(L, R, h); + max_height = max(max_height, h); + result.emplace_back(max_height); + } + return result; + } + +private: + class SegmentTree { + public: + SegmentTree(int N) + : N_(N), + tree_(2 * N), + lazy_(N) + { + H_ = 1; + while ((1 << H_) < N) { + ++H_; + } + } + + void update(int L, int R, int h) { + L += N_; R += N_; + int L0 = L, R0 = R; + while (L <= R) { + if ((L & 1) == 1) { + apply(L++, h); + } + if ((R & 1) == 0) { + apply(R--, h); + } + L >>= 1; R >>= 1; + } + pull(L0); pull(R0); + } + + int query(int L, int R) { + L += N_; R += N_; + auto result = 0; + push(L); push(R); + while (L <= R) { + if ((L & 1) == 1) { + result = max(result, tree_[L++]); + } + if ((R & 1) == 0) { + result = max(result, tree_[R--]); + } + L >>= 1; R >>= 1; + } + return result; + } + + private: + int N_, H_; + vector tree_, lazy_; + + void apply(int x, int val) { + tree_[x] = max(tree_[x], val); + if (x < N_) { + lazy_[x] = max(tree_[x], val); + } + } + + void pull(int x) { + while (x > 1) { + x >>= 1; + tree_[x] = max(tree_[x * 2], tree_[x * 2 + 1]); + tree_[x] = max(tree_[x], lazy_[x]); + } + } + + void push(int x) { + for (int h = H_; h > 0; --h) { + int y = x >> h; + if (lazy_[y] > 0) { + apply(y * 2, lazy_[y]); + apply(y * 2 + 1, lazy_[y]); + lazy_[y] = 0; + } + } + } + }; +}; + + +// Time: O(n * sqrt(n)) +// Space: O(n) +class Solution2 { +public: + vector fallingSquares(vector>& positions) { + set index; + for (const auto& position : positions) { + index.emplace(position.first); + index.emplace(position.first + position.second - 1); + } + const auto W = index.size(); + const auto B = static_cast(sqrt(W)); + vector heights(W); + vector blocks(B + 2), blocks_read(B + 2); + + auto max_height = 0; + vector result; + for (const auto& position : positions) { + const auto L = distance(index.begin(), index.find(position.first)); + const auto R = distance(index.begin(), index.find(position.first + position.second - 1)); + const auto h = query(B, L, R, heights, blocks, blocks_read) + position.second; + update(B, h, L, R, &heights, &blocks, &blocks_read); + max_height = max(max_height, h); + result.emplace_back(max_height); + } + return result; + } + +private: + int query(const int B, + int left, int right, + const vector& heights, + const vector& blocks, const vector& blocks_read) { + int result = 0; + while (left % B > 0 && left <= right) { + result = max(result, max(heights[left], blocks[left / B])); + result = max(result, blocks[left / B]); + ++left; + } + while (right % B != B - 1 && left <= right) { + result = max(result, max(heights[right], blocks[right / B])); + --right; + } + while (left <= right) { + result = max(result, max(blocks[left / B], blocks_read[left / B])); + left += B; + } + return result; + } + + void update(const int B, const int h, + int left, int right, + vector *heights, + vector *blocks, vector *blocks_read) { + while (left % B > 0 && left <= right) { + (*heights)[left] = max((*heights)[left], h); + (*blocks_read)[left / B] = max((*blocks_read)[left / B], h); + ++left; + } + while (right % B != B - 1 && left <= right) { + (*heights)[right] = max((*heights)[right], h); + (*blocks_read)[right / B] = max((*blocks_read)[right / B], h); + --right; + } + while (left <= right) { + (*blocks)[left / B] = max((*blocks)[left / B], h); + left += B; + } + } +}; + + +// Time: O(n^2) +// Space: O(n) +class Solution3 { +public: + vector fallingSquares(vector>& positions) { + vector heights(positions.size()); + for (int i = 0; i < positions.size(); ++i) { + int left_i, size_i; + tie(left_i, size_i) = positions[i]; + int right_i = left_i + size_i; + heights[i] += size_i; + for (int j = i + 1; j < positions.size(); ++j) { + int left_j, size_j; + tie(left_j, size_j) = positions[j]; + int right_j = left_j + size_j; + if (left_j < right_i and left_i < right_j) { // intersect + heights[j] = max(heights[j], heights[i]); + } + } + } + + vector result; + for (const auto& height : heights) { + result.emplace_back(result.empty() ? height : max(result.back(), height)); + } + return result; + } +}; diff --git a/C++/find-all-anagrams-in-a-string.cpp b/C++/find-all-anagrams-in-a-string.cpp new file mode 100644 index 000000000..2be245df7 --- /dev/null +++ b/C++/find-all-anagrams-in-a-string.cpp @@ -0,0 +1,28 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findAnagrams(string s, string p) { + vector result; + if (p.empty() || s.empty()) { + return result; + } + + vector cnts(26); + for (const auto& c : p) { + ++cnts[c - 'a']; + } + + for (int left = 0, right = 0; right < s.length(); ++right) { + --cnts[s[right] - 'a']; + while (left <= right && cnts[s[right] - 'a'] < 0) { + ++cnts[s[left++] - 'a']; + } + if (right - left + 1 == p.length()) { + result.emplace_back(left); + } + } + return result; + } +}; diff --git a/C++/find-all-duplicates-in-an-array.cpp b/C++/find-all-duplicates-in-an-array.cpp new file mode 100644 index 000000000..5cc2e8b93 --- /dev/null +++ b/C++/find-all-duplicates-in-an-array.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findDuplicates(vector& nums) { + vector result; + int i = 0; + while (i < nums.size()) { + if (nums[i] != nums[nums[i] - 1]) { + swap(nums[i], nums[nums[i] - 1]); + } else { + ++i; + } + } + for (i = 0; i < nums.size(); ++i) { + if (i != nums[i] - 1) { + result.emplace_back(nums[i]); + } + } + return result; + } +}; diff --git a/C++/find-all-numbers-disappeared-in-an-array.cpp b/C++/find-all-numbers-disappeared-in-an-array.cpp new file mode 100644 index 000000000..920f3420f --- /dev/null +++ b/C++/find-all-numbers-disappeared-in-an-array.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findDisappearedNumbers(vector& nums) { + for (int i = 0; i < nums.size(); ++i) { + if (nums[abs(nums[i]) - 1] > 0) { + nums[abs(nums[i]) - 1] *= -1; + } + } + + vector result; + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] > 0) { + result.emplace_back(i + 1); + } else { + nums[i] *= -1; + } + } + return result; + } +}; diff --git a/C++/find-bottom-left-tree-value.cpp b/C++/find-bottom-left-tree-value.cpp new file mode 100644 index 000000000..b30755d7b --- /dev/null +++ b/C++/find-bottom-left-tree-value.cpp @@ -0,0 +1,59 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +class Solution { +public: + int findBottomLeftValue(TreeNode* root) { + int result = 0, max_depth = 0; + findBottomLeftValueHelper(root, 0, &max_depth, &result); + return result; + } + +private: + void findBottomLeftValueHelper(TreeNode *root, int curr_depth, int *max_depth, int *bottom_left_value) { + if (!root) { + return; + } + if (!root->left && !root->right && + curr_depth + 1 > *max_depth) { + *max_depth = curr_depth + 1; + *bottom_left_value = root->val; + return; + } + + findBottomLeftValueHelper(root->left, curr_depth + 1, max_depth, bottom_left_value); + findBottomLeftValueHelper(root->right, curr_depth + 1, max_depth, bottom_left_value); + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + int findBottomLeftValue(TreeNode* root) { + queue q; + q.emplace(root); + TreeNode *node = nullptr; + while (!q.empty()) { + node = q.front(); + q.pop(); + if (node->right) { + q.emplace(node->right); + } + if (node->left) { + q.emplace(node->left); + } + } + return node->val; + } +}; diff --git a/C++/find-duplicate-file-in-system.cpp b/C++/find-duplicate-file-in-system.cpp new file mode 100644 index 000000000..fff191f24 --- /dev/null +++ b/C++/find-duplicate-file-in-system.cpp @@ -0,0 +1,28 @@ +// Time: O(n * l), l is the average length of file content +// Space: O(n * l) + +class Solution { +public: + vector> findDuplicate(vector& paths) { + unordered_map> files; + for (const auto& path : paths) { + stringstream ss(path); + string root; + string s; + getline(ss, root, ' '); + while (getline(ss, s, ' ')) { + auto fileName = root + '/' + s.substr(0, s.find('(')); + auto fileContent = s.substr(s.find('(') + 1, s.find(')') - s.find('(') - 1); + files[fileContent].emplace_back(fileName); + } + } + + vector> result; + for (const auto& file : files) { + if (file.second.size() > 1) { + result.emplace_back(file.second); + } + } + return result; + } +}; diff --git a/C++/find-duplicate-subtrees.cpp b/C++/find-duplicate-subtrees.cpp new file mode 100644 index 000000000..5b14ff2b4 --- /dev/null +++ b/C++/find-duplicate-subtrees.cpp @@ -0,0 +1,127 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +namespace std{ + namespace + { + + // Code from boost + // Reciprocal of the golden ratio helps spread entropy + // and handles duplicates. + // See Mike Seymour in magic-numbers-in-boosthash-combine: + // http://stackoverflow.com/questions/4948780 + + template + inline void hash_combine(std::size_t& seed, T const& v) + { + seed ^= std::hash()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + } + + // Recursive template code derived from Matthieu M. + template ::value - 1> + struct HashValueImpl + { + static void apply(size_t& seed, Tuple const& tuple) + { + HashValueImpl::apply(seed, tuple); + hash_combine(seed, std::get(tuple)); + } + }; + + template + struct HashValueImpl + { + static void apply(size_t& seed, Tuple const& tuple) + { + hash_combine(seed, std::get<0>(tuple)); + } + }; + } + + template + struct hash> + { + size_t + operator()(std::tuple const& tt) const + { + size_t seed = 0; + HashValueImpl >::apply(seed, tt); + return seed; + } + + }; +} + +class Solution { +public: + vector findDuplicateSubtrees(TreeNode* root) { + unordered_map> trees; + unordered_map, int> lookup; + getid(root, &lookup, &trees); + + vector result; + for (const auto& kvp : trees) { + if (kvp.second.size() > 1) { + result.emplace_back(kvp.second[0]); + } + } + return result; + } + +private: + int getid(TreeNode *root, + unordered_map, int> *lookup, + unordered_map> *trees) { + auto node_id = 0; + if (root) { + const auto& data = make_tuple(root->val, + getid(root->left, lookup, trees), + getid(root->right, lookup, trees)); + if (!lookup->count(data)) { + (*lookup)[data] = lookup->size() + 1; + } + node_id = (*lookup)[data]; + (*trees)[node_id].emplace_back(root); + } + return node_id; + } +}; + +// Time: O(n * h) +// Space: O(n * h) +class Solution2 { +public: + vector findDuplicateSubtrees(TreeNode* root) { + unordered_map lookup; + vector result; + postOrderTraversal(root, &lookup, &result); + return result; + } + +private: + string postOrderTraversal(TreeNode* node, unordered_map* lookup, vector *result) { + if (!node) { + return ""; + } + string s = "("; + s += postOrderTraversal(node->left, lookup, result); + s += to_string(node->val); + s += postOrderTraversal(node->right, lookup, result); + s += ")"; + if ((*lookup)[s] == 1) { + result->emplace_back(node); + } + ++(*lookup)[s]; + return s; + } +}; diff --git a/C++/find-k-closest-elements.cpp b/C++/find-k-closest-elements.cpp new file mode 100644 index 000000000..1b674d85a --- /dev/null +++ b/C++/find-k-closest-elements.cpp @@ -0,0 +1,14 @@ +// Time: O(logn + k) +// Space: O(1) + +class Solution { +public: + vector findClosestElements(vector& arr, int k, int x) { + auto i = distance(arr.begin(), lower_bound(arr.begin(), arr.end(), x)); + int left = i - 1, right = i; + while (k--) { + (right >= arr.size() || (left >= 0 && abs(arr[left] - x) <= abs(arr[right] - x) )) ? --left : ++right; + } + return vector(arr.begin() + left + 1, arr.begin() + right); + } +}; diff --git a/C++/find-k-pairs-with-smallest-sums.cpp b/C++/find-k-pairs-with-smallest-sums.cpp new file mode 100644 index 000000000..dbde1b312 --- /dev/null +++ b/C++/find-k-pairs-with-smallest-sums.cpp @@ -0,0 +1,37 @@ +// Time: O(k * log(min(n, m, k))), where n is the size of num1, and m is the size of num2. +// Space: O(min(n, m, k)) + +class Solution { +public: + vector> kSmallestPairs(vector& nums1, vector& nums2, int k) { + vector> pairs; + if (nums1.size() > nums2.size()) { + vector> tmp = kSmallestPairs(nums2, nums1, k); + for (const auto& pair : tmp) { + pairs.emplace_back(pair.second, pair.first); + } + return pairs; + } + + using P = pair>; + priority_queue, greater

> q; + auto push = [&nums1, &nums2, &q](int i, int j) { + if (i < nums1.size() && j < nums2.size()) { + q.emplace(nums1[i] + nums2[j], make_pair(i, j)); + } + }; + + push(0, 0); + while (!q.empty() && pairs.size() < k) { + auto tmp = q.top(); q.pop(); + int i, j; + tie(i, j) = tmp.second; + pairs.emplace_back(nums1[i], nums2[j]); + push(i, j + 1); + if (j == 0) { + push(i + 1, 0); // at most queue min(m, n) space. + } + } + return pairs; + } +}; diff --git a/C++/find-k-th-smallest-pair-distance.cpp b/C++/find-k-th-smallest-pair-distance.cpp new file mode 100644 index 000000000..72ca5a7a6 --- /dev/null +++ b/C++/find-k-th-smallest-pair-distance.cpp @@ -0,0 +1,32 @@ +// Time: O(nlogn + nlogw), n = len(nums), w = max(nums) - min(nums) +// Space: O(1) + +// Binary search with sliding window solution +class Solution { +public: + int smallestDistancePair(vector& nums, int k) { + sort(nums.begin(), nums.end()); + int left = 0, right = nums.back() - nums.front() + 1; + while (left < right) { + const auto mid = left + (right - left) / 2; + if (possible(mid, nums, k)) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } + +private: + bool possible(const int guess, const vector& nums, const int k) { + int count = 0, left = 0; + for (int right = 0; right < nums.size(); ++right) { + while ((nums[right] - nums[left]) > guess) { + ++left; + } + count += right - left; + } + return count >= k; + } +}; diff --git a/C++/find-largest-value-in-each-tree-row.cpp b/C++/find-largest-value-in-each-tree-row.cpp new file mode 100644 index 000000000..396ad8e3d --- /dev/null +++ b/C++/find-largest-value-in-each-tree-row.cpp @@ -0,0 +1,64 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +class Solution { +public: + vector largestValues(TreeNode* root) { + vector result; + largestValuesHelper(root, 0, &result); + return result; + } +private: + void largestValuesHelper(TreeNode* root, int depth, vector *result) { + if (!root) { + return; + } + if (depth == result->size()) { + result->emplace_back(root->val); + } else { + (*result)[depth] = max((*result)[depth], root->val); + } + largestValuesHelper(root->left, depth + 1, result); + largestValuesHelper(root->right, depth + 1, result); + } + }; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + vector largestValues(TreeNode* root) { + if (!root) { + return {}; + } + vector result; + vector curr, next; + curr.emplace_back(root); + while (!curr.empty()) { + int max_val = numeric_limits::min(); + next.clear(); + for (const auto& node : curr) { + max_val = max(max_val, node->val); + if (node->left) { + next.emplace_back(node->left); + } + if (node->right) { + next.emplace_back(node->right); + } + } + result.emplace_back(max_val); + swap(curr, next); + } + return result; + } +}; diff --git a/C++/find-leaves-of-binary-tree.cpp b/C++/find-leaves-of-binary-tree.cpp new file mode 100644 index 000000000..2d3e41ed6 --- /dev/null +++ b/C++/find-leaves-of-binary-tree.cpp @@ -0,0 +1,34 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector> findLeaves(TreeNode* root) { + vector> result; + findLeavesHelper(root, &result); + return result; + } + +private: + int findLeavesHelper(TreeNode *node, vector> *result) { + if (node == nullptr) { + return -1; + } + const int level = 1 + max(findLeavesHelper(node->left, result), + findLeavesHelper(node->right, result)); + if (result->size() < level + 1){ + result->emplace_back(); + } + (*result)[level].emplace_back(node->val); + return level; + } +}; diff --git a/C++/find-median-from-data-stream.cpp b/C++/find-median-from-data-stream.cpp new file mode 100644 index 000000000..1735e3596 --- /dev/null +++ b/C++/find-median-from-data-stream.cpp @@ -0,0 +1,81 @@ +// Time: O(nlogn) for total n addNums, O(logn) per addNum, O(1) per findMedian. +// Space: O(n), total space + +// Heap solution. +class MedianFinder { +public: + + // Adds a number into the data structure. + void addNum(int num) { + // Balance smaller half and larger half. + if (max_heap_.empty() || num > max_heap_.top()) { + min_heap_.emplace(num); + if (min_heap_.size() > max_heap_.size() + 1) { + max_heap_.emplace(min_heap_.top()); + min_heap_.pop(); + } + } else { + max_heap_.emplace(num); + if (max_heap_.size() > min_heap_.size()) { + min_heap_.emplace(max_heap_.top()); + max_heap_.pop(); + } + } + } + + // Returns the median of current data stream + double findMedian() { + return min_heap_.size() == max_heap_.size() ? + (max_heap_.top() + min_heap_.top()) / 2.0 : + min_heap_.top(); + + } + +private: + // min_heap_ stores the larger half seen so far. + priority_queue, greater> min_heap_; + // max_heap_ stores the smaller half seen so far. + priority_queue, less> max_heap_; +}; + +// BST solution. +class MedianFinder2 { +public: + + // Adds a number into the data structure. + void addNum(int num) { + // Balance smaller half and larger half. + if (max_bst_.empty() || num > *max_bst_.cbegin()) { + min_bst_.emplace(num); + if (min_bst_.size() > max_bst_.size() + 1) { + max_bst_.emplace(*min_bst_.cbegin()); + min_bst_.erase(min_bst_.cbegin()); + } + } else { + max_bst_.emplace(num); + if (max_bst_.size() > min_bst_.size()) { + min_bst_.emplace(*max_bst_.cbegin()); + max_bst_.erase(max_bst_.cbegin()); + } + } + } + + // Returns the median of current data stream + double findMedian() { + return min_bst_.size() == max_bst_.size() ? + (*max_bst_.cbegin() + *min_bst_.cbegin()) / 2.0 : + *min_bst_.cbegin(); + + } + +private: + // min_bst_ stores the larger half seen so far. + multiset> min_bst_; + // max_bst_ stores the smaller half seen so far. + multiset> max_bst_; +}; + +// Your MedianFinder object will be instantiated and called as such: +// MedianFinder mf; +// mf.addNum(1); +// mf.findMedian(); diff --git a/C++/find-minimum-in-rotated-sorted-array-ii.cpp b/C++/find-minimum-in-rotated-sorted-array-ii.cpp new file mode 100644 index 000000000..970ce0da1 --- /dev/null +++ b/C++/find-minimum-in-rotated-sorted-array-ii.cpp @@ -0,0 +1,23 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int findMin(vector& nums) { + int left = 0, right = nums.size() - 1; + + // Find min left s.t. nums[left] < nums[left']. + while (left < right && nums[left] >= nums[right]) { + int mid = left + (right - left) / 2; + if (nums[mid] == nums[left]) { + ++left; + } else if (nums[mid] < nums[left]) { + right = mid; + } else { + left = mid + 1; + } + } + + return nums[left]; + } +}; diff --git a/C++/find-minimum-in-rotated-sorted-array.cpp b/C++/find-minimum-in-rotated-sorted-array.cpp new file mode 100644 index 000000000..79e571a3a --- /dev/null +++ b/C++/find-minimum-in-rotated-sorted-array.cpp @@ -0,0 +1,21 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int findMin(vector& nums) { + int left = 0, right = nums.size() - 1; + + // Find min left s.t. nums[left] < nums[left']. + while (left < right && nums[left] >= nums[right]) { + int mid = left + (right - left) / 2; + if (nums[mid] < nums[left]) { + right = mid; + } else { + left = mid + 1; + } + } + + return nums[left]; + } +}; diff --git a/C++/find-mode-in-binary-search-tree.cpp b/C++/find-mode-in-binary-search-tree.cpp new file mode 100644 index 000000000..6f7961e69 --- /dev/null +++ b/C++/find-mode-in-binary-search-tree.cpp @@ -0,0 +1,51 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector findMode(TreeNode* root) { + if (!root) { + return {}; + } + + vector result; + TreeNode *prev = nullptr; + int cnt = 1, max_cnt = 0; + inorder(root, &prev, &cnt, &max_cnt, &result); + return result; + } + +private: + void inorder(TreeNode *root, TreeNode **prev, int *cnt, int *max_cnt, vector *result) { + if (root == nullptr) { + return; + } + + inorder(root->left, prev, cnt, max_cnt, result); + if (*prev) { + if (root->val == (*prev)->val) { + ++(*cnt); + } else { + *cnt = 1; + } + } + if (*cnt > *max_cnt) { + *max_cnt = *cnt; + result->clear(); + result->emplace_back(root->val); + } else if (*cnt == *max_cnt) { + result->emplace_back(root->val); + } + *prev = root; + inorder(root->right, prev, cnt, max_cnt, result); + } +}; diff --git a/C++/find-peak-element.cpp b/C++/find-peak-element.cpp new file mode 100644 index 000000000..466c5240d --- /dev/null +++ b/C++/find-peak-element.cpp @@ -0,0 +1,20 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int findPeakElement(vector& nums) { + int left = 0, right = nums.size() - 1; + + while (left < right) { + const auto mid = left + (right - left) / 2; + if (nums[mid] > nums[mid + 1]) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } +}; diff --git a/C++/find-permutation.cpp b/C++/find-permutation.cpp new file mode 100644 index 000000000..31c295061 --- /dev/null +++ b/C++/find-permutation.cpp @@ -0,0 +1,18 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findPermutation(string s) { + vector result; + for (int i = 0; i <= s.length(); ++i) { + if (i == s.length() || s[i] == 'I') { + const int k = result.size(); + for (int j = i + 1; j > k; --j) { + result.emplace_back(j); + } + } + } + return result; + } +}; diff --git a/C++/find-pivot-index.cpp b/C++/find-pivot-index.cpp new file mode 100644 index 000000000..7539acee5 --- /dev/null +++ b/C++/find-pivot-index.cpp @@ -0,0 +1,17 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int pivotIndex(vector& nums) { + const auto total = accumulate(nums.begin(), nums.end(), 0); + auto left_sum = 0; + for (int i = 0; i < nums.size(); ++i) { + if (left_sum == (total - left_sum - nums[i])) { + return i; + } + left_sum += nums[i]; + } + return -1; + } +}; diff --git a/C++/find-right-interval.cpp b/C++/find-right-interval.cpp new file mode 100644 index 000000000..9dfd70af0 --- /dev/null +++ b/C++/find-right-interval.cpp @@ -0,0 +1,31 @@ +// Time: O(nlogn) +// Space: O(n) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + vector findRightInterval(vector& intervals) { + map lookup; + vector result; + for (int i = 0; i < intervals.size(); ++i) { + lookup[intervals[i].start] = i; + } + for (const auto& interval : intervals) { + const auto it = lookup.lower_bound(interval.end); + if (it == lookup.end()) { + result.emplace_back(-1); + } else { + result.emplace_back(it->second); + } + } + return result; + } +}; diff --git a/C++/find-smallest-letter-greater-than-target.cpp b/C++/find-smallest-letter-greater-than-target.cpp new file mode 100644 index 000000000..2b1434be2 --- /dev/null +++ b/C++/find-smallest-letter-greater-than-target.cpp @@ -0,0 +1,10 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + char nextGreatestLetter(vector& letters, char target) { + const auto cit = upper_bound(letters.cbegin(), letters.cend(), target); + return cit != letters.cend() ? *cit : letters.front(); + } +}; diff --git a/C++/find-the-celebrity.cpp b/C++/find-the-celebrity.cpp new file mode 100644 index 000000000..ec96b517d --- /dev/null +++ b/C++/find-the-celebrity.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(1) + +// Forward declaration of the knows API. +bool knows(int a, int b); + +class Solution { +public: + int findCelebrity(int n) { + int candidate = 0; + // Find the candidate. + for (int i = 1; i < n; ++i) { + if (knows(candidate, i)) { + candidate = i; // All candidates < i are not celebrity candidates. + } + } + // Verify the candidate. + for (int i = 0; i < n; ++i) { + if (i != candidate && + (knows(candidate, i) || !knows(i, candidate))) { + return -1; + } + } + return candidate; + } +}; diff --git a/C++/find-the-closest-palindrome.cpp b/C++/find-the-closest-palindrome.cpp new file mode 100644 index 000000000..0e4f79f59 --- /dev/null +++ b/C++/find-the-closest-palindrome.cpp @@ -0,0 +1,28 @@ +// Time: O(l) +// Space: O(l) + +class Solution { +public: + string nearestPalindromic(string n) { + const auto l = n.size(); + unordered_set candidates; + candidates.emplace(static_cast(pow(10, l)) + 1); + candidates.emplace(static_cast(pow(10, l - 1)) - 1); + auto prefix = stol(n.substr(0, (l + 1) / 2)); + for (long long i = -1; i <= 1; ++i) { + auto p = to_string(prefix + i); + auto pp = p + string(p.rbegin() + (l % 2), p.rend()); + candidates.emplace(stol(pp)); + } + long long num = stol(n), closest_val = numeric_limits::max(); + candidates.erase(num); + for (const auto& val : candidates) { + if (abs(val - num) < abs(closest_val - num)) { + closest_val = val; + } else if (abs(val - num) == abs(closest_val - num)) { + closest_val = min(closest_val, val); + } + } + return to_string(closest_val); + } +}; diff --git a/C++/find-the-derangement-of-an-array.cpp b/C++/find-the-derangement-of-an-array.cpp new file mode 100644 index 000000000..2293e7719 --- /dev/null +++ b/C++/find-the-derangement-of-an-array.cpp @@ -0,0 +1,16 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findDerangement(int n) { + static const int M = 1000000007; + long long mul = 1, sum = 0; + for (int i = n; i >= 0; --i) { + sum = (sum + M + (i % 2 == 0 ? 1 : -1) * mul) % M; + mul = (mul * i) % M; + } + return static_cast(sum); + } +}; + diff --git a/C++/find-the-difference.cpp b/C++/find-the-difference.cpp new file mode 100644 index 000000000..bfa3a01ca --- /dev/null +++ b/C++/find-the-difference.cpp @@ -0,0 +1,10 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + char findTheDifference(string s, string t) { + return accumulate(s.cbegin(), s.cend(), 0, std::bit_xor()) ^ + accumulate(t.cbegin(), t.cend(), 0, std::bit_xor()); + } +}; diff --git a/C++/find-the-duplicate-number.cpp b/C++/find-the-duplicate-number.cpp new file mode 100644 index 000000000..958d5e0df --- /dev/null +++ b/C++/find-the-duplicate-number.cpp @@ -0,0 +1,76 @@ +// Time: O(n) +// Space: O(1) + +// Two pointers method, same as Linked List Cycle II. +class Solution { +public: + int findDuplicate(vector& nums) { + int slow = nums[0]; + int fast = nums[nums[0]]; + while (slow != fast) { + slow = nums[slow]; + fast = nums[nums[fast]]; + } + + fast = 0; + while (slow != fast) { + slow = nums[slow]; + fast = nums[fast]; + } + return slow; + } +}; + +// Time: O(nlogn) +// Space: O(1) +// Binary search method. +class Solution2 { +public: + int findDuplicate(vector& nums) { + int left = 1, right = nums.size(); + + while (left <= right) { + const int mid = left + (right - left) / 2; + // Get count of num <= mid. + int count = 0; + for (const auto& num : nums) { + if (num <= mid) { + ++count; + } + } + if (count > mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; + +// Time: O(n) +// Space: O(n) +class Solution3 { +public: + int findDuplicate(vector& nums) { + int duplicate = 0; + // Mark the value as visited by negative. + for (auto& num : nums) { + if (nums[abs(num) - 1] > 0) { + nums[abs(num) - 1] *= -1; + } else { + duplicate = abs(num); + break; + } + } + // Rollback the value. + for (auto& num : nums) { + if (nums[abs(num) - 1] < 0) { + nums[abs(num) - 1] *= -1; + } else { + break; + } + } + return duplicate; + } +}; diff --git a/C++/findMedianSortedArrays.cpp b/C++/findMedianSortedArrays.cpp deleted file mode 100644 index d48822f66..000000000 --- a/C++/findMedianSortedArrays.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// LeetCode, Median of Two Sorted Arrays -// Complexity: -// O(log(m+n)) -// O(log(m+n)) - -class Solution { -public: - double findMedianSortedArrays(int A[], int m, int B[], int n) { - int total = m + n; - if (total & 0x1) - return find_kth(A, m, B, n, total / 2 + 1); - else - return (find_kth(A, m, B, n, total / 2) - + find_kth(A, m, B, n, total / 2 + 1)) / 2.0; - } - -private: - static int find_kth(int A[], int m, int B[], int n, int k) { - //always assume that m is equal or smaller than n - if (m > n) return find_kth(B, n, A, m, k); - if (m == 0) return B[k - 1]; - if (k == 1) return min(A[0], B[0]); - - //divide k into two parts - int ia = min(k / 2, m), ib = k - ia; - if (A[ia - 1] < B[ib - 1]) - return find_kth(A + ia, m - ia, B, n, k - ia); - else if (A[ia - 1] > B[ib - 1]) - return find_kth(A, m, B + ib, n - ib, k - ib); - else - return A[ia - 1]; - } -}; \ No newline at end of file diff --git a/C++/findMinimumInRotatedSortedArray.cpp b/C++/findMinimumInRotatedSortedArray.cpp deleted file mode 100644 index 8fd41d8b8..000000000 --- a/C++/findMinimumInRotatedSortedArray.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// LeetCode, SFind Minimum in Rotated Sorted Array -// Complexity: -// O(logn) time -// O(1) space - -class Solution { -public: - int findMin(vector &num) { - int start = 0, end = num.size(); - - while (start < end) { - if (num[start] <= num[end - 1]) - return num[start]; - - int mid = start + (end - start)/2; - - if (num[mid] >= num[start]) { - start = mid + 1; - } else { - if (mid == end - 1) - return num[mid]; - else - end = mid + 1; - } - } - - return num[start]; - } -}; \ No newline at end of file diff --git a/C++/findSubstring.cpp b/C++/findSubstring.cpp deleted file mode 100644 index 749cc5378..000000000 --- a/C++/findSubstring.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Time Complexity: O((m - n * k) * n * k) ~ O(m * n * k), where m is string length, n is dict size, k is word length -// Space Complexity: O( n * k) -class Solution { - public: - vector findSubstring(string s, vector &dict) { - const size_t wordLength = dict.front().length(); - const size_t catLength = wordLength * dict.size(); - vector result; - - if(s.length() < catLength) return result; - - unordered_map wordCount; - - for(auto const & word : dict) ++wordCount[word]; - - for(auto i = begin(s); i <= prev(end(s), catLength); ++i) { - unordered_map unused(wordCount); - - for(auto j = i; j != next(i, catLength); j += wordLength) { - auto pos = unused.find(string(j, next(j, wordLength))); - - if(pos == unused.end()) break; - - if(--pos->second == 0) unused.erase(pos); - } - - if(unused.size() == 0) result.push_back(distance(begin(s), i)); - } - - return result; - } -}; diff --git a/C++/first-bad-version.cpp b/C++/first-bad-version.cpp new file mode 100644 index 000000000..6d143fef7 --- /dev/null +++ b/C++/first-bad-version.cpp @@ -0,0 +1,21 @@ +// Time: O(logn) +// Space: O(1) + +// Forward declaration of isBadVersion API. +bool isBadVersion(int version); + +class Solution { +public: + int firstBadVersion(int n) { + int left = 1, right = n; + while (left <= right) { + int mid = left + (right - left) / 2; + if (isBadVersion(mid)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; diff --git a/C++/first-missing-positive.cpp b/C++/first-missing-positive.cpp new file mode 100644 index 000000000..48112803e --- /dev/null +++ b/C++/first-missing-positive.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int firstMissingPositive(vector& nums) { + int i = 0; + bucketSort(&nums); + for (; i < nums.size() && nums[i] == i + 1; ++i); + return i + 1; + } + +private: + void bucketSort(vector *nums) { + int i = 0; + while (i < nums->size()) { + if ((*nums)[i] > 0 && (*nums)[i] <= nums->size() && + (*nums)[i] != (*nums)[(*nums)[i] - 1]) { + swap((*nums)[i], (*nums)[(*nums)[i] - 1]); + } else { + ++i; + } + } + } +}; diff --git a/C++/first-unique-character-in-a-string.cpp b/C++/first-unique-character-in-a-string.cpp new file mode 100644 index 000000000..7e06b6a11 --- /dev/null +++ b/C++/first-unique-character-in-a-string.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(n) + +// One-pass solution. +class Solution { +public: + int firstUniqChar(string s) { + using IT = list::iterator; + + list candidates; + unordered_map lookup; + for (int i = 0; i < s.length(); ++i) { + const auto c = s[i]; + if (lookup.count(c)) { + if (lookup[c] != candidates.end()) { + candidates.erase(lookup[c]); + } + lookup[c] = candidates.end(); + } else { + lookup[c] = candidates.emplace(candidates.end(), i); + } + } + return candidates.empty() ? -1 : candidates.front(); + } +}; diff --git a/C++/firstMissingPositive.cpp b/C++/firstMissingPositive.cpp deleted file mode 100644 index 2c82d651f..000000000 --- a/C++/firstMissingPositive.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int firstMissingPositive(int A[], int n) { - int i; - bucketSort(A, n); - for(i = 0; i < n && A[i] == i + 1; ++i); - return i + 1; - } - - private: - void bucketSort(int A[], int n) { - for(int i = 0; i < n; ++i) { - for (; A[i] != i + 1 && A[i] > 0 && A[i] <= n && A[i] != A[A[i] - 1];) { - swap(A[i], A[A[i] - 1]); - } - } - } -}; diff --git a/C++/fizz-buzz.cpp b/C++/fizz-buzz.cpp new file mode 100644 index 000000000..d7477648c --- /dev/null +++ b/C++/fizz-buzz.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector fizzBuzz(int n) { + vector result; + + for (int i = 1; i <= n; ++i) { + if (i % 15 == 0) { + result.emplace_back("FizzBuzz"); + } else if (i % 5 == 0) { + result.emplace_back("Buzz"); + } else if (i % 3 == 0) { + result.emplace_back("Fizz"); + } else { + result.emplace_back(to_string(i)); + } + } + + return result; + } +}; diff --git a/C++/flatten-2d-vector.cpp b/C++/flatten-2d-vector.cpp new file mode 100644 index 000000000..55c3780bb --- /dev/null +++ b/C++/flatten-2d-vector.cpp @@ -0,0 +1,38 @@ +// Time: O(1) +// Space: O(1) + +class Vector2D { +public: + Vector2D(vector>& vec2d) : vec(vec2d) { + x = vec.begin(); + if (x != vec.end()) { + y = x->begin(); + adjustNextIter(); + } + } + + int next() { + const auto ret = *y; + ++y; + adjustNextIter(); + return ret; + } + + bool hasNext() { + return x != vec.end() && y != x->end(); + } + + void adjustNextIter() { + while (x != vec.end() && y == x->end()) { + ++x; + if (x != vec.end()) { + y = x->begin(); + } + } + } + +private: + vector>& vec; + vector>::iterator x; + vector::iterator y; +}; diff --git a/C++/flatten-nested-list-iterator.cpp b/C++/flatten-nested-list-iterator.cpp new file mode 100644 index 000000000..951d80c3a --- /dev/null +++ b/C++/flatten-nested-list-iterator.cpp @@ -0,0 +1,96 @@ +// Time: O(n), n is the number of the integers. +// Space: O(h), h is the depth of the nested lists. + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * class NestedInteger { + * public: + * // Return true if this NestedInteger holds a single integer, rather than a nested list. + * bool isInteger() const; + * + * // Return the single integer that this NestedInteger holds, if it holds a single integer + * // The result is undefined if this NestedInteger holds a nested list + * int getInteger() const; + * + * // Return the nested list that this NestedInteger holds, if it holds a nested list + * // The result is undefined if this NestedInteger holds a single integer + * const vector &getList() const; + * }; + */ + +// Using stack and iterator. +class NestedIterator { +public: + using IT = vector::const_iterator; + NestedIterator(vector &nestedList) { + depth_.emplace(nestedList.cbegin(), nestedList.cend()); + } + + int next() { + return (depth_.top().first++)->getInteger(); + } + + bool hasNext() { + while (!depth_.empty()) { + auto& cur = depth_.top(); + if (cur.first == cur.second) { + depth_.pop(); + } else if (cur.first->isInteger()) { + return true; + } else { + auto& nestedList = cur.first->getList(); + ++cur.first; + depth_.emplace(nestedList.cbegin(), nestedList.cend()); + } + } + return false; + } + +private: + stack> depth_; +}; + +// Time: O(n) +// Space: O(n) +// Using stack. +class NestedIterator2 { +public: + NestedIterator2(vector &nestedList) { + for (int i = static_cast(nestedList.size()) - 1; i >= 0; --i) { + nodes_.emplace(&nestedList[i]); + } + } + + int next() { + const auto result = nodes_.top()->getInteger(); + nodes_.pop(); + return result; + } + + bool hasNext() { + while (!nodes_.empty()) { + auto *cur = nodes_.top(); + if (cur->isInteger()) { + return true; + } + nodes_.pop(); + auto& children = cur->getList(); + for (int i = static_cast(children.size()) - 1; i >= 0; --i) { + nodes_.emplace(&children[i]); + } + } + return false; + } + +private: + stack nodes_; +}; + + +/** + * Your NestedIterator object will be instantiated and called as such: + * NestedIterator i(nestedList); + * while (i.hasNext()) cout << i.next(); + */ + diff --git a/C++/flip-game-ii.cpp b/C++/flip-game-ii.cpp new file mode 100644 index 000000000..4c0bc5f01 --- /dev/null +++ b/C++/flip-game-ii.cpp @@ -0,0 +1,143 @@ +// Time: O(n + c^2), c is max length of consecutive '+' +// Space: O(c) + +// The best theory solution (DP, O(n + c^2)) could be seen here: +// https://leetcode.com/discuss/64344/theory-matters-from-backtracking-128ms-to-dp-0ms +class Solution { +public: + bool canWin(string s) { + replace(s.begin(), s.end(), '-', ' '); + istringstream in(s); + int g_final = 0; + vector g; // Sprague-Grundy function of 0 ~ maxlen, O(n) space + for (string t; in >> t; ) { // Split the string + int p = t.size(); + while (g.size() <= p) { // O(c) time + string x{t}; + int i = 0, j = g.size() - 2; + while (i <= j) { // The S-G value of all subgame states, O(c) time + // Theorem 2: g[game] = g[subgame1]^g[subgame2]^g[subgame3]...; + x[g[i++] ^ g[j--]] = '-'; + } + // Find first missing number. + g.emplace_back(x.find('+')); + } + g_final ^= g[p]; + } + return g_final; // Theorem 1: First player must win iff g(current_state) != 0 + } +}; + + +// Time: O(n + c^3 * 2^c * logc), n is length of string, c is count of "++" +// Space: O(c * 2^c) +// hash solution. +class Solution2 { +public: + struct multiset_hash { + std::size_t operator() (const multiset& set) const { + string set_string; + for (const auto& i : set) { + set_string.append(to_string(i) + " "); + } + return hash()(set_string); + } + }; + + bool canWin(string s) { + const int n = s.length(); + multiset consecutives; + for (int i = 0; i < n - 1; ++i) { // O(n) time + if (s[i] == '+') { + int c = 1; + for (; i < n - 1 && s[i + 1] == '+'; ++i, ++c); + if (c >= 2) { + consecutives.emplace(c); + } + } + } + return canWinHelper(consecutives); + } + +private: + bool canWinHelper(const multiset& consecutives) { // O(2^c) time + if (!lookup_.count(consecutives)) { + bool is_win = false; + for (auto it = consecutives.cbegin(); !is_win && it != consecutives.cend(); ++it) { // O(c) time + const int c = *it; + multiset next_consecutives(consecutives); + next_consecutives.erase(next_consecutives.find(c)); + for (int i = 0; !is_win && i < c - 1; ++i) { // O(clogc) time + if (i >= 2) { + next_consecutives.emplace(i); + } + if (c - 2 - i >= 2) { + next_consecutives.emplace(c - 2 - i); + } + is_win = !canWinHelper(next_consecutives); + if (i >= 2) { + next_consecutives.erase(next_consecutives.find(i)); + } + if (c - 2 - i >= 2) { + next_consecutives.erase(next_consecutives.find(c - 2 - i)); + } + lookup_[consecutives] = is_win; // O(c) time + } + } + } + return lookup_[consecutives]; + } + unordered_map, bool, multiset_hash> lookup_; +}; + + +// Time: O(n + c * n * 2^c), try all the possible game strings, +// and each string would have c choices to become the next string +// Space: O(n * 2^c), keep all the possible game strings +// hash solution. +class Solution3 { +public: + bool canWin(string s) { + if (!lookup_.count(s)) { + const int n = s.length(); + bool is_win = false; + for (int i = 0; !is_win && i < n - 1; ++i) { + if (s[i] == '+') { + for (; !is_win && i < n - 1 && s[i + 1] == '+'; ++i) { + s[i] = s[i + 1] = '-'; + is_win = !canWin(s); + s[i] = s[i + 1] = '+'; + lookup_[s] = is_win; + } + } + } + } + return lookup_[s]; + } +private: + unordered_map lookup_; +}; + + +// Time: O(n * c!), n is length of string, c is count of "++" +// Space: O(c), recursion would be called at most c in depth. +// Besides, no extra space in each depth for the modified string. +class Solution4 { +public: + bool canWin(string s) { + const int n = s.length(); + bool is_win = false; + for (int i = 0; !is_win && i < n - 1; ++i) { // O(n) time + if (s[i] == '+') { + for (; !is_win && i < n - 1 && s[i + 1] == '+'; ++i) { // O(c) time + s[i] = s[i + 1] = '-'; + // t(n, c) = c * t(n, c - 1) + n = ... = c! * t(n, 0) + n * c! * (1/0! + 1/1! + ... 1/c!) + // = n * c! + n * c! * O(e) = O(n * c!) + is_win = !canWin(s); + s[i] = s[i + 1] = '+'; + } + } + } + return is_win; + } +}; diff --git a/C++/flip-game.cpp b/C++/flip-game.cpp new file mode 100644 index 000000000..9d01c5804 --- /dev/null +++ b/C++/flip-game.cpp @@ -0,0 +1,20 @@ + // Time: O(c * n + n) = O(n * (c+1)), n is length of string, c is count of "++" + // Space: O(1), no extra space excluding the result which requires at most O(n^2) space + + class Solution { + public: + vector generatePossibleNextMoves(string s) { + vector res; + int n = s.length(); + for (int i = 0; i < n - 1; ++i) { // O(n) time + if (s[i] == '+') { + for (;i < n - 1 && s[i + 1] == '+'; ++i) { // O(c) time + s[i] = s[i + 1] = '-'; + res.emplace_back(s); // O(n) to copy a string + s[i] = s[i + 1] = '+'; + } + } + } + return res; + } + }; diff --git a/C++/flood-fill.cpp b/C++/flood-fill.cpp new file mode 100644 index 000000000..0d86958c5 --- /dev/null +++ b/C++/flood-fill.cpp @@ -0,0 +1,27 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + vector> floodFill(vector>& image, int sr, int sc, int newColor) { + int color = image[sr][sc]; + if (color == newColor) return image; + dfs(&image, sr, sc, newColor, color); + return image; + } + +private: + void dfs(vector> *image, int r, int c, int newColor, int color) { + static const vector> directions{{-1, 0}, { 1, 0}, + { 0, 1}, { 0, -1}}; + if (r < 0 || r >= image->size() || + c < 0 || c >= (*image)[0].size() || + (*image)[r][c] != color) { + return; + } + (*image)[r][c] = newColor; + for (const auto& d : directions) { + dfs(image, r + d.first, c + d.second, newColor, color); + } + } +}; diff --git a/C++/fourSum.cpp b/C++/fourSum.cpp deleted file mode 100644 index 0b62b1364..000000000 --- a/C++/fourSum.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(n^2) - -class Solution { - public: - vector > fourSum(vector &num, int target) { - vector> ans; - if (num.size() < 4) - return ans; - sort(num.begin(), num.end()); - unordered_multimap> cache; - - for (int i = 0; i + 1 < num.size(); ++i) - for (int j = i + 1; j < num.size(); ++j) - cache.insert(make_pair(num[i] + num[j], make_pair(i, j))); - - for (auto i = cache.begin(); i != cache.end(); ++i) { - int x = target - i->first; - auto range = cache.equal_range(x); - for (auto j = range.first; j != range.second; ++j) { - auto a = i->second.first; - auto b = i->second.second; - auto c = j->second.first; - auto d = j->second.second; - if (b < c) { - ans.push_back({ num[a], num[b], num[c], num[d] }); - } - } - } - sort(ans.begin(), ans.end()); - ans.erase(unique(ans.begin(), ans.end()), ans.end()); - return ans; - } -}; diff --git a/C++/fraction-addition-and-subtraction.cpp b/C++/fraction-addition-and-subtraction.cpp new file mode 100644 index 000000000..3c1bb0230 --- /dev/null +++ b/C++/fraction-addition-and-subtraction.cpp @@ -0,0 +1,19 @@ +// Time: O(nlogx), x is the max denominator +// Space: O(n) + +class Solution { +public: + string fractionAddition(string expression) { + istringstream iss(expression); + int A = 0, B = 1, a, b; + char _; + while (iss >> a >> _ >> b) { + A = A * b + a * B; + B *= b; + auto g = abs(__gcd(A, B)); + A /= g; + B /= g; + } + return to_string(A) + '/' + to_string(B); + } +}; diff --git a/C++/fraction-to-recurring-decimal.cpp b/C++/fraction-to-recurring-decimal.cpp new file mode 100644 index 000000000..f4f2f6171 --- /dev/null +++ b/C++/fraction-to-recurring-decimal.cpp @@ -0,0 +1,34 @@ +// Time: O(logn), where logn is the length of result strings +// Space: O(1) + +class Solution { +public: + string fractionToDecimal(int numerator, int denominator) { + string result; + if ((numerator ^ denominator) >> 31 && numerator != 0) { + result = "-"; + } + + auto dvd = llabs(numerator); + auto dvs = llabs(denominator); + result += to_string(dvd / dvs); + dvd %= dvs; + if (dvd > 0) { + result += "."; + } + + unordered_map lookup; + while (dvd && !lookup.count(dvd)) { + lookup[dvd] = result.length(); + dvd *= 10; + result += to_string(dvd / dvs); + dvd %= dvs; + } + + if (lookup.count(dvd)) { + result.insert(lookup[dvd], "("); + result.push_back(')'); + } + return result; + } +}; diff --git a/C++/freedom-trail.cpp b/C++/freedom-trail.cpp new file mode 100644 index 000000000..8387cee40 --- /dev/null +++ b/C++/freedom-trail.cpp @@ -0,0 +1,26 @@ +// Time: O(k) ~ O(k * r^2) +// Space: O(r) + +class Solution { +public: + int findRotateSteps(string ring, string key) { + unordered_map> lookup; + for (int i = 0; i < ring.size(); ++i) { + lookup[ring[i]].emplace_back(i); + } + + vector> dp(2, vector (ring.size())); + for (int i = 1; i <= key.size(); ++i) { + fill(dp[i % 2].begin(), dp[i % 2].end(), numeric_limits::max()); + for (const auto& j : lookup[key[i - 1]]) { + for (const auto& k : (i > 1 ? lookup[key[i - 2]] : vector(1))) { + int min_dist = min((k + ring.size() - j) % ring.size(), + (j + ring.size() - k) % ring.size()) + + dp[(i - 1) % 2][k]; + dp[i % 2][j] = min(dp[i % 2][j], min_dist); + } + } + } + return *min_element(dp[key.size() % 2].begin(), dp[key.size() % 2].end()) + key.size(); + } +}; diff --git a/C++/friend-circles.cpp b/C++/friend-circles.cpp new file mode 100644 index 000000000..3a58b0c26 --- /dev/null +++ b/C++/friend-circles.cpp @@ -0,0 +1,48 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + int findCircleNum(vector>& M) { + UnionFind circles(M.size()); + for (int i = 0; i < M.size(); ++i) { + for (int j = 0; j < M[i].size(); ++j) { + if (M[i][j] && i != j) { + circles.union_set(i, j); + } + } + } + return circles.size(); + } + +private: + class UnionFind { + public: + UnionFind(const int n) : set_(n), count_(n) { + iota(set_.begin(), set_.end(), 0); + } + + int find_set(const int x) { + if (set_[x] != x) { + set_[x] = find_set(set_[x]); // Path compression. + } + return set_[x]; + } + + void union_set(const int x, const int y) { + int x_root = find_set(x), y_root = find_set(y); + if (x_root != y_root) { + set_[min(x_root, y_root)] = max(x_root, y_root); + --count_; + } + } + + int size() const { + return count_; + } + + private: + vector set_; + int count_; + }; +}; diff --git a/C++/frog-jump.cpp b/C++/frog-jump.cpp new file mode 100644 index 000000000..e9dcb774a --- /dev/null +++ b/C++/frog-jump.cpp @@ -0,0 +1,29 @@ +// Time: O(n) ~ O(n^2) +// Space: O(n) + +class Solution { +public: + bool canCross(vector& stones) { + if (stones[1] != 1) { + return false; + } + + unordered_map> last_jump_units; + for (const auto& s: stones) { + last_jump_units.emplace(s, {unordered_set()}); + } + last_jump_units[1].emplace(1); + + for (int i = 0; i + 1 < stones.size(); ++i) { + for (const auto& j : last_jump_units[stones[i]]) { + for (const auto& k : {j - 1, j, j + 1}) { + if (k > 0 && last_jump_units.count(stones[i] + k)) { + last_jump_units[stones[i] + k].emplace(k); + } + } + } + } + + return !last_jump_units[stones.back()].empty(); + } +}; diff --git a/C++/game-of-life.cpp b/C++/game-of-life.cpp new file mode 100644 index 000000000..df22a3591 --- /dev/null +++ b/C++/game-of-life.cpp @@ -0,0 +1,33 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + void gameOfLife(vector>& board) { + const int m = board.size(), n = m ? board[0].size() : 0; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + int count = 0; + // Count live cells in 3x3 block. + for (int I = max(i - 1, 0); I < min(i + 2, m); ++I) { + for (int J = max(j - 1, 0); J < min(j + 2, n); ++J) { + count += board[I][J] & 1; + } + } + // if (count == 4 && board[i][j]) means: + // Any live cell with three live neighbors lives. + // if (count == 3) means: + // Any live cell with two live neighbors. + // Any dead cell with exactly three live neighbors lives. + if ((count == 4 && board[i][j]) || count == 3) { + board[i][j] |= 2; // Mark as live. + } + } + } + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + board[i][j] >>= 1; // Update to the next state. + } + } + } +}; diff --git a/C++/generalized-abbreviation.cpp b/C++/generalized-abbreviation.cpp new file mode 100644 index 000000000..afb3f9335 --- /dev/null +++ b/C++/generalized-abbreviation.cpp @@ -0,0 +1,29 @@ +// Time: O(n * 2^n) +// Space: O(n) + +class Solution { +public: + vector generateAbbreviations(string word) { + vector res; + string cur; + generateAbbreviationsHelper(word, 0, &cur, &res); + return res; + } + + void generateAbbreviationsHelper(const string& word, int i, string *cur, vector *res) { + if (i == word.length()) { + res->emplace_back(*cur); + return; + } + cur->push_back(word[i]); + generateAbbreviationsHelper(word, i + 1, cur, res); + cur->pop_back(); + if (cur->empty() || not isdigit(cur->back())) { + for (int l = 1; i + l <= word.length(); ++l) { + cur->append(to_string(l)); + generateAbbreviationsHelper(word, i + l, cur, res); + cur->resize(cur->length() - to_string(l).length()); + } + } + } +}; diff --git a/C++/generateMatrix.cpp b/C++/generateMatrix.cpp deleted file mode 100644 index 9ef1713f0..000000000 --- a/C++/generateMatrix.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(n^2) - -class Solution { - public: - vector > generateMatrix(int n) { - vector > v(n, vector(n, 0)); - enum Action {RIGHT, DOWN, LEFT, UP}; - Action action = RIGHT; - for(int i = 0, j = 0, cnt = 0, total = n * n; cnt < total;) { - v[i][j] = ++cnt; - - switch(action) { - case RIGHT: - if(j + 1 < n && v[i][j + 1] == 0) ++j; - else action = DOWN, ++i; - break; - case DOWN: - if(i + 1 < n && v[i + 1][j] == 0) ++i; - else action = LEFT, --j; - break; - case LEFT: - if(j - 1 >= 0 && v[i][j - 1] == 0) --j; - else action = UP, --i; - break; - case UP: - if(i - 1 >= 0 && v[i - 1][j] == 0) --i; - else action = RIGHT, ++j; - break; - default: - break; - } - } - return v; - } -}; diff --git a/C++/generateTrees.cpp b/C++/generateTrees.cpp deleted file mode 100644 index 00c304e8b..000000000 --- a/C++/generateTrees.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Time Complexity: O( (2n, n) / n ) ~= O( 4^n / n^(3/2) ) -// Space Complexity: O( (2n, n) ) ~= O( 4^n / n^(1/2) ) - -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { - public: - vector generateTrees(int n) { - return generate(1, n); - } - private: - vector generate(int begin, int end) { - vector subTree; - if(begin > end) { - subTree.push_back(NULL); - } - - for(int k = begin; k <= end; ++k) { - vector leftSubTree = generate(begin, k - 1); - vector rightSubTree = generate(k + 1, end); - - for(auto i : leftSubTree) { - for(auto j : rightSubTree) { - TreeNode *node = new TreeNode(k); - node->left = i; - node->right = j; - subTree.push_back(node); - } - } - } - - return subTree; - } -}; diff --git a/C++/getPermutation.cpp b/C++/getPermutation.cpp deleted file mode 100644 index 66f6b30f0..000000000 --- a/C++/getPermutation.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(n) - -class Solution { - public: - string getPermutation(int n, int k) { - string s(n, '0'); - - for(int i = 0; i < n; ++i) { - s[i] += i + 1; - } - - return kth_permutation(s, k); - } - - private: - int factorial(int n) { - int sum = 1; - for(int i = n; i >= 1; --i) { - sum *= i; - } - return sum; - } - - // Cantor Encoding - template - Sequence kth_permutation(const Sequence &seq, int k) { - const int n = seq.size(); - Sequence ans; - Sequence S(seq); - int base = factorial(n - 1); - --k; - - for(int i = n - 1; i > 0; k %= base, base /= i, --i) { - auto a = next(S.begin(), k / base); - ans.push_back(*a); - S.erase(a); - } - - ans.push_back(S[0]); - - return ans; - } -}; diff --git a/C++/graph-valid-tree.cpp b/C++/graph-valid-tree.cpp new file mode 100644 index 000000000..983f6ecfa --- /dev/null +++ b/C++/graph-valid-tree.cpp @@ -0,0 +1,89 @@ +// Time: O(|V| + |E|) +// Space: O(|V| + |E|) + +// Same complexity, but faster version. +class Solution { +public: + struct node { + int parent = -1; + vectorneighbors; + }; + + bool validTree(int n, vector>& edges) { + if (edges.size() != n - 1) { + return false; + } else if (n == 1) { + return true; + } + + unordered_map nodes; + for (const auto& edge : edges) { + nodes[edge.first].neighbors.emplace_back(edge.second); + nodes[edge.second].neighbors.emplace_back(edge.first); + } + + if (nodes.size() != n) { + return false; + } + + unordered_set visited; + queue q; + q.emplace(0); + while (!q.empty()) { + const int i = q.front(); + q.pop(); + visited.emplace(i); + for (const auto& node : nodes[i].neighbors) { + if (node != nodes[i].parent) { + if (visited.find(node) != visited.end()) { + return false; + } else { + visited.emplace(node); + nodes[node].parent = i; + q.emplace(node); + } + } + } + } + return visited.size() == n; + } +}; + +// Time: O(|V| + |E|) +// Space: O(|V| + |E|) +class Solution2 { +public: + struct node { + int parent = -1; + vectorneighbors; + }; + + bool validTree(int n, vector>& edges) { + unordered_map nodes; + for (const auto& edge : edges) { + nodes[edge.first].neighbors.emplace_back(edge.second); + nodes[edge.second].neighbors.emplace_back(edge.first); + } + + unordered_set visited; + queue q; + q.emplace(0); + while (!q.empty()) { + const int i = q.front(); + q.pop(); + visited.emplace(i); + for (const auto& node : nodes[i].neighbors) { + if (node != nodes[i].parent) { + if (visited.find(node) != visited.end()) { + return false; + } else { + visited.emplace(node); + nodes[node].parent = i; + q.emplace(node); + } + } + } + } + return visited.size() == n; + } +}; diff --git a/C++/gray-code.cpp b/C++/gray-code.cpp new file mode 100644 index 000000000..e88269a02 --- /dev/null +++ b/C++/gray-code.cpp @@ -0,0 +1,30 @@ +// Time: (2^n) +// Space: O(1) + +class Solution { +public: + vector grayCode(int n) { + vector result = {0}; + for (int i = 0; i < n; ++i) { + for (int j = result.size() - 1; j >= 0; --j) { + result.emplace_back(1 << i | result[j]); + } + } + return result; + } +}; + +// Time: (2^n) +// Space: O(1) +// Proof of closed form formula could be found here: +// http://math.stackexchange.com/questions/425894/proof-of-closed-form-formula-to-convert-a-binary-number-to-its-gray-code +class Solution2 { +public: + vector grayCode(int n) { + vector result; + for (int i = 0; i < 1 << n; ++i) { + result.emplace_back(i >> 1 ^ i); + } + return result; + } +}; diff --git a/C++/group-shifted-strings.cpp b/C++/group-shifted-strings.cpp new file mode 100644 index 000000000..47dd9e7e1 --- /dev/null +++ b/C++/group-shifted-strings.cpp @@ -0,0 +1,31 @@ +// Time: O(nlogn) +// Space: O(n) + +class Solution { +public: + vector> groupStrings(vector& strings) { + unordered_map> groups; + for (const auto& str : strings) { // Grouping. + groups[hashStr(str)].insert(str); + } + + vector> result; + for (const auto& kvp : groups) { + vector group; + for (auto& str : kvp.second) { // Sorted in a group. + group.emplace_back(move(str)); + } + result.emplace_back(move(group)); + } + + return result; + } + + string hashStr(string str) { + const char base = str[0]; + for (auto& c : str) { + c = 'a' + ((c - base) >= 0 ? c - base : c - base + 26); + } + return str; + } +}; diff --git a/C++/guess-number-higher-or-lower-ii.cpp b/C++/guess-number-higher-or-lower-ii.cpp new file mode 100644 index 000000000..972e05964 --- /dev/null +++ b/C++/guess-number-higher-or-lower-ii.cpp @@ -0,0 +1,18 @@ +// Time: O(n^2) +// Space: O(n^2) + +class Solution { +public: + int getMoneyAmount(int n) { + vector> pay(n + 1, vector(n)); + for (int i = n - 1; i >= 0; --i) { + for (int j = i + 1; j < n; ++j) { + pay[i][j] = numeric_limits::max(); + for (int k = i; k <= j; ++k) { + pay[i][j] = min(pay[i][j], k + 1 + max(pay[i][k - 1], pay[k + 1][j])); + } + } + } + return pay[0][n - 1]; + } +}; diff --git a/C++/guess-number-higher-or-lower.cpp b/C++/guess-number-higher-or-lower.cpp new file mode 100644 index 000000000..8e41a9ba7 --- /dev/null +++ b/C++/guess-number-higher-or-lower.cpp @@ -0,0 +1,23 @@ +// Time: O(logn) +// Space: O(1) + +// Forward declaration of guess API. +// @param num, your guess +// @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 +int guess(int num); + +class Solution { +public: + int guessNumber(int n) { + int left = 1, right = n; + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (guess(mid) <= 0) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; diff --git a/C++/h-index-ii.cpp b/C++/h-index-ii.cpp new file mode 100644 index 000000000..c7c7cc9f2 --- /dev/null +++ b/C++/h-index-ii.cpp @@ -0,0 +1,20 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int hIndex(vector& citations) { + const int n = citations.size(); + int left = 0; + int right = n - 1; + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (citations[mid] >= n - mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return n - left; + } +}; diff --git a/C++/h-index.cpp b/C++/h-index.cpp new file mode 100644 index 000000000..2f6d86c42 --- /dev/null +++ b/C++/h-index.cpp @@ -0,0 +1,46 @@ +// Time: O(n) +// Space: O(n) + +// Counting sort. +class Solution { +public: + int hIndex(vector& citations) { + const auto n = citations.size(); + vector count(n + 1, 0); + for (const auto& x : citations) { + // Put all x >= n in the same bucket. + if (x >= n) { + ++count[n]; + } else { + ++count[x]; + } + } + + int h = 0; + for (int i = n; i >= 0; --i) { + h += count[i]; + if (h >= i) { + return i; + } + } + return h; + } +}; + +// Time: O(nlogn) +// Space: O(1) +class Solution2 { +public: + int hIndex(vector& citations) { + sort(citations.begin(), citations.end(), greater()); + int h = 0; + for (const auto& x : citations) { + if (x >= h + 1) { + ++h; + } else { + break; + } + } + return h; + } +}; diff --git a/C++/hamming-distance.cpp b/C++/hamming-distance.cpp new file mode 100644 index 000000000..32424d864 --- /dev/null +++ b/C++/hamming-distance.cpp @@ -0,0 +1,13 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int hammingDistance(int x, int y) { + int distance = 0; + for (int z = x ^ y; z; z &= z - 1) { + ++distance; + } + return distance; + } +}; diff --git a/C++/happy-number.cpp b/C++/happy-number.cpp new file mode 100644 index 000000000..b251abeb6 --- /dev/null +++ b/C++/happy-number.cpp @@ -0,0 +1,23 @@ +// Time: O(k), where k is the steps to be happy number +// Space: O(k) + +class Solution { +public: + bool isHappy(int n) { + unordered_set visited; + while (n != 1 && !visited.count(n)) { + visited.emplace(n); + n = nextNumber(n); + } + return n == 1; + } + + int nextNumber(int n) { + int sum = 0; + while (n) { + sum += pow(n % 10, 2); + n /= 10; + } + return sum; + } +}; diff --git a/C++/hasCycle.cpp b/C++/hasCycle.cpp deleted file mode 100644 index 4b8df99f5..000000000 --- a/C++/hasCycle.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - bool hasCycle(ListNode *head) { - ListNode *slow = head, *fast = head; - - while(fast && fast->next) { - slow = slow->next; - fast = fast->next->next; - - if(slow == fast) - return true; - } - - return false; - } -}; diff --git a/C++/heaters.cpp b/C++/heaters.cpp new file mode 100644 index 000000000..894800bea --- /dev/null +++ b/C++/heaters.cpp @@ -0,0 +1,23 @@ +// Time: O((m + n) * logn), m is the number of the houses, n is the number of the heaters. +// Space: O(1) + +class Solution { +public: + int findRadius(vector& houses, vector& heaters) { + sort(heaters.begin(), heaters.end()); + int min_radius = 0; + for (const auto& house : houses) { + auto equal_or_larger = lower_bound(heaters.cbegin(), heaters.cend(), house); + auto curr_radius = numeric_limits::max(); + if (equal_or_larger != heaters.cend()) { + curr_radius = *equal_or_larger - house; + } + if (equal_or_larger != heaters.cbegin()) { + auto smaller = prev(equal_or_larger); + curr_radius = min(curr_radius, house - *smaller); + } + min_radius = max(min_radius, curr_radius); + } + return min_radius; + } +}; diff --git a/C++/house-robber-ii.cpp b/C++/house-robber-ii.cpp new file mode 100644 index 000000000..5bb26728c --- /dev/null +++ b/C++/house-robber-ii.cpp @@ -0,0 +1,27 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int rob(vector& nums) { + if (nums.size() == 0) { + return 0; + } + if (nums.size() == 1) { + return nums[0]; + } + + return max(robRange(nums, 0, nums.size() - 1), // Include the first one of nums without the last one. + robRange(nums, 1, nums.size())); // Include the last one of nums without the first one. + } + + int robRange(vector& nums, int start, int end) { + int num_i = nums[start], num_i_1 = 0, num_i_2 = 0; + for (int i = start + 1; i < end; ++i) { + num_i_2 = num_i_1; + num_i_1 = num_i; + num_i = max(nums[i] + num_i_2, num_i_1); + } + return num_i; + } +}; diff --git a/C++/house-robber-iii.cpp b/C++/house-robber-iii.cpp new file mode 100644 index 000000000..2e4746f21 --- /dev/null +++ b/C++/house-robber-iii.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int rob(TreeNode* root) { + auto res = robHelper(root); + return max(res.first, res.second); + } + +private: + pair robHelper(TreeNode* root) { + if (!root) { + return {0, 0}; + } + auto left = robHelper(root->left); + auto right = robHelper(root->right); + return {root->val + left.second + right.second, + max(left.first, left.second) + max(right.first, right.second)}; + } +}; diff --git a/C++/image-smoother.cpp b/C++/image-smoother.cpp new file mode 100644 index 000000000..57feb4300 --- /dev/null +++ b/C++/image-smoother.cpp @@ -0,0 +1,35 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + vector> imageSmoother(vector>& M) { + const auto m = M.size(), n = M[0].size(); + vector> result(M); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + result[i][j] = getGray(M, i, j); + } + } + return result; + } + +private: + int getGray(const vector>& M, int i, int j) { + const auto& m = M.size(), n = M[0].size(); + static const vector> directions = { {-1, -1}, {0, -1}, {1, -1}, + {-1, 0}, {0, 0}, {1, 0}, + {-1, 1}, {0, 1}, {1, 1} }; + double total = 0.0; + int count = 0; + for (const auto& direction : directions) { + const auto& ii = i + direction.first; + const auto& jj = j + direction.second; + if (0 <= ii && ii < m && 0 <= jj && jj < n) { + total += M[ii][jj]; + ++count; + } + } + return static_cast(total / count); + } +}; diff --git a/C++/implement-magic-dictionary.cpp b/C++/implement-magic-dictionary.cpp new file mode 100644 index 000000000..11345c08d --- /dev/null +++ b/C++/implement-magic-dictionary.cpp @@ -0,0 +1,82 @@ +// Time: O(n), n is the length of the word +// Space: O(d) + +class MagicDictionary { +public: + /** Initialize your data structure here. */ + MagicDictionary() { + + } + + /** Build a dictionary through a list of words */ + void buildDict(vector dict) { + string result; + for (const auto& s : dict) { + trie_.Insert(s); + } + } + + /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */ + bool search(string word) { + return find(word, &trie_, 0, true); + } + +private: + struct TrieNode { + bool isString = false; + unordered_map leaves; + + void Insert(const string& s) { + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + p->leaves[c] = new TrieNode; + } + p = p->leaves[c]; + } + p->isString = true; + } + + ~TrieNode() { + for (auto& kv : leaves) { + if (kv.second) { + delete kv.second; + } + } + } + }; + + bool find(const string& word, TrieNode *curr, int i, bool mistakeAllowed) { + if (i == word.length()) { + return curr->isString && !mistakeAllowed; + } + + if (!curr->leaves.count(word[i])) { + return mistakeAllowed ? + any_of(curr->leaves.begin(), curr->leaves.end(), + [&](const pair& kvp) { + return find(word, kvp.second, i + 1, false); + }) : + false; + } + + if (mistakeAllowed) { + return find(word, curr->leaves[word[i]], i + 1, true) || + any_of(curr->leaves.begin(), curr->leaves.end(), + [&](const pair& kvp) { + return kvp.first != word[i] && find(word, kvp.second, i + 1, false); + }); + } + return find(word, curr->leaves[word[i]], i + 1, false); + } + + TrieNode trie_; +}; + +/** + * Your MagicDictionary object will be instantiated and called as such: + * MagicDictionary obj = new MagicDictionary(); + * obj.buildDict(dict); + * bool param_2 = obj.search(word); + */ + diff --git a/C++/implement-queue-using-stacks.cpp b/C++/implement-queue-using-stacks.cpp new file mode 100644 index 000000000..0392d858c --- /dev/null +++ b/C++/implement-queue-using-stacks.cpp @@ -0,0 +1,39 @@ +// Time: O(1), amortized +// Space: O(n) + +class Queue { +public: + // Push element x to the back of queue. + void push(int x) { + A_.emplace(x); + } + + // Removes the element from in front of queue. + void pop(void) { + peek(); + B_.pop(); + } + + // Get the front element. + int peek(void) { + if (B_.empty()) { + // Transfers the elements in A_ to B_. + while (!A_.empty()) { + B_.emplace(A_.top()); + A_.pop(); + } + } + if (B_.empty()) { // B_ is still empty! + throw length_error("empty queue"); + } + return B_.top(); + } + + // Return whether the queue is empty. + bool empty(void) { + return A_.empty() && B_.empty(); + } + + private: + stack A_, B_; +}; diff --git a/C++/implement-stack-using-queues.cpp b/C++/implement-stack-using-queues.cpp new file mode 100644 index 000000000..baf0b5789 --- /dev/null +++ b/C++/implement-stack-using-queues.cpp @@ -0,0 +1,66 @@ +// Time: push: O(n), pop: O(1), top: O(1) +// Space: O(n) + +class Stack { +public: + queue q_; + + // Push element x onto stack. + void push(int x) { // O(n) + q_.emplace(x); + for (int i = 0; i < q_.size() - 1; ++i) { + q_.emplace(q_.front()); + q_.pop(); + } + } + + // Remove the element on top of the stack. + void pop() { // O(1) + q_.pop(); + } + + // Get the top element. + int top() { // O(1) + return q_.front(); + } + + // Return whether the stack is empty. + bool empty() { // O(1) + return q_.empty(); + } +}; + +// Time: push: O(1), pop: O(n), top: O(1) +// Space: O(n) +class Stack2 { +public: + queue q_; + int top_; + + // Push element x onto stack. + void push(int x) { // O(1) + q_.emplace(x); + top_ = x; + } + + // Remove the element on top of the stack. + void pop() { // O(n) + for (int i = 0; i < q_.size() - 1; ++i) { + top_ = q_.front(); + q_.emplace(top_); + q_.pop(); + } + q_.pop(); + } + + // Get the top element. + int top() { // O(1) + return top_; + } + + // Return whether the stack is empty. + bool empty() { // O(1) + return q_.empty(); + } +}; + diff --git a/C++/implement-strstr.cpp b/C++/implement-strstr.cpp new file mode 100644 index 000000000..831645f8b --- /dev/null +++ b/C++/implement-strstr.cpp @@ -0,0 +1,62 @@ +// Time: O(n + k) +// Space: O(k) + +// Wiki of KMP algorithm: +// http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm +class Solution { +public: + int strStr(string haystack, string needle) { + if (needle.empty()) { + return 0; + } + + return KMP(haystack, needle); + } + + int KMP(const string& text, const string& pattern) { + const vector prefix = getPrefix(pattern); + int j = -1; + for (int i = 0; i < text.length(); ++i) { + while (j > -1 && pattern[j + 1] != text[i]) { + j = prefix[j]; + } + if (pattern[j + 1] == text[i]) { + ++j; + } + if (j == pattern.length() - 1) { + return i - j; + } + } + return -1; + } + + vector getPrefix(const string& pattern) { + vector prefix(pattern.length(), -1); + int j = -1; + for (int i = 1; i < pattern.length(); ++i) { + while (j > -1 && pattern[j + 1] != pattern[i]) { + j = prefix[j]; + } + if (pattern[j + 1] == pattern[i]) { + ++j; + } + prefix[i] = j; + } + return prefix; + } +}; + + +// Time: O(n * k) +// Space: O(k) +class Solution2 { +public: + int strStr(string haystack, string needle) { + for (int i = 0; i + needle.length() < haystack.length() + 1; ++i) { + if (haystack.substr(i, needle.length()) == needle) { + return i; + } + } + return -1; + } +}; diff --git a/C++/implement-trie-prefix-tree.cpp b/C++/implement-trie-prefix-tree.cpp new file mode 100644 index 000000000..8a94245dd --- /dev/null +++ b/C++/implement-trie-prefix-tree.cpp @@ -0,0 +1,66 @@ +// Time: O(n), per operation +// Space: O(1) + +class TrieNode { +public: + // Initialize your data structure here. + TrieNode() : is_string(false) { + + } + bool is_string; + unordered_map leaves; +}; + +class Trie { +public: + Trie() { + root_ = new TrieNode(); + } + + // Inserts a word into the trie. + void insert(string word) { + auto *cur = root_; + for (const auto& c : word) { + if (!cur->leaves.count(c)) { + cur->leaves[c] = new TrieNode(); + } + cur = cur->leaves[c]; + } + cur->is_string = true; + } + + // Returns if the word is in the trie. + bool search(string word) { + auto *node = childSearch(word); + if (node) { + return node->is_string; + } + return false; + } + + // Returns if there is any word in the trie + // that starts with the given prefix. + bool startsWith(string prefix) { + return childSearch(prefix); + } + + TrieNode *childSearch(const string& word) { + auto *cur = root_; + for (const auto& c : word) { + if (cur->leaves.count(c)) { + cur = cur->leaves[c]; + } else { + return nullptr; + } + } + return cur; + } + +private: + TrieNode *root_; +}; + +// Your Trie object will be instantiated and called as such: +// Trie trie; +// trie.insert("somestring"); +// trie.search("key"); diff --git a/C++/increasing-subsequences.cpp b/C++/increasing-subsequences.cpp new file mode 100644 index 000000000..50cd7c944 --- /dev/null +++ b/C++/increasing-subsequences.cpp @@ -0,0 +1,30 @@ +// Time: O(n * 2^n) +// Space: O(n^2) + +class Solution { +public: + vector> findSubsequences(vector& nums) { + vector> result; + vector seq; + findSubsequencesHelper(nums, 0, &seq, &result); + return result; + } + + void findSubsequencesHelper(const vector& nums, int i, + vector *seq, + vector> *result) { + if (seq->size() >= 2) { + result->emplace_back(*seq); + } + unordered_set lookup; + for (; i < nums.size(); ++i) { + if ((seq->empty() || nums[i] >= seq->back()) && + lookup.find(nums[i]) == lookup.end()) { + lookup.emplace(nums[i]); + seq->emplace_back(nums[i]); + findSubsequencesHelper(nums, i + 1, seq, result); + seq->pop_back(); + } + } + } +}; diff --git a/C++/increasing-triplet-subsequence.cpp b/C++/increasing-triplet-subsequence.cpp new file mode 100644 index 000000000..8b6066111 --- /dev/null +++ b/C++/increasing-triplet-subsequence.cpp @@ -0,0 +1,42 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool increasingTriplet(vector& nums) { + int min = numeric_limits::max(), a = numeric_limits::max(), b = numeric_limits::max(); + for (const auto& c : nums) { + if (min >= c) { + min = c; + } else if (b >= c) { + a = min, b = c; + } else { // a < b < c + return true; + } + } + return false; + } +}; + +// Time: O(n * logk) +// Space: O(k) +// Generalization of k-uplet. +class Solution_Generalization { +public: + bool increasingTriplet(vector& nums) { + return increasingKUplet(nums, 3); + } + +private: + bool increasingKUplet(const vector& nums, const size_t k) { + vector inc(k - 1, numeric_limits::max()); + for (const auto& num : nums) { + auto it = lower_bound(inc.begin(), inc.end(), num); + if (distance(inc.begin(), it) >= k - 1) { + return true; + } + *it = num; + } + return k == 0; + } +}; diff --git a/C++/inorder-successor-in-bst.cpp b/C++/inorder-successor-in-bst.cpp new file mode 100644 index 000000000..7abac51c1 --- /dev/null +++ b/C++/inorder-successor-in-bst.cpp @@ -0,0 +1,38 @@ +// Time: O(h) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) { + // If it has right subtree. + if (p && p->right) { + p = p->right; + while (p->left) { + p = p->left; + } + return p; + } + + // Search from root. + TreeNode *successor = nullptr; + while (root && root != p) { + if (root->val > p->val) { + successor = root; + root = root->left; + } else { + root = root->right; + } + } + + return successor; + } +}; diff --git a/C++/insert-delete-getrandom-o1-duplicates-allowed.cpp b/C++/insert-delete-getrandom-o1-duplicates-allowed.cpp new file mode 100644 index 000000000..7e27d4891 --- /dev/null +++ b/C++/insert-delete-getrandom-o1-duplicates-allowed.cpp @@ -0,0 +1,103 @@ +// Time: O(1) +// Space: O(n) + +class RandomizedCollection { +public: + /** Initialize your data structure here. */ + RandomizedCollection() { + + } + + /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */ + bool insert(int val) { + bool has = used_.count(val); + + list_.emplace_back(val); + used_[val].emplace_back(list_.size() - 1); + + return !has; + } + + /** Removes a value from the collection. Returns true if the collection contained the specified element. */ + bool remove(int val) { + if (!used_.count(val)) { + return false; + } + + used_[list_.back()].back() = used_[val].back(); + swap(list_[used_[val].back()], list_.back()); + + used_[val].pop_back(); + if (used_[val].empty()) { + used_.erase(val); + } + list_.pop_back(); + + return true; + } + + /** Get a random element from the collection. */ + int getRandom() { + return list_[rand() % list_.size()]; + } + +private: + vector list_; + unordered_map> used_; +}; + + +// Time: O(1) +// Space: O(n) +class RandomizedCollection2 { +public: + /** Initialize your data structure here. */ + RandomizedCollection2() { + + } + + /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */ + bool insert(int val) { + bool has = used_.count(val); + + list_.emplace_back(val); + used_.emplace(val, list_.size() - 1); + + return !has; + } + + /** Removes a value from the collection. Returns true if the collection contained the specified element. */ + bool remove(int val) { + if (!used_.count(val)) { + return false; + } + + auto it_to_delete = used_.find(val); + auto it_to_back = used_.find(list_.back()); + it_to_back->second = it_to_delete->second; + swap(list_[it_to_delete->second], list_.back()); + + used_.erase(it_to_delete); + list_.pop_back(); + + return true; + } + + /** Get a random element from the collection. */ + int getRandom() { + return list_[rand() % list_.size()]; + } + +private: + vector list_; + unordered_multimap used_; +}; + +/** + * Your RandomizedCollection object will be instantiated and called as such: + * RandomizedCollection obj = new RandomizedCollection(); + * bool param_1 = obj.insert(val); + * bool param_2 = obj.remove(val); + * int param_3 = obj.getRandom(); + */ + diff --git a/C++/insert-delete-getrandom-o1.cpp b/C++/insert-delete-getrandom-o1.cpp new file mode 100644 index 000000000..cbc097811 --- /dev/null +++ b/C++/insert-delete-getrandom-o1.cpp @@ -0,0 +1,55 @@ +// Time: O(1) +// Space: O(n) + +class RandomizedSet { +public: + /** Initialize your data structure here. */ + RandomizedSet() { + + } + + /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ + bool insert(int val) { + if (used_.count(val)) { + return false; + } + + set_.emplace_back(val); + used_[val] = set_.size() - 1; + + return true; + } + + /** Removes a value from the set. Returns true if the set contained the specified element. */ + bool remove(int val) { + if (!used_.count(val)) { + return false; + } + + used_[set_.back()] = used_[val]; + swap(set_[used_[val]], set_.back()); + + used_.erase(val); + set_.pop_back(); + + return true; + } + + /** Get a random element from the set. */ + int getRandom() { + return set_[rand() % set_.size()]; + } + +private: + vector set_; + unordered_map used_; +}; + +/** + * Your RandomizedSet object will be instantiated and called as such: + * RandomizedSet obj = new RandomizedSet(); + * bool param_1 = obj.insert(val); + * bool param_2 = obj.remove(val); + * int param_3 = obj.getRandom(); + */ + diff --git a/C++/insert-interval.cpp b/C++/insert-interval.cpp new file mode 100644 index 000000000..8a5bc9120 --- /dev/null +++ b/C++/insert-interval.cpp @@ -0,0 +1,35 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + vector insert(vector& intervals, Interval newInterval) { + size_t i = 0; + vector result; + // Insert intervals appeared before newInterval. + while (i < intervals.size() && newInterval.start > intervals[i].end) { + result.emplace_back(intervals[i++]); + } + + // Merge intervals that overlap with newInterval. + while (i < intervals.size() && newInterval.end >= intervals[i].start) { + newInterval = {min(newInterval.start, intervals[i].start), + max(newInterval.end, intervals[i].end)}; + ++i; + } + result.emplace_back(newInterval); + + // Insert intervals appearing after newInterval. + result.insert(result.end(), intervals.cbegin() + i, intervals.cend()); + return result; + } +}; diff --git a/C++/insert.cpp b/C++/insert.cpp deleted file mode 100644 index 12a2a6e10..000000000 --- a/C++/insert.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for an interval. - * struct Interval { - * int start; - * int end; - * Interval() : start(0), end(0) {} - * Interval(int s, int e) : start(s), end(e) {} - * }; - */ -class Solution { - public: - vector insert(vector &intervals, Interval newInterval) { - vector ans; - auto n = intervals.size(); - for(int i = 0; i < n; ++i) { - if (newInterval.end < intervals[i].start) { // not overlapped - ans.push_back(newInterval); - for(; i < n; ++i) - ans.push_back(intervals[i]); - return ans; - } - else if (newInterval.start > intervals[i].end) { // not overlapped - ans.push_back(intervals[i]); - } - else { // merge - newInterval.start = min(newInterval.start, intervals[i].start); - newInterval.end = max(newInterval.end, intervals[i].end); - } - } - - ans.push_back(newInterval); - return ans; - } -}; diff --git a/C++/insertion-sort-list.cpp b/C++/insertion-sort-list.cpp new file mode 100644 index 000000000..d329155e5 --- /dev/null +++ b/C++/insertion-sort-list.cpp @@ -0,0 +1,37 @@ +// Time: O(n^2) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { + public: + ListNode *insertionSortList(ListNode *head) { + ListNode dummy{numeric_limits::min()}; + + auto curr = head; + ListNode *position = nullptr; + + while (curr) { + position = findInsertPosition(&dummy, curr->val); + ListNode *tmp = curr->next; + curr->next = position->next; + position->next = curr; + curr = tmp; + } + + return dummy.next; + } + + ListNode* findInsertPosition(ListNode *head, int x) { + ListNode *prev = nullptr; + for (auto curr = head; curr && curr->val <= x; + prev = curr, curr = curr->next); + return prev; + } +}; diff --git a/C++/insertionSortList.cpp b/C++/insertionSortList.cpp deleted file mode 100644 index 776d6ded6..000000000 --- a/C++/insertionSortList.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *insertionSortList(ListNode *head) { - ListNode dummy(INT_MIN); - - ListNode *cur = head; - ListNode *prev = NULL; - ListNode *pos = head; - - while(cur) { - pos = findInsertPos(&dummy, cur->val); - ListNode *tmp = cur->next; - cur->next = pos->next; - pos->next = cur; - cur = tmp; - } - - return dummy.next; - } - - ListNode* findInsertPos(ListNode *head, int x) { - ListNode *pre = NULL; - for (ListNode *cur = head; cur && cur->val <= x; - pre = cur, cur = cur->next); - return pre; - } -}; diff --git a/C++/integer-break.cpp b/C++/integer-break.cpp new file mode 100644 index 000000000..824ae28ea --- /dev/null +++ b/C++/integer-break.cpp @@ -0,0 +1,63 @@ +// Time: O(logn), pow is O(logn). +// Space: O(1) + +class Solution { +public: + int integerBreak(int n) { + if (n < 4) { + return n - 1; + } + + // Proof. + // 1. Let n = a1 + a2 + ... + ak, product = a1 * a2 * ... * ak + // - For each ai >= 4, we can always maximize the product by: + // ai <= 2 * (ai - 2) + // - For each aj >= 5, we can always maximize the product by: + // aj <= 3 * (aj - 3) + // + // Conclusion 1: + // - For n >= 4, the max of the product must be in the form of + // 3^a * 2^b, s.t. 3a + 2b = n + // + // 2. To maximize the product = 3^a * 2^b s.t. 3a + 2b = n + // - For each b >= 3, we can always maximize the product by: + // 3^a * 2^b <= 3^(a+2) * 2^(b-3) s.t. 3(a+2) + 2(b-3) = n + // + // Conclusion 2: + // - For n >= 4, the max of the product must be in the form of + // 3^Q * 2^R, 0 <= R < 3 s.t. 3Q + 2R = n + // i.e. + // if n = 3Q + 0, the max of the product = 3^Q * 2^0 + // if n = 3Q + 2, the max of the product = 3^Q * 2^1 + // if n = 3Q + 2*2, the max of the product = 3^Q * 2^2 + + int res = 0; + if (n % 3 == 0) { // n = 3Q + 0, the max is 3^Q * 2^0 + res = pow(3, n / 3); + } else if (n % 3 == 2) { // n = 3Q + 2, the max is 3^Q * 2^1 + res = pow(3, n / 3) * 2; + } else { // n = 3Q + 4, the max is 3^Q * 2^2 + res = pow(3, n / 3 - 1) * 4; + } + return res; + } +}; + +// Time: O(n) +// Space: O(1) +// DP solution. +class Solution2 { +public: + int integerBreak(int n) { + if (n < 4) { + return n - 1; + } + + // integerBreak(n) = max(integerBreak(n - 2) * 2, integerBreak(n - 3) * 3) + vector res{0, 1, 2, 3}; + for (int i = 4; i <= n; ++i) { + res[i % 4] = max(res[(i - 2) % 4] * 2, res[(i - 3) % 4] * 3); + } + return res[n % 4]; + } +}; diff --git a/C++/integer-replacement.cpp b/C++/integer-replacement.cpp new file mode 100644 index 000000000..9539e1c8f --- /dev/null +++ b/C++/integer-replacement.cpp @@ -0,0 +1,55 @@ +// Time: O(logn) +// Space: O(1) + +// Iterative solution. +class Solution { +public: + int integerReplacement(int n) { + if (n == 2147483647) { + return 2 + integerReplacement(n / 2 + 1); + } + + int result = 0; + while (n != 1) { + const auto b = n & 3; + if (n == 3) { + --n; + } else if (b == 3) { + ++n; + } else if (b == 1) { + --n; + } else { + n /= 2; + } + ++result; + } + return result; + } +}; + +// Time: O(logn) +// Space: O(logn) +// Recursive solution +class Solution2 { +public: + int integerReplacement(int n) { + if (n == 2147483647) { + return 2 + integerReplacement(n / 2 + 1); + } + + if (n < 4) { + switch (n % 4) { + case 0: case 1: return 0; + case 2: return 1; + case 3: return 2; + } + } + + switch (n % 4) { + case 0: case 2: return integerReplacement(n / 2) + 1; + case 1: return integerReplacement((n - 1) / 4) + 3; + case 3: return integerReplacement((n + 1) / 4) + 3; + } + return 0; + } +}; diff --git a/C++/integer-to-english-words.cpp b/C++/integer-to-english-words.cpp new file mode 100644 index 000000000..fef662047 --- /dev/null +++ b/C++/integer-to-english-words.cpp @@ -0,0 +1,65 @@ +// Time: O(logn), n is the value of the integer +// Space: O(1) + +class Solution { +public: + string numberToWords(int num) { + if (num == 0) { + return "Zero"; + } + const unordered_map lookup = {{0, "Zero"}, {1, "One"}, {2, "Two"}, + {3, "Three"}, {4, "Four"}, {5, "Five"}, + {6, "Six"}, {7, "Seven"}, {8, "Eight"}, + {9, "Nine"}, {10, "Ten"}, {11, "Eleven"}, + {12, "Twelve"}, {13, "Thirteen"}, {14, "Fourteen"}, + {15, "Fifteen"}, {16, "Sixteen"}, {17, "Seventeen"}, + {18, "Eighteen"}, {19, "Nineteen"}, {20, "Twenty"}, + {30, "Thirty"}, {40, "Forty"}, {50, "Fifty"}, + {60, "Sixty"}, {70, "Seventy"}, {80, "Eighty"}, + {90, "Ninety"}}; + const vector unit{"", "Thousand", "Million", "Billion"}; + + vector res; + int i = 0; + while (num) { + const int cur = num % 1000; + if (num % 1000) { + res.emplace_back(threeDigits(cur, lookup, unit[i])); + } + num /= 1000; + ++i; + } + reverse(res.begin(), res.end()); + return join(res, " "); + } + + string join(const vector& strings, const string& delim) { + if (strings.empty()) { + return ""; + } + ostringstream imploded; + copy(strings.begin(), prev(strings.end()), ostream_iterator(imploded, delim.c_str())); + return imploded.str() + *prev(strings.end()); + } + + string threeDigits(const int& num, const unordered_map& lookup, const string& unit) { + vector res; + if (num / 100) { + res.emplace_back(lookup.find(num / 100)->second + " " + "Hundred"); + } + if (num % 100) { + res.emplace_back(twoDigits(num % 100, lookup)); + } + if (!unit.empty()) { + res.emplace_back(unit); + } + return join(res, " "); + } + + string twoDigits(const int& num, const unordered_map& lookup) { + if (lookup.find(num) != lookup.end()) { + return lookup.find(num)->second; + } + return lookup.find((num / 10) * 10)->second + " " + lookup.find(num % 10)->second; + } +}; diff --git a/C++/integer-to-roman.cpp b/C++/integer-to-roman.cpp new file mode 100644 index 000000000..4b4d4fc9c --- /dev/null +++ b/C++/integer-to-roman.cpp @@ -0,0 +1,24 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string intToRoman(int num) { + const vector nums{1000, 900, 500, 400, 100, 90, + 50, 40, 10, 9, 5, 4, 1}; + const vector romans{"M", "CM", "D", "CD", "C", "XC", "L", + "XL", "X", "IX", "V", "IV", "I"}; + + string result; + int i = 0; + while (num > 0) { + int times = num / nums[i]; + while (times--) { + num -= nums[i]; + result.append(romans[i]); + } + ++i; + } + return result; + } +}; diff --git a/C++/intersection-of-two-arrays-ii.cpp b/C++/intersection-of-two-arrays-ii.cpp new file mode 100644 index 000000000..c79fd27cc --- /dev/null +++ b/C++/intersection-of-two-arrays-ii.cpp @@ -0,0 +1,124 @@ +// If the given array is not sorted and the memory is unlimited: +// - Time: O(m + n) +// - Space: O(min(m, n)) +// elif the given array is already sorted: +// if m << n or m >> n: +// - Time: O(min(m, n) * log(max(m, n))) +// - Space: O(1) +// else: +// - Time: O(m + n) +// - Soace: O(1) +// else: (the given array is not sorted and the memory is limited) +// - Time: O(max(m, n) * log(max(m, n))) +// - Space: O(1) + +// If the given array is not sorted and the memory is unlimited. +// Time: O(m + n) +// Space: O(min(m, n)) +// Hash solution. +class Solution { +public: + vector intersect(vector& nums1, vector& nums2) { + if (nums1.size() > nums2.size()) { + return intersect(nums2, nums1); + } + + unordered_map lookup; + for (const auto& i : nums1) { + ++lookup[i]; + } + + vector result; + for (const auto& i : nums2) { + if (lookup[i] > 0) { + result.emplace_back(i); + --lookup[i]; + } + } + + return result; + } +}; + + +// If the given array is already sorted, and the memory is limited, and (m << n or m >> n). +// Time: O(min(m, n) * log(max(m, n))) +// Space: O(1) +// Binary search solution. +class Solution { +public: + vector intersect(vector& nums1, vector& nums2) { + if (nums1.size() > nums2.size()) { + return intersect(nums2, nums1); + } + + // Make sure it is sorted, doesn't count in time. + sort(nums1.begin(), nums1.end()); + sort(nums2.begin(), nums2.end()); + + vector result; + auto it = nums2.cbegin(); + for (const auto& i : nums1) { + it = lower_bound(it, nums2.cend(), i); + if (it != nums2.end() && *it == i) { + result.emplace_back(*it++); + } + } + + return result; + } +}; + + +// If the given array is already sorted, and the memory is limited or m ~ n. +// Time: O(m + n) +// Soace: O(1) +// Two pointers solution. +class Solution { +public: + vector intersect(vector& nums1, vector& nums2) { + vector result; + // Make sure it is sorted, doesn't count in time. + sort(nums1.begin(), nums1.end()); + sort(nums2.begin(), nums2.end()); + auto it1 = nums1.cbegin(), it2 = nums2.cbegin(); + while (it1 != nums1.cend() && it2 != nums2.cend()) { + if (*it1 < *it2) { + ++it1; + } else if (*it1 > *it2) { + ++it2; + } else { + result.emplace_back(*it1); + ++it1, ++it2; + } + } + return result; + } +}; + + +// If the given array is not sorted, and the memory is limited. +// Time: O(max(m, n) * log(max(m, n))) +// Space: O(1) +// Two pointers solution. +class Solution { +public: + vector intersect(vector& nums1, vector& nums2) { + vector result; + // O(max(m, n) * log(max(m, n))) + sort(nums1.begin(), nums1.end()); + sort(nums2.begin(), nums2.end()); + auto it1 = nums1.cbegin(), it2 = nums2.cbegin(); + while (it1 != nums1.cend() && it2 != nums2.cend()) { + if (*it1 < *it2) { + ++it1; + } else if (*it1 > *it2) { + ++it2; + } else { + result.emplace_back(*it1); + ++it1, ++it2; + } + } + return result; + } +}; diff --git a/C++/intersection-of-two-arrays.cpp b/C++/intersection-of-two-arrays.cpp new file mode 100644 index 000000000..a9f84bfc4 --- /dev/null +++ b/C++/intersection-of-two-arrays.cpp @@ -0,0 +1,79 @@ +// Time: O(m + n) +// Space: O(min(m, n)) + +// Hash solution. +class Solution { +public: + vector intersection(vector& nums1, vector& nums2) { + if (nums1.size() > nums2.size()) { + return intersection(nums2, nums1); + } + + unordered_set lookup{nums1.cbegin(), nums1.cend()}; + + vector result; + for (const auto& i : nums2) { + if (lookup.count(i)) { + result.emplace_back(i); + lookup.erase(i); + } + } + + return result; + } +}; + + +// Time: O(max(m, n) * log(max(m, n))) +// Space: O(1) +// Binary search solution. +class Solution2 { +public: + vector intersection(vector& nums1, vector& nums2) { + if (nums1.size() > nums2.size()) { + return intersection(nums2, nums1); + } + + sort(nums1.begin(), nums1.end()); + sort(nums2.begin(), nums2.end()); + + vector result; + auto it = nums2.cbegin(); + for (const auto& i : nums1) { + it = lower_bound(it, nums2.cend(), i); + if (it != nums2.end() && *it == i) { + result.emplace_back(*it); + it = upper_bound(it, nums2.cend(), i); + } + } + + return result; + } +}; + + +// Time: O(max(m, n) * log(max(m, n))) +// Space: O(1) +// Two pointers solution. +class Solution3 { +public: + vector intersection(vector& nums1, vector& nums2) { + vector result; + sort(nums1.begin(), nums1.end()); + sort(nums2.begin(), nums2.end()); + auto it1 = nums1.cbegin(), it2 = nums2.cbegin(); + while (it1 != nums1.cend() && it2 != nums2.cend()) { + if (*it1 < *it2) { + ++it1; + } else if (*it1 > *it2) { + ++it2; + } else { + if (result.empty() || result.back() != *it1) { + result.emplace_back(*it1); + } + ++it1, ++it2; + } + } + return result; + } +}; diff --git a/C++/intersection-of-two-linked-lists.cpp b/C++/intersection-of-two-linked-lists.cpp new file mode 100644 index 000000000..d5dda7208 --- /dev/null +++ b/C++/intersection-of-two-linked-lists.cpp @@ -0,0 +1,44 @@ +// Time: O(m + n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + ListNode *curA = headA, *curB = headB; + ListNode *begin = nullptr, *tailA = nullptr, *tailB = nullptr; + while (curA && curB) { + if (curA == curB) { + begin = curA; + break; + } + + if (curA->next) { + curA = curA->next; + } else if (!tailA) { + tailA = curA; + curA = headB; + } else { + break; + } + + if (curB->next) { + curB = curB->next; + } else if (!tailB) { + tailB = curB; + curB = headA; + } else { + break; + } + } + + return begin; + } +}; diff --git a/C++/invert-binary-tree.cpp b/C++/invert-binary-tree.cpp new file mode 100644 index 000000000..f08fa7b42 --- /dev/null +++ b/C++/invert-binary-tree.cpp @@ -0,0 +1,77 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +// Time: O(n) +// Space: O(w), w is the max number of nodes of the levels. +// BFS solution. +class Solution { +public: + TreeNode* invertTree(TreeNode* root) { + if (root != nullptr) { + queue nodes; + nodes.emplace(root); + while (!nodes.empty()) { + auto node = nodes.front(); + nodes.pop(); + swap(node->left, node->right); + if (node->left != nullptr) { + nodes.emplace(node->left); + } + if (node->right != nullptr) { + nodes.emplace(node->right); + } + } + } + return root; + } +}; + +// Time: O(n) +// Space: O(h) +// Stack solution. +class Solution2 { +public: + TreeNode* invertTree(TreeNode* root) { + if (root != nullptr) { + stack nodes; + nodes.emplace(root); + while (!nodes.empty()) { + auto node = nodes.top(); + nodes.pop(); + swap(node->left, node->right); + if (node->left != nullptr) { + nodes.emplace(node->left); + } + if (node->right != nullptr) { + nodes.emplace(node->right); + } + } + } + return root; + } +}; + +// Time: O(n) +// Space: O(h) +// DFS, Recursive solution. +class Solution3 { +public: + TreeNode* invertTree(TreeNode* root) { + if (root != nullptr) { + swap(root->left, root->right); + invertTree(root->left); + invertTree(root->right); + } + return root; + } +}; diff --git a/C++/ipo.cpp b/C++/ipo.cpp new file mode 100644 index 000000000..d0d1d19cf --- /dev/null +++ b/C++/ipo.cpp @@ -0,0 +1,26 @@ +// Time: O(nlogn) +// Space: O(n) + +class Solution { +public: + int findMaximizedCapital(int k, int W, vector& Profits, vector& Capital) { + vector> future; + for (int i = 0; i < Profits.size(); ++i) { + future.emplace_back(Capital[i], Profits[i]); + } + sort(future.begin(), future.end(), greater>()); + + priority_queue curr; + while (k--) { + while (!future.empty() && future.back().first <= W) { + curr.emplace(future.back().second); + future.pop_back(); + } + if (!curr.empty()) { + W += curr.top(); + curr.pop(); + } + } + return W; + } +}; diff --git a/C++/is-subsequence.cpp b/C++/is-subsequence.cpp new file mode 100644 index 000000000..9be890d17 --- /dev/null +++ b/C++/is-subsequence.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(1) + +// Greedy solution. +class Solution { +public: + bool isSubsequence(string s, string t) { + if (s.empty()) { + return true; + } + + int i = 0; + for (const auto& c : t) { + if (c == s[i]) { + ++i; + } + if (i == s.length()) { + break; + } + } + return i == s.length(); + } +}; diff --git a/C++/isPalindrome.cpp b/C++/isPalindrome.cpp deleted file mode 100644 index b2506097f..000000000 --- a/C++/isPalindrome.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - bool isPalindrome(int x) { - if(x < 0) - return false; - - int d = 1; - for(; x / d >= 10 ; d *= 10); - - for(; x > 0; x = (x % d) / 10, d /= 100) { - int q = x / d; - int r = x % 10; - if(q != r) - return false; - } - - return true; - } -}; diff --git a/C++/isPalindromeII.cpp b/C++/isPalindromeII.cpp deleted file mode 100644 index 557697794..000000000 --- a/C++/isPalindromeII.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - bool isPalindrome(string s) { - transform(s.begin(), s.end(), s.begin(), ::tolower); - auto left = s.begin(); - auto right = prev(s.end()); - for(; left < right;) { - if(!isalnum(*left)) - ++left; - else if(!isalnum(*right)) - --right; - else if(*left != *right) - return false; - else { - ++left; - --right; - } - } - return true; - } -}; diff --git a/C++/isValid.cpp b/C++/isValid.cpp deleted file mode 100644 index 2f132d8bc..000000000 --- a/C++/isValid.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - bool isValid(string s) { - const string left = "([{"; - const string right = ")]}"; - stack stack; - for(auto c : s) { - if(left.find(c) != string::npos) { - stack.push(c); - } - else if (right.find(c) != string::npos){ - if(!stack.empty() && stack.top() == left[right.find(c)]) { - stack.pop(); - } - else - return false; - } - } - - return stack.empty(); - } -}; diff --git a/C++/isValidBST.cpp b/C++/isValidBST.cpp deleted file mode 100644 index cb8359ba7..000000000 --- a/C++/isValidBST.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(logn) - -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { - public: - bool isValidBST(TreeNode *root) { - if(!root) - return true; - - if(!isValidBST(root->left)) - return false; - - if(last && last != root && last->val >= root->val) - return false; - - last = root; - - if(!isValidBST(root->right)) - return false; - - return true; - } - - private: - TreeNode *last; -}; diff --git a/C++/isValidSudoku.cpp b/C++/isValidSudoku.cpp deleted file mode 100644 index 021c8fa83..000000000 --- a/C++/isValidSudoku.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(n) - -class Solution { - public: - bool isValidSudoku(vector > &board) { - bool used[9]; - - for(int i = 0; i < 9; ++i) { - fill(used, used + 9, false); - for(int j = 0; j < 9; ++j) { - if(!check(board[i][j], used)) - return false; - } - - fill(used, used + 9, false); - for(int j = 0; j < 9; ++j) { - if(!check(board[j][i], used)) - return false; - } - } - - for(int r = 0; r < 3; ++r) { - for(int c = 0; c < 3; ++c) { - fill(used, used + 9, false); - for(int i = 3 * r; i < 3 * (r + 1); ++i) { - for(int j = 3 * c; j < 3 * (c + 1); ++j) { - if(!check(board[i][j], used)) - return false; - } - } - } - } - - return true; - } - - private: - bool check(char c, bool used[9]) { - if(c != '.') { - if(used[c - '1']) - return false; - used[c - '1'] = true; - } - return true; - } -}; diff --git a/C++/island-perimeter.cpp b/C++/island-perimeter.cpp new file mode 100644 index 000000000..2b60cee51 --- /dev/null +++ b/C++/island-perimeter.cpp @@ -0,0 +1,23 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + int islandPerimeter(vector>& grid) { + int count = 0, repeat = 0; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[i].size(); ++j) { + if (grid[i][j] == 1) { + ++count; + if (i != 0 && grid[i - 1][j] == 1) { + ++repeat; + } + if (j != 0 && grid[i][j - 1] == 1) { + ++repeat; + } + } + } + } + return 4 * count - 2 * repeat; + } +}; diff --git a/C++/isomorphic-strings.cpp b/C++/isomorphic-strings.cpp new file mode 100644 index 000000000..1a100d7cf --- /dev/null +++ b/C++/isomorphic-strings.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isIsomorphic(string s, string t) { + if (s.length() != t.length()) { + return false; + } + vector s2t(256, 0), t2s(256, 0); + for (int i = 0; i < s.length(); ++i) { + if (s2t[s[i]] == 0 && t2s[t[i]] == 0) { + s2t[s[i]] = t[i]; + t2s[t[i]] = s[i]; + } else if (s2t[s[i]] != t[i]) { + // Contradict mapping. + return false; + } + } + return true; + } +}; diff --git a/C++/judge-route-circle.cpp b/C++/judge-route-circle.cpp new file mode 100644 index 000000000..26c9262c7 --- /dev/null +++ b/C++/judge-route-circle.cpp @@ -0,0 +1,18 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool judgeCircle(string moves) { + auto v = 0, h = 0; + for (const auto& move : moves) { + switch (move) { + case 'U': ++v; break; + case 'D': --v; break; + case 'R': ++h; break; + case 'L': --h; break; + } + } + return v == 0 && h == 0; + } +}; diff --git a/C++/k-diff-pairs-in-an-array.cpp b/C++/k-diff-pairs-in-an-array.cpp new file mode 100644 index 000000000..0d1d32fd5 --- /dev/null +++ b/C++/k-diff-pairs-in-an-array.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int findPairs(vector& nums, int k) { + if (k < 0) { + return 0; + } + unordered_set result, lookup; + for (const auto& num : nums) { + if (lookup.count(num - k)) { + result.emplace(num - k); + } + if (lookup.count(num + k)) { + result.emplace(num); + } + lookup.emplace(num); + } + return result.size(); + } +}; diff --git a/C++/k-empty-slots.cpp b/C++/k-empty-slots.cpp new file mode 100644 index 000000000..97cc23a15 --- /dev/null +++ b/C++/k-empty-slots.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int kEmptySlots(vector& flowers, int k) { + vector days(flowers.size()); + for (int i = 0; i < flowers.size(); ++i) { + days[flowers[i] - 1] = i; + } + auto result = numeric_limits::max(); + for (int i = 0, left = 0, right = k + 1; right < days.size(); ++i) { + if (days[i] < days[left] || days[i] <= days[right]) { + if (i == right) { + result = min(result, max(days[left], days[right])); + } + left = i, right = k + 1 + i; + } + } + return (result == numeric_limits::max()) ? -1 : result + 1; + } +}; diff --git a/C++/k-inverse-pairs-array.cpp b/C++/k-inverse-pairs-array.cpp new file mode 100644 index 000000000..bc3647ed8 --- /dev/null +++ b/C++/k-inverse-pairs-array.cpp @@ -0,0 +1,23 @@ +// Time: O(n * k) +// Space: O(k) + +class Solution { +public: + int kInversePairs(int n, int k) { + static const int M = 1000000007; + vector> dp(2, vector(k + 1)); + dp[0][0] = 1; + for (int i = 1; i <= n; ++i) { + dp[i % 2] = vector(k + 1); + dp[i % 2][0] = 1; + for (int j = 1; j <= k; ++j) { + dp[i % 2][j] = (dp[i % 2][j - 1] + dp[(i - 1) % 2][j]) % M; + if (j - i >= 0) { + dp[i % 2][j] = (dp[i % 2][j] - dp[(i - 1) % 2][j - i] + M) % M; + } + } + } + return dp[n % 2][k]; + } +}; + diff --git a/C++/k-th-smallest-in-lexicographical-order.cpp b/C++/k-th-smallest-in-lexicographical-order.cpp new file mode 100644 index 000000000..48f9fbfb9 --- /dev/null +++ b/C++/k-th-smallest-in-lexicographical-order.cpp @@ -0,0 +1,92 @@ +// Time: O(logn) +// Space: O(logn) + +class Solution { +public: + int findKthNumber(int n, int k) { + int result = 0; + + vector cnts(10); + for (int i = 1; i <= 9; ++i) { + cnts[i] = cnts[i - 1] * 10 + 1; + } + + vector nums; + for (int i = n; i > 0; i /= 10) { + nums.emplace_back(i % 10); + } + int total = n; + int target = 0; + for (int i = nums.size() - 1; i >= 0 && k; --i) { + target = target * 10 + nums[i]; + const auto start = i == nums.size() - 1 ? 1 : 0; + for (int j = start; j <= 9; ++j) { + const auto candidate = result * 10 + j; + int num; + if (candidate < target) { + num = cnts[i + 1]; + } else if (candidate > target) { + num = cnts[i]; + } else { + num = total - cnts[i + 1] * (j - start) - cnts[i] * (9 - j); + } + if (k > num) { + k -= num; + } else { + result = candidate; + --k; + total = num - 1; + break; + } + } + } + return result; + } +}; + +// Time: O(logn * logn) +// Space: O(logn) +class Solution2 { +public: + int findKthNumber(int n, int k) { + int result = 0; + int index = 0; + findKthNumberHelper(n, k, 0, &index, &result); + return result; + } + +private: + bool findKthNumberHelper(int n, int k, int cur, int *index, int *result) { + if (cur) { + ++(*index); + if (*index == k) { + *result = cur; + return true; + } + } + for (int i = (cur == 0 ? 1 : 0); i <= 9; ++i, cur /= 10) { + cur = cur * 10 + i; + int cnt = count(n, cur); + if (k > cnt + *index) { + *index += cnt; + continue; + } + if (cur <= n && findKthNumberHelper(n, k, cur, index, result)) { + return true; + } + } + return false; + } + + int count(int n, long long prefix) { // Time: O(logn) + int result = 0; + int number = 1; + while (prefix <= n) { + result += number; + prefix *= 10; + number *= 10; + } + result -= max(number / 10 - (n - prefix / 10 + 1), static_cast(0)); + return result; + } +}; diff --git a/C++/keyboard-row.cpp b/C++/keyboard-row.cpp new file mode 100644 index 000000000..d6820da13 --- /dev/null +++ b/C++/keyboard-row.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findWords(vector& words) { + static const vector> rows{{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'}, + {'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'}, + {'z', 'x', 'c', 'v', 'b' ,'n', 'm'}}; + + vector result; + for (const auto& word : words) { + int k = 0; + for (int i = 0; i < rows.size(); ++i) { + if (rows[i].count(tolower(word[0]))) { + k = i; + break; + } + } + result.emplace_back(word); + for (const auto& c: word) { + if (!rows[k].count(tolower(c))) { + result.pop_back(); + break; + } + } + } + return result; + } +}; diff --git a/C++/kill-process.cpp b/C++/kill-process.cpp new file mode 100644 index 000000000..4f4e82766 --- /dev/null +++ b/C++/kill-process.cpp @@ -0,0 +1,50 @@ +// Time: O(n) +// Space: O(n) + +// DFS solution. +class Solution { +public: + vector killProcess(vector& pid, vector& ppid, int kill) { + vector result; + unordered_map> children; + for (int i = 0; i < pid.size(); ++i) { + children[ppid[i]].emplace(pid[i]); + } + killAll(kill, children, &result); + return result; + } + +private: + void killAll(int pid, unordered_map>& children, vector *killed) { + killed->emplace_back(pid); + for (const auto& child : children[pid]) { + killAll(child, children, killed); + } + } +}; + +// Time: O(n) +// Space: O(n) +// BFS solution. +class Solution { +public: + vector killProcess(vector& pid, vector& ppid, int kill) { + vector result; + unordered_map> children; + for (int i = 0; i < pid.size(); ++i) { + children[ppid[i]].emplace(pid[i]); + } + + queue q; + q.emplace(kill); + while (!q.empty()) { + const auto p = q.front(); q.pop(); + result.emplace_back(p); + for (const auto& child : children[p]) { + q.emplace(child); + } + } + + return result; + } +}; diff --git a/C++/knight-probability-in-chessboard.cpp b/C++/knight-probability-in-chessboard.cpp new file mode 100644 index 000000000..8d95b4ed9 --- /dev/null +++ b/C++/knight-probability-in-chessboard.cpp @@ -0,0 +1,27 @@ +// Time: O(k * n^2) +// Space: O(n^2) + +class Solution { +public: + double knightProbability(int N, int K, int r, int c) { + static const vector> directions = + {{ 1, 2}, { 1, -2}, { 2, 1}, { 2, -1}, + {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}}; + vector>> dp(2, vector>(N, vector(N, 1.0l))); + for (int step = 1; step <= K; ++step) { + for (int i = 0; i < N; ++i) { + for (int j = 0; j < N; ++j) { + dp[step % 2][i][j] = 0; + for (const auto& direction : directions) { + auto rr = i + direction.first; + auto cc = j + direction.second; + if (0 <= cc && cc < N && 0 <= rr && rr < N) { + dp[step % 2][i][j] += 0.125l * dp[(step - 1) % 2][rr][cc]; + } + } + } + } + } + return dp[K % 2][r][c]; + } +}; diff --git a/C++/kth-largest-element-in-an-array.cpp b/C++/kth-largest-element-in-an-array.cpp new file mode 100644 index 000000000..caa643239 --- /dev/null +++ b/C++/kth-largest-element-in-an-array.cpp @@ -0,0 +1,47 @@ +// Time: O(n) ~ O(n^2) +// Space: O(1) + +class Solution { +public: + int findKthLargest(vector& nums, int k) { + int left = 0, right = nums.size() - 1; + default_random_engine gen((random_device())()); + while (left <= right) { + // Generates a random int in [left, right]. + uniform_int_distribution dis(left, right); + int pivot_idx = dis(gen); + int new_pivot_idx = PartitionAroundPivot(left, right, pivot_idx, &nums); + if (new_pivot_idx == k - 1) { + return nums[new_pivot_idx]; + } else if (new_pivot_idx > k - 1) { + right = new_pivot_idx - 1; + } else { // new_pivot_idx < k - 1. + left = new_pivot_idx + 1; + } + } + } + + int PartitionAroundPivot(int left, int right, int pivot_idx, vector* nums) { + auto& nums_ref = *nums; + int pivot_value = nums_ref[pivot_idx]; + int new_pivot_idx = left; + swap(nums_ref[pivot_idx], nums_ref[right]); + for (int i = left; i < right; ++i) { + if (nums_ref[i] > pivot_value) { + swap(nums_ref[i], nums_ref[new_pivot_idx++]); + } + } + swap(nums_ref[right], nums_ref[new_pivot_idx]); + return new_pivot_idx; + } +}; + +// Time: O(n) ~ O(n^2) +// Space: O(1) +class Solution2 { +public: + int findKthLargest(vector& nums, int k) { + nth_element(nums.begin(), next(nums.begin(), k - 1), nums.end(), greater()); + return *next(nums.begin(), k - 1); + } +}; diff --git a/C++/kth-smallest-element-in-a-bst.cpp b/C++/kth-smallest-element-in-a-bst.cpp new file mode 100644 index 000000000..57901862d --- /dev/null +++ b/C++/kth-smallest-element-in-a-bst.cpp @@ -0,0 +1,65 @@ +// Time: O(max(h, k)) +// Space: O(min(h, k)) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +class Solution { +public: + int kthSmallest(TreeNode* root, int k) { + deque s; + TreeNode *cur = root; + int rank = 0; + while (!s.empty() || cur) { + if (cur) { + s.emplace_back(cur); + if (s.size() > k) { + s.pop_front(); + } + cur = cur->left; + } else { + cur = s.back(); + s.pop_back(); + if (++rank == k) { + return cur->val; + } + cur = cur->right; + } + } + + return INT_MIN; + } +}; + +// Time: O(max(h, k)) +// Space: O(h) +class Solution2 { +public: + int kthSmallest(TreeNode* root, int k) { + stack s; + TreeNode *cur = root; + int rank = 0; + while (!s.empty() || cur) { + if (cur) { + s.emplace(cur); + cur = cur->left; + } else { + cur = s.top(); + s.pop(); + if (++rank == k) { + return cur->val; + } + cur = cur->right; + } + } + + return INT_MIN; + } +}; diff --git a/C++/kth-smallest-element-in-a-sorted-matrix.cpp b/C++/kth-smallest-element-in-a-sorted-matrix.cpp new file mode 100644 index 000000000..580af5978 --- /dev/null +++ b/C++/kth-smallest-element-in-a-sorted-matrix.cpp @@ -0,0 +1,36 @@ +// Time: O(k * log(min(n, m, k))), with n x m matrix +// Space: O(min(n, m, k)) + +class Solution { +public: + int kthSmallest(vector>& matrix, int k) { + int kth_smallest = 0; + + using P = pair>; + priority_queue, greater

> q; + auto push = [&matrix, &q](int i, int j) { + if (matrix.size() > matrix[0].size()) { + if (i < matrix[0].size() && j < matrix.size()) { + q.emplace(matrix[j][i], make_pair(i, j)); + } + } else { + if (i < matrix.size() && j < matrix[0].size()) { + q.emplace(matrix[i][j], make_pair(i, j)); + } + } + }; + + push(0, 0); + while (!q.empty() && k--) { + auto tmp = q.top(); q.pop(); + kth_smallest = tmp.first; + int i, j; + tie(i, j) = tmp.second; + push(i, j + 1); + if (j == 0) { + push(i + 1, 0); + } + } + return kth_smallest; + } +}; diff --git a/C++/kth-smallest-number-in-multiplication-table.cpp b/C++/kth-smallest-number-in-multiplication-table.cpp new file mode 100644 index 000000000..bc3e788a4 --- /dev/null +++ b/C++/kth-smallest-number-in-multiplication-table.cpp @@ -0,0 +1,27 @@ +// Time: O(m * log(m * n)) +// Space: O(1) + +class Solution { +public: + int findKthNumber(int m, int n, int k) { + int left = 1, right = m * n; + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (count(mid, m, n) >= k) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } + +private: + int count(int target, int m, int n) { + auto count = 0; + for (int i = 1; i <= m; ++i) { + count += min(target / i , n); + } + return count; + } +}; diff --git a/C++/largest-bst-subtree.cpp b/C++/largest-bst-subtree.cpp new file mode 100644 index 000000000..0fbe79f6c --- /dev/null +++ b/C++/largest-bst-subtree.cpp @@ -0,0 +1,51 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int largestBSTSubtree(TreeNode* root) { + if (!root) { + return 0; + } + + int max_size = 1; + largestBSTSubtreeHelper(root, &max_size); + return max_size; + } + +private: + tuple largestBSTSubtreeHelper(TreeNode* root, int *max_size) { + if (!root->left && !root->right) { + return make_tuple(1, root->val, root->val); + } + + int left_size = 0, left_min = root->val, left_max = root->val; + if (root->left) { + tie(left_size, left_min, left_max) = largestBSTSubtreeHelper(root->left, max_size); + } + + int right_size = 0, right_min = root->val, right_max = root->val; + if (root->right) { + tie(right_size, right_min, right_max) = largestBSTSubtreeHelper(root->right, max_size); + } + + int size = 0; + if ((!root->left || left_size > 0) && + (!root->right || right_size > 0) && + left_max <= root->val && root->val <= right_min) { + size = 1 + left_size + right_size; + *max_size = max(*max_size, size); + } + + return make_tuple(size, left_min, right_max); + } +}; diff --git a/C++/largest-divisible-subset.cpp b/C++/largest-divisible-subset.cpp new file mode 100644 index 000000000..3a8ad35a2 --- /dev/null +++ b/C++/largest-divisible-subset.cpp @@ -0,0 +1,38 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + vector largestDivisibleSubset(vector& nums) { + if (nums.empty()) { + return {}; + } + + sort(nums.begin(), nums.end()); + // dp[i]: the size of the largest distinct subset of + // the first i+1 numbers including nums[i] + vector dp(nums.size() , 1); + vector prev(nums.size(), -1); + int largest_idx = 0; + for (int i = 0; i < nums.size(); ++i) { + for (int j = 0; j < i; ++j) { + if (nums[i] % nums[j] == 0) { + if (dp[i] < dp[j] + 1) { + dp[i] = dp[j] + 1; + prev[i] = j; + } + } + } + if (dp[largest_idx] < dp[i]) { + largest_idx = i; + } + } + + vector result; + for (int i = largest_idx; i != -1; i = prev[i]) { + result.emplace_back(nums[i]); + } + reverse(result.begin(), result.end()); + return result; + } +}; diff --git a/C++/largest-number.cpp b/C++/largest-number.cpp new file mode 100644 index 000000000..44ded1bb0 --- /dev/null +++ b/C++/largest-number.cpp @@ -0,0 +1,25 @@ +// Time: O(nlogn) +// Space: O(1) + +class Solution { +public: + string largestNumber(vector& nums) { + // sort numbers + sort(nums.begin(), nums.end(), [](const int &i, const int &j) { + return to_string(i) + to_string(j) > to_string(j) + to_string(i); + }); + + // combine the numbers + string max_num; + for (const auto& i : nums) { + max_num.append(to_string(i)); + } + + // special case: start with zero (e.g. [0, 0]) + if (!max_num.empty() && max_num[0] == '0') { + return "0"; + } + + return max_num; + } +}; diff --git a/C++/largest-palindrome-product.cpp b/C++/largest-palindrome-product.cpp new file mode 100644 index 000000000..f6513ef75 --- /dev/null +++ b/C++/largest-palindrome-product.cpp @@ -0,0 +1,29 @@ +// Time: O(10^(2n)) +// Space: O(n) + +class Solution { +public: + int largestPalindrome(int n) { + if (n == 1) { + return 9; + } + int upper = pow(10, n) - 1; + int lower = pow(10, n - 1); + for (int i = upper; i >= lower; --i) { + auto candidate = buildPalindrome(i); + for (long long j = upper; j * j >= candidate; --j) { + if (candidate % j == 0) { + return candidate % 1337; + } + } + } + return -1; + } + +private: + long long buildPalindrome(int n) { + string s = to_string(n); + reverse(s.begin(), s.end()); + return stoll(to_string(n) + s); + } +}; diff --git a/C++/largest-rectangle-in-histogram.cpp b/C++/largest-rectangle-in-histogram.cpp new file mode 100644 index 000000000..42ca352da --- /dev/null +++ b/C++/largest-rectangle-in-histogram.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int largestRectangleArea(vector& heights) { + stack increasing_heights; + int max_area = 0; + + for (int i = 0; i <= heights.size();) { + if (increasing_heights.empty() || + (i < heights.size() && heights[i] > heights[increasing_heights.top()])) { + increasing_heights.emplace(i); + ++i; + } else { + auto h = heights[increasing_heights.top()]; + increasing_heights.pop(); + auto left = increasing_heights.empty() ? -1 : increasing_heights.top(); + max_area = max(max_area, h * (i - left - 1)); + } + } + + return max_area; + } +}; diff --git a/C++/largestRectangleArea.cpp b/C++/largestRectangleArea.cpp deleted file mode 100644 index 584336bd0..000000000 --- a/C++/largestRectangleArea.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(n) - -Solution { - public: - int largestRectangleArea(vector &height) { - const int n = height.size(); - stack s; - int ans = 0; - if(n == 0) return 0; - - height.push_back(0); - - for(int i = 0; i < n + 1;) { - if(s.empty() || height[s.top()] < height[i]) - s.push(i++); - else { - int tmp = s.top(); - s.pop(); - ans = max(ans, height[tmp] * (s.empty()? i : i - s.top() - 1)); - } - } - return ans; - } -}; diff --git a/C++/length-of-last-word.cpp b/C++/length-of-last-word.cpp new file mode 100644 index 000000000..05684d6ca --- /dev/null +++ b/C++/length-of-last-word.cpp @@ -0,0 +1,12 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int lengthOfLastWord(string s) { + const auto is_space = [](const char c) { return isspace(c); }; + const auto it = find_if_not(s.rbegin(), s.rend(), is_space); + const auto jt = find_if(it, s.rend(), is_space); + return distance(it, jt); + } +}; diff --git a/C++/lengthOfLastWord.cpp b/C++/lengthOfLastWord.cpp deleted file mode 100644 index fc6ce929c..000000000 --- a/C++/lengthOfLastWord.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int lengthOfLastWord(const char *s) { - int len = 0; - for(; *s; ++s) { - if (*s != ' ') - ++len; - else if (*(s+1) && *(s+1) != ' ') - len = 0; - } - return len; - } -}; diff --git a/C++/lengthOfLongestSubstring.cpp b/C++/lengthOfLongestSubstring.cpp deleted file mode 100644 index 4d7486d17..000000000 --- a/C++/lengthOfLongestSubstring.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int lengthOfLongestSubstring(string s) { - vector last(26, -1); - int start = 0; - int ans = 0; - - for(int i = 0; i < s.size(); ++i) { - if(last[s[i] - 'a'] >= start) { // meet a repeated character - ans = max(i - start, ans); // recount max length of substring - start = last[s[i] - 'a'] + 1; // update start index next to the repeated one - } - last[s[i] - 'a'] = i; // update last index - } - - return max(static_cast(s.size()) - start, ans); // recount max length of substring due to end - } -}; diff --git a/C++/lexicographical-numbers.cpp b/C++/lexicographical-numbers.cpp new file mode 100644 index 000000000..8edaf8dcd --- /dev/null +++ b/C++/lexicographical-numbers.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector lexicalOrder(int n) { + vector result; + + for (int i = 1, num = 1; result.size() < n; i = num + 1) { + for (int k = 0; i * pow(10, k) <= n; ++k) { + result.emplace_back(i * pow(10, k)); + } + + for (num = result.back() + 1; num <= n && num % 10; ++num) { + result.emplace_back(num); + } + + if (num % 10 == 0) { + --num; + } else { + num /= 10; + } + + while (num % 10 == 9) { + num /= 10; + } + } + + return result; + } +}; diff --git a/C++/lfu-cache.cpp b/C++/lfu-cache.cpp new file mode 100644 index 000000000..6f454c313 --- /dev/null +++ b/C++/lfu-cache.cpp @@ -0,0 +1,69 @@ +// Time: O(1), per operation +// Space: O(k), k is the capacity of cache + +class LFUCache { +public: + LFUCache(int capacity) : capa_(capacity), size_(0), min_freq_(0) { + } + + int get(int key) { + if (!key_to_nodeit_.count(key)) { + return -1; + } + + auto new_node = *key_to_nodeit_[key]; + auto& freq = std::get(new_node); + freq_to_nodes_[freq].erase(key_to_nodeit_[key]); + if (freq_to_nodes_[freq].empty()) { + freq_to_nodes_.erase(freq); + if (min_freq_ == freq) { + ++min_freq_; + } + } + ++freq; + freq_to_nodes_[freq].emplace_back(move(new_node)); + key_to_nodeit_[key] = prev(freq_to_nodes_[freq].end()); + + return std::get(*key_to_nodeit_[key]); + } + + void put(int key, int value) { + if (capa_ <= 0) { + return; + } + + if (get(key) != -1) { + std::get(*key_to_nodeit_[key]) = value; + return; + } + + if (size_ == capa_) { + key_to_nodeit_.erase(std::get(freq_to_nodes_[min_freq_].front())); + freq_to_nodes_[min_freq_].pop_front(); + if (freq_to_nodes_[min_freq_].empty()) { + freq_to_nodes_.erase(min_freq_); + } + --size_; + } + + min_freq_ = 1; + freq_to_nodes_[min_freq_].emplace_back(key, value, min_freq_); + key_to_nodeit_[key] = prev(freq_to_nodes_[min_freq_].end()); + ++size_; + } + +private: + enum Data {KEY, VAL, FREQ}; + int capa_; + int size_; + int min_freq_; + unordered_map>> freq_to_nodes_; // freq to list of {key, val, freq} + unordered_map>::iterator> key_to_nodeit_; // key to list iterator +}; + +/** + * Your LFUCache object will be instantiated and called as such: + * LFUCache obj = new LFUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ diff --git a/C++/license-key-formatting.cpp b/C++/license-key-formatting.cpp new file mode 100644 index 000000000..f365c7b27 --- /dev/null +++ b/C++/license-key-formatting.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string licenseKeyFormatting(string S, int K) { + string result; + for (auto it = S.rbegin(); it < S.rend(); ++it) { + if (*it == '-') { + continue; + } + if (result.length() % (K + 1) == K) { + result += '-'; + } + result += toupper(*it); + } + reverse(result.begin(), result.end()); + return result; + } +}; diff --git a/C++/line-reflection.cpp b/C++/line-reflection.cpp new file mode 100644 index 000000000..986d8f904 --- /dev/null +++ b/C++/line-reflection.cpp @@ -0,0 +1,59 @@ +// Time: O(n) +// Space: O(n) + +// Hash solution. +class Solution { +public: + bool isReflected(vector>& points) { + if (points.empty()) { + return true; + } + unordered_map> groups_by_y; + int left = numeric_limits::max(); + int right = numeric_limits::min(); + for (const auto& p : points) { + groups_by_y[p.second].emplace(p.first); + left = min(left, p.first); + right = max(right, p.first); + } + const auto mid = left + right; + for (const auto& kvp : groups_by_y) { + for (const auto& x : kvp.second) { + if (kvp.second.count(mid - x) == 0) { + return false; + } + } + } + return true; + } +}; + +// Time: O(nlogn) +// Space: O(1) +// Two pointers solution. +class Solution2 { +public: + bool isReflected(vector>& points) { + if (points.empty()) { + return true; + } + sort(points.begin(), points.end()); + sort(points.begin(), points.begin() + distance(points.begin(), points.end()) / 2, + [](const pair& a, const pair& b) { + if (a.first == b.first) { + return a.second > b.second; + } + return a.first < b.first; + }); + + const auto mid = points.front().first + points.back().first; + for (int left = 0, right = points.size() - 1; left <= right; ++left, --right) { + if ((mid != points[left].first + points[right].first) || + (points[left].first != points[right].first && + points[left].second != points[right].second)) { + return false; + } + } + return true; + } +}; diff --git a/C++/linked-list-cycle-ii.cpp b/C++/linked-list-cycle-ii.cpp new file mode 100644 index 000000000..3acc2385a --- /dev/null +++ b/C++/linked-list-cycle-ii.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *detectCycle(ListNode *head) { + ListNode *slow = head, *fast = head; + + while (fast && fast->next) { + slow = slow->next, fast = fast->next->next; + if (slow == fast) { // There is a cycle. + slow = head; + // Both pointers advance at the same time. + while (slow != fast) { + slow = slow->next, fast = fast->next; + } + return slow; // slow is the begin of cycle. + } + } + return nullptr; // No cycle. + } +}; diff --git a/C++/linked-list-cycle.cpp b/C++/linked-list-cycle.cpp new file mode 100644 index 000000000..84d3a8383 --- /dev/null +++ b/C++/linked-list-cycle.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + bool hasCycle(ListNode *head) { + ListNode *slow = head, *fast = head; + + while (fast && fast->next) { + slow = slow->next, fast = fast->next->next; + if (slow == fast) { // There is a cycle. + return true; + } + } + return false; // No cycle. + } +}; diff --git a/C++/linked-list-random-node.cpp b/C++/linked-list-random-node.cpp new file mode 100644 index 000000000..9e5809495 --- /dev/null +++ b/C++/linked-list-random-node.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + /** @param head The linked list's head. Note that the head is guanranteed to be not null, so it contains at least one node. */ + Solution(ListNode* head) : head_(head) { + + } + + /** Returns a random node's value. */ + int getRandom() { + auto reservoir = -1; + auto n = 0; + for (auto curr = head_; curr; curr = curr->next) { + if (rand() % ++n == 0) { + reservoir = curr->val; + } + } + return reservoir; + } + +private: + ListNode *head_; +}; + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(head); + * int param_1 = obj.getRandom(); + */ + diff --git a/C++/logger-rate-limiter.cpp b/C++/logger-rate-limiter.cpp new file mode 100644 index 000000000..8872e6bad --- /dev/null +++ b/C++/logger-rate-limiter.cpp @@ -0,0 +1,57 @@ +// Time: O(1), amortized +// Space: O(k), k is the max number of printed messages in last 10 seconds + +class Logger { +public: + /** Initialize your data structure here. */ + Logger() { + + } + + /** Returns true if the message should be printed in the given timestamp, otherwise returns false. The timestamp is in seconds granularity. */ + bool shouldPrintMessage(int timestamp, string message) { + while (!dq_.empty() && dq_.front().first <= timestamp - 10) { + printed_.erase(dq_.front().second); + dq_.pop_front(); + } + if (printed_.count(message)) { + return false; + } + dq_.emplace_back(timestamp, message); + printed_.emplace(message); + return true; + } + +private: + deque> dq_; + unordered_set printed_; +}; + +// Time: O(1) +// Space: O(n), n is the number of total unique messages +class Logger2 { +public: + /** Initialize your data structure here. */ + Logger() { + + } + + /** Returns true if the message should be printed in the given timestamp, otherwise returns false. The timestamp is in seconds granularity. */ + bool shouldPrintMessage(int timestamp, string message) { + if (message_time_.count(message) && + timestamp < message_time_[message] + 10) { + return false; + } + message_time_[message] = timestamp; + return true; + } + +private: + unordered_map message_time_; +}; + +/** + * Your Logger object will be instantiated and called as such: + * Logger obj = new Logger(); + * bool param_1 = obj.shouldPrintMessage(timestamp,message); + */ diff --git a/C++/lonely-pixel-i.cpp b/C++/lonely-pixel-i.cpp new file mode 100644 index 000000000..709853593 --- /dev/null +++ b/C++/lonely-pixel-i.cpp @@ -0,0 +1,27 @@ +// Time: O(m * n) +// Space: O(m + n) + +class Solution { +public: + int findLonelyPixel(vector>& picture) { + vector rows = vector(picture.size()); + vector cols = vector(picture[0].size()); + + for (int i = 0; i < picture.size(); ++i) { + for (int j = 0; j < picture[0].size(); ++j) { + rows[i] += picture[i][j] == 'B'; + cols[j] += picture[i][j] == 'B'; + } + } + + int result = 0; + for (int i = 0; i < picture.size(); ++i) { + if (rows[i] == 1) { + for (int j = 0; j < picture[0].size() && rows[i] > 0; ++j) { + result += picture[i][j] == 'B' && cols[j] == 1; + } + } + } + return result; + } +}; diff --git a/C++/lonely-pixel-ii.cpp b/C++/lonely-pixel-ii.cpp new file mode 100644 index 000000000..08c23dd68 --- /dev/null +++ b/C++/lonely-pixel-ii.cpp @@ -0,0 +1,35 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + int findBlackPixel(vector>& picture, int N) { + vector rows = vector(picture.size()); + vector cols = vector(picture[0].size()); + + unordered_map lookup; + vector srows; + for (int i = 0; i < picture.size(); ++i) { + string s; + for (int j = 0; j < picture[0].size(); ++j) { + if (picture[i][j] == 'B') { + ++rows[i]; + ++cols[j]; + } + s.push_back(picture[i][j]); + } + ++lookup[s]; + srows.emplace_back(move(s)); + } + + int result = 0; + for (int i = 0; i < picture.size(); ++i) { + if (rows[i] == N && lookup[srows[i]] == N) { + for (int j = 0; j < picture[0].size(); ++j) { + result += picture[i][j] == 'B' && cols[j] == N; + } + } + } + return result; + } +}; diff --git a/C++/longest-absolute-file-path.cpp b/C++/longest-absolute-file-path.cpp new file mode 100644 index 000000000..aca011c53 --- /dev/null +++ b/C++/longest-absolute-file-path.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(d), d is the max depth of the paths + +class Solution { +public: + int lengthLongestPath(string input) { + input.push_back('\n'); + + size_t max_len = 0; + unordered_map path_len; + path_len[0] = 0; + + for (auto i = input.find("\n"), prev_i = 0ul; + i != string::npos; + prev_i = i + 1, i = input.find("\n", i + 1)) { + + const auto line = input.substr(prev_i, i - prev_i); + const auto name = line.substr(line.find_first_not_of("\t")); + const auto depth = line.length() - name.length(); + + if (name.find('.') != string::npos) { + max_len = max(max_len, path_len[depth] + name.length()); + } else { + path_len[depth + 1] = path_len[depth] + name.length() + 1; + } + } + return max_len; + } +}; diff --git a/C++/longest-common-prefix.cpp b/C++/longest-common-prefix.cpp new file mode 100644 index 000000000..aa362d047 --- /dev/null +++ b/C++/longest-common-prefix.cpp @@ -0,0 +1,20 @@ +// Time: O(n * k), k is the length of the common prefix +// Space: O(1) + +class Solution { +public: + string longestCommonPrefix(vector& strs) { + if (strs.empty()) { + return ""; + } + + for (int i = 0; i < strs[0].length(); ++i) { + for (const auto& str : strs) { + if (i >= str.length() || str[i] != strs[0][i]) { + return strs[0].substr(0, i); + } + } + } + return strs[0]; + } +}; diff --git a/C++/longest-consecutive-sequence.cpp b/C++/longest-consecutive-sequence.cpp new file mode 100644 index 000000000..253cc2c97 --- /dev/null +++ b/C++/longest-consecutive-sequence.cpp @@ -0,0 +1,58 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int longestConsecutive(vector& nums) { + // unprocessed_entries records the existence of each entry in num. + unordered_set unprocessed_entries; + for (const auto& num : nums) { + unprocessed_entries.emplace(num); + } + + int max_interval_size = 0; + while (!unprocessed_entries.empty()) { + int num = *unprocessed_entries.begin(); + unprocessed_entries.erase(num); + + // Finds the lower bound of the largest range containing a. + int lower_bound = num - 1; + while (unprocessed_entries.count(lower_bound)) { + unprocessed_entries.erase(lower_bound); + --lower_bound; + } + + // Finds the upper bound of the largest range containing a. + int upper_bound = num + 1; + while (unprocessed_entries.count(upper_bound)) { + unprocessed_entries.erase(upper_bound); + ++upper_bound; + } + max_interval_size = + max(max_interval_size, upper_bound - lower_bound - 1); + } + return max_interval_size; + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + int longestConsecutive(vector &nums) { + if (nums.empty()) { + return 0; + } + unordered_map hash; + int ans{1}; + for (const auto& i : nums) { + if (!hash[i]) { + hash[i] = 1; + int leftbound{hash[i - 1]}, rightbound{hash[i + 1]}; // Get neighbor info. + hash[i - leftbound] = hash[i + rightbound] = 1 + leftbound + rightbound; // Update left and right bound info. + ans = max(ans, 1 + leftbound + rightbound); + } + } + return ans; + } +}; diff --git a/C++/longest-continuous-increasing-subsequence.cpp b/C++/longest-continuous-increasing-subsequence.cpp new file mode 100644 index 000000000..02f6415b3 --- /dev/null +++ b/C++/longest-continuous-increasing-subsequence.cpp @@ -0,0 +1,17 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findLengthOfLCIS(vector& nums) { + int result = 0, count = 0; + for (int i = 0; i < nums.size(); ++i) { + if (i == 0 || nums[i - 1] < nums[i]) { + result = max(result, ++count); + } else { + count = 1; + } + } + return result; + } +}; diff --git a/C++/longest-harmonious-subsequence.cpp b/C++/longest-harmonious-subsequence.cpp new file mode 100644 index 000000000..d8a4f9e03 --- /dev/null +++ b/C++/longest-harmonious-subsequence.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int findLHS(vector& nums) { + unordered_map lookup; + auto result = 0; + for (const auto& num : nums) { + ++lookup[num]; + for (const auto& diff : {-1, 1}) { + if (lookup.count(num + diff)) { + result = max(result, lookup[num] + lookup[num + diff]); + } + } + } + return result; + } +}; diff --git a/C++/longest-increasing-path-in-a-matrix.cpp b/C++/longest-increasing-path-in-a-matrix.cpp new file mode 100644 index 000000000..a6e09e1ca --- /dev/null +++ b/C++/longest-increasing-path-in-a-matrix.cpp @@ -0,0 +1,46 @@ +// Time: O(m * n) +// Space: O(m * n) + +// DFS + Memorization solution. +class Solution { +public: + int longestIncreasingPath(vector>& matrix) { + if (matrix.empty()) { + return 0; + } + + int res = 0; + vector> max_lengths(matrix.size(), vector(matrix[0].size())); + for (int i = 0; i < matrix.size(); ++i) { + for (int j = 0; j < matrix[0].size(); ++j) { + res = max(res, longestpath(matrix, i, j, &max_lengths)); + } + } + + return res; + } + +private: + int longestpath(const vector>& matrix, const int i, const int j, + vector> *max_lengths) { + if ((*max_lengths)[i][j] > 0) { + return (*max_lengths)[i][j]; + } + + int max_depth = 0; + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + for (const auto& d : directions) { + const int x = i + d.first, y = j + d.second; + if (x >= 0 && x < matrix.size() && + y >= 0 && y < matrix[0].size() && + matrix[x][y] < matrix[i][j]) { + max_depth = max(max_depth, + longestpath(matrix, x, y, max_lengths)); + } + } + + (*max_lengths)[i][j] = max_depth + 1; + return (*max_lengths)[i][j]; + } +}; diff --git a/C++/longest-increasing-subsequence.cpp b/C++/longest-increasing-subsequence.cpp new file mode 100644 index 000000000..aff8c30bf --- /dev/null +++ b/C++/longest-increasing-subsequence.cpp @@ -0,0 +1,87 @@ +// Time: O(nlogn) +// Space: O(n) + +// Binary search solution with STL. +class Solution { +public: + int lengthOfLIS(vector& nums) { + vector LIS; + + for (const auto& num : nums) { + insert(&LIS, num); + } + + return LIS.size(); + } + +private: + void insert(vector *LIS, const int target) { + // Find the first index "left" which satisfies LIS[left] >= target + auto it = lower_bound(LIS->begin(), LIS->end(), target); + + // If not found, append the target. + if (it == LIS->end()) { + LIS->emplace_back(target); + } else { + *it = target; + } + } +}; + +// Binary search solution. +class Solution2 { +public: + int lengthOfLIS(vector& nums) { + vector LIS; + + for (const auto& num : nums) { + insert(&LIS, num); + } + + return LIS.size(); + } + +private: + void insert(vector *LIS, const int target) { + int left = 0, right = LIS->size() - 1; + auto comp = [](int x, int target) { return x >= target; }; + + // Find the first index "left" which satisfies LIS[left] >= target + while (left <= right) { + int mid = left + (right - left) / 2; + if (comp((*LIS)[mid], target)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + // If not found, append the target. + if (left == LIS->size()) { + LIS->emplace_back(target); + } else { + (*LIS)[left] = target; + } + } +}; + +// Time: O(n^2) +// Space: O(n) +// Traditional DP solution. +class Solution3 { +public: + int lengthOfLIS(vector& nums) { + const int n = nums.size(); + vector dp(n, 1); // dp[i]: the length of LIS ends with nums[i] + int res = 0; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + if (nums[j] < nums[i]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + res = max(res, dp[i]); + } + return res; + } +}; diff --git a/C++/longest-line-of-consecutive-one-in-matrix.cpp b/C++/longest-line-of-consecutive-one-in-matrix.cpp new file mode 100644 index 000000000..a59c4c433 --- /dev/null +++ b/C++/longest-line-of-consecutive-one-in-matrix.cpp @@ -0,0 +1,26 @@ +// Time: O(m * n) +// Space: O(n) + +class Solution { +public: + int longestLine(vector>& M) { + if (M.empty()) { + return 0; + } + int result = 0; + vector>> dp(2, vector>(M[0].size(), vector(4))); + for (int i = 0; i < M.size(); ++i) { + for (int j = 0; j < M[0].size(); ++j) { + dp[i % 2][j][0] = dp[i % 2][j][1] = dp[i % 2][j][2] = dp[i % 2][j][3] = 0; + if (M[i][j] == 1) { + dp[i % 2][j][0] = j > 0 ? dp[i % 2][j - 1][0] + 1 : 1; + dp[i % 2][j][1] = i > 0 ? dp[(i - 1) % 2][j][1] + 1 : 1; + dp[i % 2][j][2] = (i > 0 && j > 0) ? dp[(i - 1) % 2][j - 1][2] + 1 : 1; + dp[i % 2][j][3] = (i > 0 && j < M[0].size() - 1) ? dp[(i - 1) % 2][j + 1][3] + 1 : 1; + result = max(result, max(dp[i % 2][j][0], max(dp[i % 2][j][1], max(dp[i % 2][j][2], dp[i % 2][j][3])))); + } + } + } + return result; + } +}; diff --git a/C++/longest-palindrome.cpp b/C++/longest-palindrome.cpp new file mode 100644 index 000000000..019ceb2f8 --- /dev/null +++ b/C++/longest-palindrome.cpp @@ -0,0 +1,13 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int longestPalindrome(string s) { + int odds = 0; + for (auto c = 'A'; c <= 'z'; ++c) { + odds += count(s.cbegin(), s.cend(), c) & 1; + } + return s.length() - odds + (odds > 0); + } +}; diff --git a/C++/longest-palindromic-subsequence.cpp b/C++/longest-palindromic-subsequence.cpp new file mode 100644 index 000000000..852f3ff0c --- /dev/null +++ b/C++/longest-palindromic-subsequence.cpp @@ -0,0 +1,19 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + int longestPalindromeSubseq(string s) { + vector> dp(2, vector(s.size(), 1)); + for (int i = s.length() - 2; i >= 0; --i) { + for (int j = i + 1; j < s.length(); ++j) { + if (s[i] == s[j]) { + dp[i % 2][j] = (i + 1 <= j - 1) ? 2 + dp[(i + 1) % 2][j - 1] : 2; + } else { + dp[i % 2][j] = max(dp[(i + 1) % 2][j], dp[i % 2][j - 1]); + } + } + } + return dp[0][s.length() - 1]; + } +}; diff --git a/C++/longest-palindromic-substring.cpp b/C++/longest-palindromic-substring.cpp new file mode 100644 index 000000000..bd3851f2b --- /dev/null +++ b/C++/longest-palindromic-substring.cpp @@ -0,0 +1,53 @@ +// Time: O(n) +// Space: O(n) + +// Manacher's Algorithm. +class Solution { +public: + string longestPalindrome(string s) { + string T = preProcess(s); + const int n = T.length(); + vector P(n); + int C = 0, R = 0; + for (int i = 1; i < n - 1; ++i) { + int i_mirror = 2 * C - i; // equals to i' = C - (i-C) + + P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; + + // Attempt to expand palindrome centered at i + while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) { + ++P[i]; + } + + // If palindrome centered at i expands the past R, + // adjust center based on expanded palindrome. + if (i + P[i] > R) { + C = i; + R = i + P[i]; + } + } + + // Find the maximum element in P. + int max_i = 0; + for (int i = 1; i < n - 1; ++i) { + if (P[i] > P[max_i]) { + max_i = i; + } + } + + return s.substr((max_i - P[max_i]) / 2, P[max_i]); + } + +private: + string preProcess(const string& s) { + if (s.empty()) { + return "^$"; + } + string ret = "^"; + for (int i = 0; i < s.length(); ++i) { + ret += "#" + s.substr(i, 1); + } + ret += "#$"; + return ret; + } +}; diff --git a/C++/longest-repeating-character-replacement.cpp b/C++/longest-repeating-character-replacement.cpp new file mode 100644 index 000000000..78fe53af1 --- /dev/null +++ b/C++/longest-repeating-character-replacement.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int characterReplacement(string s, int k) { + vector cache(26); + + int i = 0, j = 0, times = k, res = 0; + for (; j < s.size(); ++j) { + ++cache[s[j] - 'A']; + if (s[j] != s[i]) { + --times; + if (times < 0) { + res = max(res, j - i); + while (i < j && times < 0) { + --cache[s[i++] - 'A']; + times = k - (j - i + 1 - cache[s[i] - 'A']); + } + } + } + } + return max(res, j - i + min(i, times)); + } +}; diff --git a/C++/longest-substring-with-at-least-k-repeating-characters.cpp b/C++/longest-substring-with-at-least-k-repeating-characters.cpp new file mode 100644 index 000000000..b2f107d16 --- /dev/null +++ b/C++/longest-substring-with-at-least-k-repeating-characters.cpp @@ -0,0 +1,40 @@ +// Time: O(26 * n) = O(n) +// Space: O(26) = O(1) + +// Recursive solution. +class Solution { +public: + int longestSubstring(string s, int k) { + return longestSubstringHelper(s, k, 0, s.size()); + } + +private: + int longestSubstringHelper(const string& s, int k, int start, int end) { + vector count(26); + for (int i = start; i < end; ++i) { + ++count[s[i] - 'a']; + } + + int max_len = 0; + for (int i = start; i < end;) { + while (i < end && count[s[i] - 'a'] < k) { + ++i; + } + if (i == end) { + break; + } + + int j = i; + while (j < end && count[s[j] - 'a'] >= k) { + ++j; + } + if (i == start && j == end) { + return end - start; + } + + max_len = max(max_len, longestSubstringHelper(s, k, i, j)); + i = j; + } + return max_len; + } +}; diff --git a/C++/longest-substring-with-at-most-k-distinct-characters.cpp b/C++/longest-substring-with-at-most-k-distinct-characters.cpp new file mode 100644 index 000000000..c9ce78198 --- /dev/null +++ b/C++/longest-substring-with-at-most-k-distinct-characters.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int lengthOfLongestSubstringKDistinct(string s, int k) { + int longest = 0, start = 0, distinct_count = 0; + array visited = {0}; + for (int i = 0; i < s.length(); ++i) { + if (visited[s[i]] == 0) { + ++distinct_count; + } + ++visited[s[i]]; + while (distinct_count > k) { + --visited[s[start]]; + if (visited[s[start]] == 0) { + --distinct_count; + } + ++start; + } + longest = max(longest, i - start + 1); + } + return longest; + } +}; diff --git a/C++/longest-substring-with-at-most-two-distinct-characters.cpp b/C++/longest-substring-with-at-most-two-distinct-characters.cpp new file mode 100644 index 000000000..d4eb2484c --- /dev/null +++ b/C++/longest-substring-with-at-most-two-distinct-characters.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int lengthOfLongestSubstringTwoDistinct(string s) { + const int k = 2; + int longest = 0, start = 0, distinct_count = 0; + array visited = {0}; + for (int i = 0; i < s.length(); ++i) { + if (visited[s[i]] == 0) { + ++distinct_count; + } + ++visited[s[i]]; + while (distinct_count > k) { + --visited[s[start]]; + if (visited[s[start]] == 0) { + --distinct_count; + } + ++start; + } + longest = max(longest, i - start + 1); + } + return longest; + } +}; diff --git a/C++/longest-substring-without-repeating-characters.cpp b/C++/longest-substring-without-repeating-characters.cpp new file mode 100644 index 000000000..95aa6b37b --- /dev/null +++ b/C++/longest-substring-without-repeating-characters.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int lengthOfLongestSubstring(string s) { + // Record the last occurrence of each char. + unordered_map last_occurrence; + size_t starting_idx = 0, ans = 0; + for (size_t i = 0; i < s.size(); ++i) { + auto it(last_occurrence.find(s[i])); + if (it == last_occurrence.cend()) { + last_occurrence.emplace_hint(it, s[i], i); + } else { // s[i] appeared before. Check its validity. + if (it->second >= starting_idx) { + ans = max(ans, i - starting_idx); + starting_idx = it->second + 1; + } + it->second = i; + } + } + ans = max(ans, s.size() - starting_idx); + return ans; + } +}; diff --git a/C++/longest-uncommon-subsequence-i.cpp b/C++/longest-uncommon-subsequence-i.cpp new file mode 100644 index 000000000..24b695e99 --- /dev/null +++ b/C++/longest-uncommon-subsequence-i.cpp @@ -0,0 +1,12 @@ +// Time: O(min(a, b)) +// Space: O(1) + +class Solution { +public: + int findLUSlength(string a, string b) { + if (a == b) { + return -1; + } + return max(a.length(), b.length()); + } +}; diff --git a/C++/longest-uncommon-subsequence-ii.cpp b/C++/longest-uncommon-subsequence-ii.cpp new file mode 100644 index 000000000..1641f6074 --- /dev/null +++ b/C++/longest-uncommon-subsequence-ii.cpp @@ -0,0 +1,34 @@ +// Time: O(l * n^2) +// Space: O(1) + +class Solution { +public: + int findLUSlength(vector& strs) { + sort(strs.begin(), strs.end(), + [](const string& a, const string& b) { return a.length() > b.length(); }); + for (int i = 0; i < strs.size(); ++i) { + bool all_of = true; + for (int j = 0; strs[j].length() >= strs[i].length() && j < strs.size(); ++j) { + if (i != j && isSubsequence(strs[i], strs[j])) { + all_of = false; + break; + } + } + if (all_of) { + return strs[i].length(); + } + } + return -1; + } + +private: + bool isSubsequence(const string& a, const string& b) { + int i = 0; + for (int j = 0; j < b.length() && i < a.length(); ++j) { + if (a[i] == b[j]) { + ++i; + } + } + return i == a.length(); + } +}; diff --git a/C++/longest-univalue-path.cpp b/C++/longest-univalue-path.cpp new file mode 100644 index 000000000..a4b652a43 --- /dev/null +++ b/C++/longest-univalue-path.cpp @@ -0,0 +1,33 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int longestUnivaluePath(TreeNode* root) { + auto result = 0; + dfs(root, &result); + return result; + } + +private: + int dfs(TreeNode *node, int *result) { + if (!node) { + return 0; + } + auto left = dfs(node->left, result); + auto right = dfs(node->right, result); + left = node->left && node->val == node->left->val ? left + 1 : 0; + right = node->right && node->val == node->right->val ? right + 1 : 0; + *result = max(*result, left + right); + return max(left, right); + } +}; diff --git a/C++/longest-valid-parentheses.cpp b/C++/longest-valid-parentheses.cpp new file mode 100644 index 000000000..d8c4d84b2 --- /dev/null +++ b/C++/longest-valid-parentheses.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int longestValidParentheses(string s) { + return max(length(s.begin(), s.end(), '('), length(s.rbegin(), s.rend(), ')')); + } + +private: + template + int length(T begin, T end, char c) { + int len = 0, depth = 0; + T start = begin; + for (T it = begin; it != end; ++it) { + if (*it == c) { + ++depth; + } else { + --depth; + if (depth < 0) { + start = next(it); + depth = 0; + } else { + if (depth == 0) { + len = max(len, static_cast(distance(start, it)) + 1); + } + } + } + } + return len; + } +}; diff --git a/C++/longest-word-in-dictionary-through-deleting.cpp b/C++/longest-word-in-dictionary-through-deleting.cpp new file mode 100644 index 000000000..f2e3f438d --- /dev/null +++ b/C++/longest-word-in-dictionary-through-deleting.cpp @@ -0,0 +1,25 @@ +// Time: O(dlogd) +// Space: O(1) + +class Solution { +public: + string findLongestWord(string s, vector& d) { + sort(d.begin(), d.end(), + [](const string& a, const string&b) { + return a.length() != b.length() ? a.length() > b.length() : a < b; + }); + + for (const auto& word : d) { + int i = 0; + for (const auto& c : s) { + if (i < word.length() && word[i] == c) { + ++i; + } + } + if (i == word.length()) { + return word; + } + } + return ""; + } +}; diff --git a/C++/longest-word-in-dictionary.cpp b/C++/longest-word-in-dictionary.cpp new file mode 100644 index 000000000..2d1baf26f --- /dev/null +++ b/C++/longest-word-in-dictionary.cpp @@ -0,0 +1,66 @@ +// Time: O(n), n is the total sum of the lengths of words +// Space: O(t), t is the number of nodes in trie + +class Solution { +public: + string longestWord(vector& words) { + TrieNode trie; + for (int i = 0; i < words.size(); ++i) { + trie.Insert(words[i], i); + } + + // DFS + stack stk; + for (const auto& node : trie.leaves) { + if (node) { + stk.emplace(node); + } + } + + string result; + while (!stk.empty()) { + const auto curr = stk.top(); stk.pop(); + if (curr->isString) { + const auto& word = words[curr->val]; + if (word.size() > result.size() || (word.size() == result.size() && word < result)) { + result = word; + } + for (const auto& node : curr->leaves) { + if (node) { + stk.emplace(node); + } + } + } + } + return result; + } + +private: + struct TrieNode { + bool isString; + int val; + vector leaves; + + TrieNode() : isString{false}, val{0}, leaves(26) {} + + void Insert(const string& s, const int i) { + auto* p = this; + for (const auto& c : s) { + if (!p->leaves[c - 'a']) { + p->leaves[c - 'a'] = new TrieNode; + } + p = p->leaves[c - 'a']; + } + p->isString = true; + p->val = i; + } + + ~TrieNode() { + for (auto& node : leaves) { + if (node) { + delete node; + } + } + } + }; +}; diff --git a/C++/longestConsecutive.cpp b/C++/longestConsecutive.cpp deleted file mode 100644 index 08a929e02..000000000 --- a/C++/longestConsecutive.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(n) - -class Solution { - public: - int longestConsecutive(vector &num) { - if (num.size() == 0) - return 0; - unordered_map hash; - int ans{1}; - for (auto &i: num) { - if (hash[i] != 0) { - continue; - } - hash[i] = 1; - int leftbound{hash[i - 1]}, rightbound{hash[i + 1]}; // get neighbor info - hash[i - leftbound] = hash[i + rightbound] = 1 + leftbound + rightbound; // update left and right bound info - ans = max(ans, 1 + leftbound + rightbound); - } - return ans; - } -}; diff --git a/C++/longestPalindrome.cpp b/C++/longestPalindrome.cpp deleted file mode 100644 index 51e4acc9b..000000000 --- a/C++/longestPalindrome.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(n) - -class Solution { - public: - // Manacher's Algorithm - string longestPalindrome(string s) { - string T = preProcess(s); - int n = T.length(); - vector P(n); - int C = 0, R = 0; - for (int i = 1; i < n-1; i++) { - int i_mirror = 2*C-i; // equals to i' = C - (i-C) - - P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0; - - // Attempt to expand palindrome centered at i - while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) - P[i]++; - - // If palindrome centered at i expand past R, - // adjust center based on expanded palindrome. - if (i + P[i] > R) { - C = i; - R = i + P[i]; - } - } - - // Find the maximum element in P. - int maxLen = 0; - int centerIndex = 0; - for (int i = 1; i < n-1; i++) { - if (P[i] > maxLen) { - maxLen = P[i]; - centerIndex = i; - } - } - - return s.substr((centerIndex - 1 - maxLen)/2, maxLen); - } - private: - string preProcess(string s) { - int n = s.length(); - if (n == 0) return "^$"; - string ret = "^"; - for (int i = 0; i < n; i++) - ret += "#" + s.substr(i, 1); - - ret += "#$"; - return ret; - } -}; diff --git a/C++/longestValidParentheses.cpp b/C++/longestValidParentheses.cpp deleted file mode 100644 index 9f18d84fb..000000000 --- a/C++/longestValidParentheses.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int longestValidParentheses(string s) { - int ans = 0; - - int depth = 0; - int last = -1; - for(int i = 0; i < s.length(); ++i) { - if(s[i] == '(') { - ++depth; - } - else { - --depth; - if(depth < 0) { - last = i; - depth = 0; - } - else { - if(depth == 0) - ans = max(ans, i - last); - } - } - } - - depth = 0; - last = s.size(); - for(int i = s.length() - 1; i >= 0; --i) { - if(s[i] == ')') { - ++depth; - } - else { - --depth; - if(depth < 0) { - last = i; - depth = 0; - } - else { - if(depth == 0) - ans = max(ans, last - i); - } - } - } - - return ans; - } -}; diff --git a/C++/lowest-common-ancestor-of-a-binary-search-tree.cpp b/C++/lowest-common-ancestor-of-a-binary-search-tree.cpp new file mode 100644 index 000000000..ef1f95021 --- /dev/null +++ b/C++/lowest-common-ancestor-of-a-binary-search-tree.cpp @@ -0,0 +1,27 @@ +// Time: O(h) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + auto s = min(p->val, q->val); + auto b = max(p->val, q->val); + + while (root->val < s || root->val > b) { + // Keep searching since root is outside of [s, b]. + root = s <= root->val ? root->left : root->right; + } + + // s <= root->val && root->val <= b. + return root; + } +}; diff --git a/C++/lowest-common-ancestor-of-a-binary-tree.cpp b/C++/lowest-common-ancestor-of-a-binary-tree.cpp new file mode 100644 index 000000000..d01235a99 --- /dev/null +++ b/C++/lowest-common-ancestor-of-a-binary-tree.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (!root || root == p || root == q) { + return root; + } + TreeNode *left = lowestCommonAncestor(root->left, p, q); + TreeNode *right = lowestCommonAncestor(root->right, p, q); + // 1. If the current subtree contains both p and q, + // return their LCA. + // 2. If only one of them is in that subtree, + // return that one of them. + // 3. If neither of them is in that subtree, + // return the node of that subtree. + return left ? (right ? root : left) : right; + } +}; diff --git a/C++/lru-cache.cpp b/C++/lru-cache.cpp new file mode 100644 index 000000000..bdc844863 --- /dev/null +++ b/C++/lru-cache.cpp @@ -0,0 +1,45 @@ +// Time: O(1), per operation. +// Space: O(k), k is the capacity of cache. + +#include + +class LRUCache { +public: + LRUCache(int capacity) : capa_(capacity) { + } + + int get(int key) { + if (map_.find(key) != map_.end()) { + // It key exists, update it. + const auto value = map_[key]->second; + update(key, value); + return value; + } else { + return -1; + } + } + + void put(int key, int value) { + // If cache is full while inserting, remove the last one. + if (map_.find(key) == map_.end() && list_.size() == capa_) { + auto del = list_.back(); list_.pop_back(); + map_.erase(del.first); + } + update(key, value); + } + +private: + list> list_; // key, value + unordered_map>::iterator> map_; // key, list iterator + int capa_; + + // Update (key, iterator of (key, value)) pair + void update(int key, int value) { + auto it = map_.find(key); + if (it != map_.end()) { + list_.erase(it->second); + } + list_.emplace_front(key, value); + map_[key] = list_.begin(); + } +}; diff --git a/C++/magical-string.cpp b/C++/magical-string.cpp new file mode 100644 index 000000000..90b95c430 --- /dev/null +++ b/C++/magical-string.cpp @@ -0,0 +1,13 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int magicalString(int n) { + string S = "122"; + for (int i = 2; S.length() < n; ++i) { + S += string(S[i] - '0', S.back() ^ 3); + } + return count(S.begin(), S.begin() + n, '1'); + } +}; diff --git a/C++/majority-element-ii.cpp b/C++/majority-element-ii.cpp new file mode 100644 index 000000000..93406d205 --- /dev/null +++ b/C++/majority-element-ii.cpp @@ -0,0 +1,51 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector majorityElement(vector& nums) { + int k = 3; + const int n = nums.size(); + unordered_map hash; + + for (const auto& i : nums) { + ++hash[i]; + // Detecting k items in hash, at least one of them must have exactly + // one in it. We will discard those k items by one for each. + // This action keeps the same mojority numbers in the remaining numbers. + // Because if x / n > 1 / k is true, then (x - 1) / (n - k) > 1 / k is also true. + if (hash.size() == k) { + auto it = hash.begin(); + while (it != hash.end()) { + if (--(it->second) == 0) { + hash.erase(it++); + } else { + ++it; + } + } + } + } + + // Resets hash for the following counting. + for (auto& it : hash) { + it.second = 0; + } + + // Counts the occurrence of each candidate integer. + for (const auto& i : nums) { + auto it = hash.find(i); + if (it != hash.end()) { + ++it->second; + } + } + + // Selects the integer which occurs > [n / k] times. + vector ret; + for (const pair& it : hash) { + if (it.second > n / k) { + ret.emplace_back(it.first); + } + } + return ret; + } +}; diff --git a/C++/majority-element.cpp b/C++/majority-element.cpp new file mode 100644 index 000000000..4d0d38cb8 --- /dev/null +++ b/C++/majority-element.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int majorityElement(vector& nums) { + int ans = nums[0], cnt = 1; + for (const auto& i : nums) { + if (i == ans) { + ++cnt; + } else { + --cnt; + if (cnt == 0) { + ans = i; + cnt = 1; + } + } + } + return ans; + } +}; diff --git a/C++/map-sum-pairs.cpp b/C++/map-sum-pairs.cpp new file mode 100644 index 000000000..3c3ee4aca --- /dev/null +++ b/C++/map-sum-pairs.cpp @@ -0,0 +1,79 @@ +// Time: O(n), n is the length of key +// Space: O(t), t is the number of nodes in trie + +class MapSum { +public: + /** Initialize your data structure here. */ + MapSum() { + + } + + void insert(string key, int val) { + trie_.Insert(key, val); + } + + int sum(string prefix) { + return trie_.GetCount(prefix); + } + +private: + struct TrieNode { + bool isString = false; + int count = 0; + int val = 0; + unordered_map leaves; + + void Insert(const string& s, const int val) { + const auto delta = val - GetVal(s); + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + p->leaves[c] = new TrieNode; + } + p = p->leaves[c]; + p->count += delta; + } + p->val = val; + p->isString = true; + } + + int GetVal(const string& s) const { + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + return 0; + } + p = p->leaves.at(c); + } + return p->isString ? p->val : 0; + } + + int GetCount(const string& s) const { + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + return 0; + } + p = p->leaves.at(c); + } + return p->count; + } + + ~TrieNode() { + for (auto& kv : leaves) { + if (kv.second) { + delete kv.second; + } + } + } + }; + TrieNode trie_; +}; + +/** + * Your MapSum object will be instantiated and called as such: + * MapSum obj = new MapSum(); + * obj.insert(key,val); + * int param_2 = obj.sum(prefix); + */ + diff --git a/C++/matchsticks-to-square.cpp b/C++/matchsticks-to-square.cpp new file mode 100644 index 000000000..565a4211c --- /dev/null +++ b/C++/matchsticks-to-square.cpp @@ -0,0 +1,40 @@ +// Time: O(n * s * 2^n), s is the number of subset of which sum equals to side length. +// Space: O(n * (2^n + s)) + +class Solution { +public: + bool makesquare(vector& nums) { + int sum = accumulate(nums.begin(), nums.end(), 0); + if (sum % 4) { + return false; + } + + const auto side_len = sum / 4; + const auto all = (1 << nums.size()) - 1; + + vector used_subsets; + vector valid_half_subsets(1 << nums.size()); + + for (int subset = 0; subset <= all; ++subset) { + int subset_sum = 0; + for (int i = 0; i < nums.size(); ++i) { + if (subset & (1 << i)) { + subset_sum += nums[i]; + } + } + if (subset_sum == side_len) { + for (const auto& used_subset : used_subsets) { + if ((used_subset & subset) == 0) { + int valid_half_subset = used_subset | subset; + valid_half_subsets[valid_half_subset] = true; + if (valid_half_subsets[all ^ valid_half_subset]) { + return true; + } + } + } + used_subsets.emplace_back(subset); + } + } + return false; + } +}; diff --git a/C++/max-area-of-island.cpp b/C++/max-area-of-island.cpp new file mode 100644 index 000000000..da9e5aa59 --- /dev/null +++ b/C++/max-area-of-island.cpp @@ -0,0 +1,35 @@ +// Time: O(m * n) +// Space: O(m * n), the max depth of dfs may be m * n + +class Solution { +public: + int maxAreaOfIsland(vector>& grid) { + int result = 0; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + int area = 0; + if (dfs(i, j, &grid, &area)) { + result = max(result, area); + } + } + } + return result; + } + +private: + bool dfs(const int i, const int j, vector> *grid, int *area) { + static const vector> directions{{-1, 0}, { 1, 0}, + { 0, 1}, { 0, -1}}; + if (i < 0 || i >= grid->size() || + j < 0 || j >= (*grid)[0].size() || + (*grid)[i][j] <= 0) { + return false; + } + (*grid)[i][j] *= -1; + ++(*area); + for (const auto& d : directions) { + dfs(i + d.first, j + d.second, grid, area); + } + return true; + } +}; diff --git a/C++/max-consecutive-ones-ii.cpp b/C++/max-consecutive-ones-ii.cpp new file mode 100644 index 000000000..289e662d5 --- /dev/null +++ b/C++/max-consecutive-ones-ii.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int result = 0, prev = 0, curr = 0; + for (const auto& n : nums) { + if (n == 0) { + result = max(result, prev + curr + 1); + prev = curr; + curr = 0; + } else { + ++curr; + } + } + return min(max(result, prev + curr + 1), static_cast(nums.size())); + } +}; diff --git a/C++/max-consecutive-ones.cpp b/C++/max-consecutive-ones.cpp new file mode 100644 index 000000000..5510733e3 --- /dev/null +++ b/C++/max-consecutive-ones.cpp @@ -0,0 +1,14 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int result = 0, local_max = 0; + for (const auto& n : nums) { + local_max = n ? local_max + 1 : 0; + result = max(result, local_max); + } + return result; + } +}; diff --git a/C++/max-points-on-a-line.cpp b/C++/max-points-on-a-line.cpp new file mode 100644 index 000000000..816321f52 --- /dev/null +++ b/C++/max-points-on-a-line.cpp @@ -0,0 +1,44 @@ +// Time: O(n^2) +// Space: O(n) + +/** + * Definition for a point. + * struct Point { + * int x; + * int y; + * Point() : x(0), y(0) {} + * Point(int a, int b) : x(a), y(b) {} + * }; + */ +class Solution { +public: + int maxPoints(vector& points) { + int max_points = 0; + for (int i = 0; i < points.size(); ++i) { + unordered_map slope_count; + const auto& start = points[i]; + int same = 1; + + for (int j = i + 1; j < points.size(); ++j) { + const auto& end = points[j]; + if (start.x == end.x && start.y == end.y) { + ++same; + } else { + auto slope = numeric_limits::max(); + if (start.x - end.x != 0) { + slope = (start.y - end.y) * 1.0 / (start.x - end.x); + } + ++slope_count[slope]; + } + } + + int current_max = same; + for (const auto& kvp : slope_count) { + current_max = max(current_max, kvp.second + same); + } + max_points = max(max_points, current_max); + } + + return max_points; + } +}; diff --git a/C++/max-stack.cpp b/C++/max-stack.cpp new file mode 100644 index 000000000..d62fdf41e --- /dev/null +++ b/C++/max-stack.cpp @@ -0,0 +1,63 @@ +// Time: push: O(logn) +// pop: O(logn) +// popMax: O(logn) +// top: O(1) +// peekMax: O(1) +// Space: O(n), n is the number of values in the current stack + +class MaxStack { +public: + /** initialize your data structure here. */ + MaxStack() { + + } + + void push(int x) { + const auto idx = idx_to_val_.empty() ? 0 : idx_to_val_.cbegin()->first + 1; + idx_to_val_[idx] = x; + val_to_idxs_[x].emplace_back(idx); + } + + int pop() { + const auto val = idx_to_val_.cbegin()->second; + remove(val); + return val; + } + + int top() { + return idx_to_val_.cbegin()->second; + } + + int peekMax() { + return val_to_idxs_.cbegin()->first; + } + + int popMax() { + const auto val = val_to_idxs_.cbegin()->first; + remove(val); + return val; + } + +private: + void remove(const int val) { + const auto idx = val_to_idxs_[val].back(); + val_to_idxs_[val].pop_back(); + if (val_to_idxs_[val].empty()) { + val_to_idxs_.erase(val); + } + idx_to_val_.erase(idx); + } + + map> idx_to_val_; + map, greater> val_to_idxs_; +}; + +/** + * Your MaxStack object will be instantiated and called as such: + * MaxStack obj = new MaxStack(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.top(); + * int param_4 = obj.peekMax(); + * int param_5 = obj.popMax(); + */ diff --git a/C++/max-sum-of-sub-matrix-no-larger-than-k.cpp b/C++/max-sum-of-sub-matrix-no-larger-than-k.cpp new file mode 100644 index 000000000..1fd294eca --- /dev/null +++ b/C++/max-sum-of-sub-matrix-no-larger-than-k.cpp @@ -0,0 +1,39 @@ +// Time: O(min(m, n)^2 * max(m, n) * log(max(m, n))) +// Space: O(max(m, n)) + +class Solution { +public: + int maxSumSubmatrix(vector>& matrix, int k) { + if (matrix.empty()) { + return 0; + } + + const int m = min(matrix.size(), matrix[0].size()); + const int n = max(matrix.size(), matrix[0].size()); + int result = numeric_limits::min(); + + for (int i = 0; i < m; ++i) { + vector sums(n, 0); + for (int j = i; j < m; ++j) { + for (int l = 0; l < n; ++l) { + sums[l] += (m == matrix.size()) ? matrix[j][l] : matrix[l][j]; + } + + // Find the max subarray no more than K. + set accu_sum_set; + accu_sum_set.emplace(0); + int accu_sum = 0; + for (int sum : sums) { + accu_sum += sum; + auto it = accu_sum_set.lower_bound(accu_sum - k); + if (it != accu_sum_set.end()) { + result = max(result, accu_sum - *it); + } + accu_sum_set.emplace(accu_sum); + } + } + } + + return result; + } +}; diff --git a/C++/maxArea.cpp b/C++/maxArea.cpp deleted file mode 100644 index a6c8fb46a..000000000 --- a/C++/maxArea.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int maxArea(vector &height) { - int start = 0, end = height.size() - 1, ans = 0; - - while(start < end) { - if(height[start] <= height[end]) { - ans = max(ans, height[start] * (end - start)); - start++; - } - if(height[start] > height[end]) { - ans = max(ans, height[end] * (end - start)); - end--; - } - } - return ans; - } -}; diff --git a/C++/maxProfitI.cpp b/C++/maxProfitI.cpp deleted file mode 100644 index c7d4dea53..000000000 --- a/C++/maxProfitI.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int maxProfit(vector &prices) { - const int n = prices.size(); - - if(n < 2) - return 0; - - // Greedy Algorithm - int ans = 0; - for(int i = 1, valley = prices[0]; i < n; ++i) { - ans = max(ans, prices[i] - valley); - valley = min(valley, prices[i]); - } - - return ans; - } -}; diff --git a/C++/maximal-rectangle.cpp b/C++/maximal-rectangle.cpp new file mode 100644 index 000000000..1f127f593 --- /dev/null +++ b/C++/maximal-rectangle.cpp @@ -0,0 +1,88 @@ +// Time: O(m * n) +// Space: O(n) + +// Ascending stack solution. +class Solution { +public: + int maximalRectangle(vector > &matrix) { + if (matrix.empty() || matrix[0].empty()) { + return 0; + } + + int res = 0; + vector height(matrix[0].size(), 0); + for (int i = 0; i < matrix.size(); ++i) { + for (int j = 0; j < matrix[0].size(); ++j) { + height[j] = matrix[i][j] == '1' ? height[j] + 1 : 0; + } + res = max(res, largestRectangleArea(height)); + } + + return res; + } + +private: + int largestRectangleArea(const vector &height) { + stack increasing_height; + int max_area = 0; + + for (int i = 0; i <= height.size();) { + if (increasing_height.empty() || + (i < height.size() && height[i] > height[increasing_height.top()])) { + increasing_height.emplace(i); + ++i; + } else { + auto h = height[increasing_height.top()]; + increasing_height.pop(); + auto left = increasing_height.empty() ? -1 : increasing_height.top(); + max_area = max(max_area, h * (i - left - 1)); + } + } + + return max_area; + } +}; + +// Time: O(m * n) +// Space: O(n) +// DP solution. +class Solution2 { +public: + int maximalRectangle(vector > &matrix) { + if (matrix.empty()) { + return 0; + } + + const int m = matrix.size(); + const int n = matrix.front().size(); + int res = 0; + vector H(n, 0); // Height of all ones rectangle include matrix[i][j]. + vector L(n, 0); // Left closed bound of all ones rectangle include matrix[i][j]. + vector R(n, n); // Right open bound of all ones rectangle include matrix[i][j]. + + for (int i = 0; i < m; ++i) { + int left = 0, right = n; + for (int j = 0; j < n; ++j) { + if (matrix[i][j] == '1') { + ++H[j]; // Update height. + L[j] = max(L[j], left); // Update left bound. + } else { + left = j + 1; + H[j] = L[j] = 0; + R[j] = n; + } + } + + for (int j = n - 1; j >= 0; --j) { + if (matrix[i][j] == '1') { + R[j] = min(R[j], right); // Update right bound. + res = max(res, H[j] * (R[j] - L[j])); + } else { + right = j; + } + } + } + + return res; + } +}; diff --git a/C++/maximal-square.cpp b/C++/maximal-square.cpp new file mode 100644 index 000000000..8fdafb1a0 --- /dev/null +++ b/C++/maximal-square.cpp @@ -0,0 +1,115 @@ +// Time: O(n^2) +// Space: O(n) + +// DP with rolling window. +class Solution { +public: + int maximalSquare(vector>& A) { + if (A.empty()) { + return 0; + } + const int m = A.size(), n = A[0].size(); + vector> size(2, vector(n, 0)); + int max_size = 0; + + for (int j = 0; j < n; ++j) { + size[0][j] = A[0][j] - '0'; + max_size = max(max_size, size[0][j]); + } + for (int i = 1; i < m; ++i) { + size[i % 2][0] = A[i][0] - '0'; + for (int j = 1; j < n; ++j) { + if (A[i][j] == '1') { + size[i % 2][j] = min(size[i % 2][j - 1], + min(size[(i - 1) % 2][j], + size[(i - 1) % 2][j - 1])) + 1; + max_size = max(max_size, size[i % 2][j]); + } else { + size[i % 2][j] = 0; + } + } + } + return max_size * max_size; + } +}; + +// Time: O(n^2) +// Space: O(n^2) +// DP. +class Solution2 { +public: + int maximalSquare(vector>& A) { + if (A.empty()) { + return 0; + } + const int m = A.size(), n = A[0].size(); + vector> size(m, vector(n, 0)); + int max_size = 0; + + for (int j = 0; j < n; ++j) { + size[0][j] = A[0][j] - '0'; + max_size = max(max_size, size[0][j]); + } + for (int i = 1; i < m; ++i) { + size[i][0] = A[i][0] - '0'; + for (int j = 1; j < n; ++j) { + if (A[i][j] == '1') { + size[i][j] = min(size[i][j - 1], + min(size[i - 1][j], + size[i - 1][j - 1])) + 1; + max_size = max(max_size, size[i][j]); + } else { + size[i][j] = 0; + } + } + } + return max_size * max_size; + } +}; + +// Time: O(n^2) +// Space: O(n^2) +// DP. +class Solution3 { +public: + struct MaxHW { + int h, w; + }; + + int maximalSquare(vector>& A) { + if (A.empty()) { + return 0; + } + + // DP table stores (h, w) for each (i, j). + vector> table(A.size(), vector(A.front().size())); + for (int i = A.size() - 1; i >= 0; --i) { + for (int j = A[i].size() - 1; j >= 0; --j) { + // Find the largest h such that (i, j) to (i + h - 1, j) are feasible. + // Find the largest w such that (i, j) to (i, j + w - 1) are feasible. + table[i][j] = A[i][j] == '1' + ? MaxHW{i + 1 < A.size() ? table[i + 1][j].h + 1 : 1, + j + 1 < A[i].size() ? table[i][j + 1].w + 1 : 1} + : MaxHW{0, 0}; + } + } + + // A table stores the length of largest square for each (i, j). + vector> s(A.size(), vector(A.front().size(), 0)); + int max_square_area = 0; + for (int i = A.size() - 1; i >= 0; --i) { + for (int j = A[i].size() - 1; j >= 0; --j) { + int side = min(table[i][j].h, table[i][j].w); + if (A[i][j]) { + // Get the length of largest square with bottom-left corner (i, j). + if (i + 1 < A.size() && j + 1 < A[i + 1].size()) { + side = min(s[i + 1][j + 1] + 1, side); + } + s[i][j] = side; + max_square_area = max(max_square_area, side * side); + } + } + } + return max_square_area; + } +}; diff --git a/C++/maximalRectangle.cpp b/C++/maximalRectangle.cpp deleted file mode 100644 index 829905865..000000000 --- a/C++/maximalRectangle.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Time Complexity: O(m * n) -// Space Complexity: O(n) - -class Solution { - public: - int maximalRectangle(vector > &matrix) { - if(matrix.empty()) - return 0; - - const int m = matrix.size(); - const int n = matrix.front().size(); - - int ans = 0; - - vector H(n, 0); // height of all ones rectangle include matrix[i][j] - vector L(n, 0); // left closed bound of all ones rectangle include matrix[i][j] - vector R(n, n); // right open bound of all onces rectangle include matrix[i][j] - - for(int i = 0; i < m; ++i) { - int left = 0, right = n; - for(int j = 0; j < n; ++j) { - if(matrix[i][j] == '1') { - ++H[j]; // update height - L[j] = max(L[j], left); // update left bound - } - else { - left = j + 1; - H[j] = L[j] = 0; - R[j] = n; - } - } - - for(int j = n - 1; j >= 0; --j) { - if(matrix[i][j] == '1') { - R[j] = min(R[j], right); // update right bound - ans = max(ans, H[j] * (R[j] - L[j])); - } - else { - right = j; - } - } - } - - return ans; - } -}; diff --git a/C++/maximum-average-subarray-i.cpp b/C++/maximum-average-subarray-i.cpp new file mode 100644 index 000000000..4407e3d1f --- /dev/null +++ b/C++/maximum-average-subarray-i.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + double findMaxAverage(vector& nums, int k) { + double sum = 0; + for (int i = 0; i < k; ++i) { + sum += nums[i]; + } + double result = sum; + for (int i = k; i < nums.size(); ++i) { + sum += nums[i] - nums[i-k]; + result = max(result, sum); + } + return result / k; + } +}; + diff --git a/C++/maximum-average-subarray-ii.cpp b/C++/maximum-average-subarray-ii.cpp new file mode 100644 index 000000000..3d8d658e8 --- /dev/null +++ b/C++/maximum-average-subarray-ii.cpp @@ -0,0 +1,74 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + double findMaxAverage(vector& nums, int k) { + double left = *min_element(nums.begin(), nums.end()); + double delta = numeric_limits::max(); + while (delta > 1e-5) { + delta = getDelta(left, nums, k); + left += delta; + } + return left; + } + +private: + double getDelta(double avg, const vector& nums, int k) { + vector accu(nums.size() + 1); + int minval_pos = -1; + double delta = 0.0; + for (int i = 0; i < nums.size(); ++i) { + accu[i + 1] = nums[i] + accu[i] - avg; + if (i >= k - 1) { + if (minval_pos == -1 || accu[i - k + 1] < accu[minval_pos]) { + minval_pos = i - k + 1; + } + if (accu[i+1] - accu[minval_pos] >= 0) { + delta = max(delta, (accu[i + 1] - accu[minval_pos]) / (i + 1 - minval_pos)); + } + } + } + return delta; + } +}; + + +// Time: O(nlogm), m is (max_val - min_val) +// Space: O(1) +class Solution2 { +public: + double findMaxAverage(vector& nums, int k) { + double left = *min_element(nums.begin(), nums.end()); + double right = *max_element(nums.begin(), nums.end()); + while (right - left > 1e-5) { + double mid = left + (right - left) / 2; + if (isMidLargerOrEqualToTarget(mid, nums, k)) { + right = mid; + } else { + left = mid; + } + } + return left; + } + +private: + bool isMidLargerOrEqualToTarget(double mid, const vector& nums, int k) { + double sum = 0, prev = 0, min_sum = 0; + for (int i = 0; i < k; ++i) { + sum += nums[i] - mid; + } + if (sum > 0) { + return false; + } + for (int i = k; i < nums.size(); ++i) { + sum += nums[i] - mid; + prev += nums[i - k] - mid; + min_sum = min(prev, min_sum); + if (sum > min_sum) { + return false; + } + } + return true; + } +}; \ No newline at end of file diff --git a/C++/maximum-binary-tree.cpp b/C++/maximum-binary-tree.cpp new file mode 100644 index 000000000..2b275d427 --- /dev/null +++ b/C++/maximum-binary-tree.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* constructMaximumBinaryTree(vector& nums) { + // https://github.com/kamyu104/LintCode/blob/master/C++/max-tree.cpp + vector nodeStack; + for (int i = 0; i < nums.size(); ++i) { + auto node = new TreeNode(nums[i]); + while (!nodeStack.empty() && nums[i] > nodeStack.back()->val) { + node->left = nodeStack.back(); + nodeStack.pop_back(); + } + if (!nodeStack.empty()) { + nodeStack.back()->right = node; + } + nodeStack.emplace_back(node); + } + return nodeStack.front(); + } +}; diff --git a/C++/maxDepth.cpp b/C++/maximum-depth-of-binary-tree.cpp similarity index 51% rename from C++/maxDepth.cpp rename to C++/maximum-depth-of-binary-tree.cpp index df822474a..23c2cdc8d 100644 --- a/C++/maxDepth.cpp +++ b/C++/maximum-depth-of-binary-tree.cpp @@ -1,5 +1,8 @@ +// Time: O(n) +// Space: O(h) + /** - * Definition for binary tree + * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; @@ -9,9 +12,10 @@ */ class Solution { public: - int maxDepth(TreeNode *root) { - if(!root) + int maxDepth(TreeNode* root) { + if (!root) { return 0; - return max(maxDepth(root->left), maxDepth(root->right))+1; + } + return max(maxDepth(root->left), maxDepth(root->right)) + 1; } }; diff --git a/C++/maximum-distance-in-arrays.cpp b/C++/maximum-distance-in-arrays.cpp new file mode 100644 index 000000000..f5af49463 --- /dev/null +++ b/C++/maximum-distance-in-arrays.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maxDistance(vector>& arrays) { + int result = 0; + int min_val = arrays[0].front(), max_val = arrays[0].back(); + for (int i = 1; i < arrays.size(); ++i) { + result = max(result, + max(max_val - arrays[i].front(), + arrays[i].back() - min_val)); + min_val = min(min_val, arrays[i].front()); + max_val = max(max_val, arrays[i].back()); + } + return result; + } +}; + diff --git a/C++/maximum-gap.cpp b/C++/maximum-gap.cpp new file mode 100644 index 000000000..07d005c73 --- /dev/null +++ b/C++/maximum-gap.cpp @@ -0,0 +1,92 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + struct Bucket { + int max = numeric_limits::min(); + int min = numeric_limits::max(); + }; + + int maximumGap(vector& nums) { + if (nums.size() < 2) { + return 0; + } + + // Init bucket. + int max_val = *max_element(nums.cbegin(), nums.cend()); + int min_val = *min_element(nums.cbegin(), nums.cend()); + int gap = max(1, static_cast((max_val - min_val) / + (nums.size() - 1))); + vector buckets((max_val - min_val) / gap + 1); + + // Find the bucket where the n should be put. + for (const auto& n : nums) { + // min_val / max_val is in the first / last bucket. + if (n == max_val || n == min_val) { + continue; + } + int i = (n - min_val) / gap; + buckets[i].min = min(buckets[i].min, n); + buckets[i].max = max(buckets[i].max, n); + } + + // Maximum gap should not be smaller than any gap inside the bucket. + // i.e. max_gap >= (max_val - min_val) / (count - 1) + // Thus, only count each bucket gap between the first and the last bucket. + int max_gap = 0, pre_bucket_max = min_val; + for (const auto& bucket : buckets) { + if (bucket.min != numeric_limits::max()) { + max_gap = max(max_gap, bucket.min - pre_bucket_max); + pre_bucket_max = bucket.max; + } + } + // Count the last bucket. + max_gap = max(max_gap, max_val - pre_bucket_max); + + return max_gap; + } +}; + +// Time: O(nlogn) +// Space: O(n) +class Solution2 { +public: + int maximumGap(vector& nums) { + if (nums.size() < 2) { + return 0; + } + + // Init bucket. + int max_val = *max_element(nums.cbegin(), nums.cend()); + int min_val = *min_element(nums.cbegin(), nums.cend()); + int gap = max(1, static_cast((max_val - min_val) / + (nums.size() - 1))); + map> bucket; + using ValueType = enum {MIN, MAX}; + + // Find the bucket where the n should be put. + for (const auto& n : nums) { + // min_val / max_val is in the first / last bucket. + if (n == max_val || n == min_val) { + continue ; + } + int i = (n - min_val) / gap; + bucket[i][MIN] = min(!bucket[i][MIN] ? numeric_limits::max() : + bucket[i][MIN], n); + bucket[i][MAX] = max(!bucket[i][MAX] ? numeric_limits::min() : + bucket[i][MAX], n); + } + + // Count each bucket gap between the first and the last bucket. + int max_gap = 0, pre_bucket_max = min_val; + for (auto& kvp : bucket) { + max_gap = max(max_gap, kvp.second[MIN] - pre_bucket_max); + pre_bucket_max = (kvp.second)[MAX]; + } + // Count the last bucket. + max_gap = max(max_gap, max_val - pre_bucket_max); + + return max_gap; + } +}; diff --git a/C++/maximum-length-of-pair-chain.cpp b/C++/maximum-length-of-pair-chain.cpp new file mode 100644 index 000000000..e834b846e --- /dev/null +++ b/C++/maximum-length-of-pair-chain.cpp @@ -0,0 +1,21 @@ +// Time: O(nlogn) +// Space: O(1) + +class Solution { +public: + int findLongestChain(vector>& pairs) { + sort(pairs.begin(), pairs.end(), + [](const vector& a, const vector& b) { + return a[1] < b[1]; + }); + int cnt = 0; + for (int i = 0, j = 0; j < pairs.size(); ++j) { + if (j == 0 || pairs[i][1] < pairs[j][0]) { + ++cnt; + i = j; + } + } + return cnt; + } +}; + diff --git a/C++/maximum-length-of-repeated-subarray.cpp b/C++/maximum-length-of-repeated-subarray.cpp new file mode 100644 index 000000000..2264817f8 --- /dev/null +++ b/C++/maximum-length-of-repeated-subarray.cpp @@ -0,0 +1,101 @@ +// Time: O(m * n) +// Space: O(min(m, n)) + +// dp solution (99 ms) +class Solution { +public: + int findLength(vector& A, vector& B) { + if (A.size() < B.size()) { + return findLength(B, A); + } + int result = 0; + vector> dp(2, vector(B.size() + 1)); + for (int i = 0; i < A.size(); ++i) { + for (int j = 0; j < B.size(); ++j) { + if (A[i] == B[j]) { + dp[(i + 1) % 2][j + 1] = dp[i % 2][j] + 1; + result = max(result, dp[(i + 1) % 2][j + 1]); + } else { + dp[(i + 1) % 2][j + 1] = 0; + } + } + } + return result; + } +}; + + +// Time: O(m * n * log(min(m, n))) +// Space: O(min(m, n)) +// Binary search + rolling hash solution (36 ms) +class Solution2 { +public: + int findLength(vector& A, vector& B) { + if (A.size() > B.size()) { + return findLength(B, A); + } + int left = 0, right = min(A.size(), B.size()) + 1; + while (left < right) { + const auto mid = left + (right-left) / 2; + if (!check(mid, A, B)) { // find the min idx such that check(idx) == false + right = mid; + } else { + left = mid + 1; + } + } + return left - 1; + } + +private: + bool check(const int guess, const vector& A, const vector& B) { + unordered_map> hashes; + int i = 0; + for (const auto& hash_a : rolling_hashes(A, guess)) { + hashes[hash_a].emplace_back(i++); + } + int j = 0; + for (const auto& hash_b : rolling_hashes(B, guess)) { + for (const auto& i : hashes[hash_b]) { + if (equal(A.begin() + i, A.begin() + i + guess, B.begin() + j)) { + return true; + } + } + ++j; + } + return false; + } + + vector rolling_hashes(const vector& source, const int length) { + static const uint64_t M = 1000000007; + static const uint64_t p = 113; + static const uint64_t p_inv = pow(p, M - 2, M); + vector result(source.size() - length + 1); + uint64_t hash = 0, power = 1; + if (length == 0) { + return result; + } + for (int i = 0; i < source.size(); ++i) { + hash = (hash + source[i] * power) % M; + if (i < length - 1) { + power = (power * p) % M; + } else { + result[i - (length - 1)] = hash; + hash = (hash - source[i - (length - 1)]) * p_inv % M; + } + } + return result; + } + + uint64_t pow(uint64_t a,uint64_t b, uint64_t m) { + a %= m; + uint64_t result = 1; + while (b) { + if (b & 1) { + result = (result * a) % m; + } + a = (a * a) % m; + b >>= 1; + } + return result; + } +}; diff --git a/C++/maximum-product-of-three-numbers.cpp b/C++/maximum-product-of-three-numbers.cpp new file mode 100644 index 000000000..57dc25757 --- /dev/null +++ b/C++/maximum-product-of-three-numbers.cpp @@ -0,0 +1,33 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maximumProduct(vector& nums) { + auto min1 = numeric_limits::max(); + auto min2 = numeric_limits::max(); + auto max1 = numeric_limits::min(); + auto max2 = numeric_limits::min(); + auto max3 = numeric_limits::min(); + for (const auto& n: nums) { + if (n <= min1) { + min2 = min1; + min1 = n; + } else if (n <= min2) { + min2 = n; + } + if (n >= max1) { + max3 = max2; + max2 = max1; + max1 = n; + } else if (n >= max2) { + max3 = max2; + max2 = n; + } else if (n >= max3) { + max3 = n; + } + } + return max(min1 * min2 * max1, max1 * max2 * max3); + } +}; + diff --git a/C++/maximum-product-of-word-lengths.cpp b/C++/maximum-product-of-word-lengths.cpp new file mode 100644 index 000000000..bad7e7817 --- /dev/null +++ b/C++/maximum-product-of-word-lengths.cpp @@ -0,0 +1,65 @@ +// Time: O(n) ~ O(n^2) +// Space: O(n) + +// Counting Sort + Pruning + Bit Manipulation +class Solution { +public: + int maxProduct(vector& words) { + words = counting_sort(words); + vector bits(words.size()); + for (int i = 0; i < words.size(); ++i) { + for (const auto& c : words[i]) { + bits[i] |= (1 << (c - 'a')); + } + } + int max_product = 0; + for (int i = 0; i + 1 < words.size() && pow(words[i].length(), 2) > max_product; ++i) { + for (int j = i + 1; j < words.size() && words[i].length() * words[j].length() > max_product; ++j) { + if (!(bits[i] & bits[j])) { + max_product = words[i].length() * words[j].length(); + } + } + } + return max_product; + } + + vector counting_sort(const vector& words) { + const int k = 1000; // k is max length of words in the dictionary + vector> buckets(k); + for (const auto& word : words) { + buckets[word.length()].emplace_back(word); + } + vector res; + for (int i = k - 1; i >= 0; --i) { + if (!buckets[i].empty()) { + move(buckets[i].begin(), buckets[i].end(), back_inserter(res)); + } + } + return res; + } +}; + +// Time: O(nlogn) ~ O(n^2) +// Space: O(n) +// Sorting + Pruning + Bit Manipulation +class Solution2 { +public: + int maxProduct(vector& words) { + sort(words.begin(), words.end(), [](const string& a, const string& b) { return a.length() > b.length(); }); + vector bits(words.size()); + for (int i = 0; i < words.size(); ++i) { + for (const auto& c : words[i]) { + bits[i] |= (1 << (c - 'a')); + } + } + int max_product = 0; + for (int i = 0; i + 1 < words.size() && pow(words[i].length(), 2) > max_product; ++i) { + for (int j = i + 1; j < words.size() && words[i].length() * words[j].length() > max_product; ++j) { + if (!(bits[i] & bits[j])) { + max_product = words[i].length() * words[j].length(); + } + } + } + return max_product; + } +}; diff --git a/C++/maximum-size-subarray-sum-equals-k.cpp b/C++/maximum-size-subarray-sum-equals-k.cpp new file mode 100644 index 000000000..9784071ef --- /dev/null +++ b/C++/maximum-size-subarray-sum-equals-k.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int maxSubArrayLen(vector& nums, int k) { + unordered_map sums; + int cur_sum = 0, max_len = 0; + for (int i = 0; i < nums.size(); ++i) { + cur_sum += nums[i]; + if (cur_sum == k) { + max_len = i + 1; + } else if (sums.find(cur_sum - k) != sums.end()) { + max_len = max(max_len, i - sums[cur_sum - k]); + } + if (sums.find(cur_sum) == sums.end()) { + sums[cur_sum] = i; // Only keep the smallest index. + } + } + return max_len; + } +}; diff --git a/C++/maximum-sum-of-3-non-overlapping-subarrays.cpp b/C++/maximum-sum-of-3-non-overlapping-subarrays.cpp new file mode 100644 index 000000000..aedc67d4b --- /dev/null +++ b/C++/maximum-sum-of-3-non-overlapping-subarrays.cpp @@ -0,0 +1,46 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector maxSumOfThreeSubarrays(vector& nums, int k) { + const auto n = nums.size(); + vector accu = {0}; + for (const auto& num : nums) { + accu.emplace_back(accu.back() + num); + } + + vector left_pos(n); + for (int i = k, total = accu[k] - accu[0]; i < n; ++i) { + if (accu[i + 1] - accu[i + 1 - k] > total) { + left_pos[i] = i + 1 - k; + total = accu[i + 1] - accu[i + 1 - k]; + } else { + left_pos[i] = left_pos[i - 1]; + } + } + + vector right_pos(n, n - k); + for (int i = n - k - 1, total = accu[n] - accu[n - k]; i >= 0; --i) { + if (accu[i + k] - accu[i] > total) { + right_pos[i] = i; + total = accu[i + k] - accu[i]; + } else { + right_pos[i] = right_pos[i + 1]; + } + } + + vector result(3); + for (int i = k, max_sum = 0; i <= n - 2 * k; ++i) { + auto left = left_pos[i - 1], right = right_pos[i + k]; + auto total = (accu[i + k] - accu[i]) + + (accu[left + k] - accu[left]) + + (accu[right + k] - accu[right]); + if (total > max_sum) { + max_sum = total; + result = {left, i, right}; + } + } + return result; + } +}; diff --git a/C++/maximum-swap.cpp b/C++/maximum-swap.cpp new file mode 100644 index 000000000..5282aeb2e --- /dev/null +++ b/C++/maximum-swap.cpp @@ -0,0 +1,21 @@ +// Time: O(logn), logn is the length of the number string +// Space: O(logn) + +class Solution { +public: + int maximumSwap(int num) { + string digits = to_string(num); + int left = 0, right = 0; + int max_idx = digits.length() - 1; + for (int i = digits.length() - 1; i >= 0; --i) { + if (digits[i] > digits[max_idx]) { + max_idx = i; + } else if (digits[max_idx] > digits[i]) { + left = i; + right = max_idx; + } + } + swap(digits[left], digits[right]); + return stoi(digits); + } +}; diff --git a/C++/maximum-vacation-days.cpp b/C++/maximum-vacation-days.cpp new file mode 100644 index 000000000..ed61426a7 --- /dev/null +++ b/C++/maximum-vacation-days.cpp @@ -0,0 +1,24 @@ +// Time: O(n^2 * k) +// Space: O(k) + +class Solution { +public: + int maxVacationDays(vector>& flights, vector>& days) { + if (days.empty() || flights.empty()) { + return 0; + } + vector> dp(2, vector(days.size())); + for (int week = days[0].size() - 1; week >= 0; --week) { + for (int cur_city = 0; cur_city < days.size(); ++cur_city) { + dp[week % 2][cur_city] = days[cur_city][week] + dp[(week + 1) % 2][cur_city]; + for (int dest_city = 0; dest_city < days.size(); ++dest_city) { + if (flights[cur_city][dest_city] == 1) { + dp[week % 2][cur_city] = max(dp[week % 2][cur_city], + days[dest_city][week] + dp[(week + 1) % 2][dest_city]); + } + } + } + } + return dp[0][0]; + } +}; diff --git a/C++/maximum-width-of-binary-tree.cpp b/C++/maximum-width-of-binary-tree.cpp new file mode 100644 index 000000000..711af584a --- /dev/null +++ b/C++/maximum-width-of-binary-tree.cpp @@ -0,0 +1,33 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int widthOfBinaryTree(TreeNode* root) { + vector leftmosts; + return dfs(root, 1, 0, &leftmosts); + } + +private: + int dfs(TreeNode* node, int id, int depth, vector *leftmosts) { + if (!node) { + return 0; + } + if (depth >= leftmosts->size()) { + leftmosts->emplace_back(id); + } + int result = id - (*leftmosts)[depth] + 1; + result = max(result, dfs(node->left, id * 2, depth + 1, leftmosts)); + result = max(result, dfs(node->right, id * 2 + 1, depth + 1, leftmosts)); + return result; + } +}; diff --git a/C++/maximum-xor-of-two-numbers-in-an-array.cpp b/C++/maximum-xor-of-two-numbers-in-an-array.cpp new file mode 100644 index 000000000..8822939f9 --- /dev/null +++ b/C++/maximum-xor-of-two-numbers-in-an-array.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int findMaximumXOR(vector& nums) { + int result = 0; + + for (int i = 31; i >= 0; --i) { + result <<= 1; + unordered_set prefixes; + for (const auto& n : nums) { + prefixes.emplace(n >> i); + } + for (const auto& p : prefixes) { + if (prefixes.count((result | 1) ^ p)) { + ++result; + break; + } + } + } + + return result; + } +}; diff --git a/C++/median-of-two-sorted-arrays.cpp b/C++/median-of-two-sorted-arrays.cpp new file mode 100644 index 000000000..d119db59e --- /dev/null +++ b/C++/median-of-two-sorted-arrays.cpp @@ -0,0 +1,93 @@ +// Time: O(log(min(m, n))) +// Space: O(1) + +class Solution { +public: + double findMedianSortedArrays(vector& nums1, vector& nums2) { + if ((nums1.size() + nums2.size()) % 2 == 1) { + return findKthInTwoSortedArrays(nums1, nums2, (nums1.size() + nums2.size()) / 2 + 1); + } else { + return (findKthInTwoSortedArrays(nums1, nums2, (nums1.size() + nums2.size()) / 2) + + findKthInTwoSortedArrays(nums1, nums2, (nums1.size() + nums2.size()) / 2 + 1)) / 2.0; + } + } + + int findKthInTwoSortedArrays(const vector& A, const vector& B, + int k) { + const int m = A.size(); + const int n = B.size(); + + // Make sure m is the smaller one. + if (m > n) { + return findKthInTwoSortedArrays(B, A, k); + } + + int left = 0; + int right = m; + // Find a partition of A and B + // where min left s.t. A[left] >= B[k - 1 - left]. Thus A[left] is the (k+1)-th or above element. + while (left < right) { + int mid = left + (right - left) / 2; + if (0 <= k - 1 - mid && k - 1 - mid < n && A[mid] >= B[k - 1 - mid]) { + right = mid; + } else { + left = mid + 1; + } + } + + int Ai_minus_1 = left - 1 >= 0 ? A[left - 1] : numeric_limits::min(); + int Bj = k - 1 - left >= 0 ? B[k - 1 - left] : numeric_limits::min(); + + // kth element would be A[left - 1] or B[k - 1 - left]. + return max(Ai_minus_1, Bj); + } +}; + +// Time: O(log(max(m, n)) * log(max_val - min_val)) +// Space: O(1) +// Generic solution. +class Solution_Generic { +public: + double findMedianSortedArrays(vector& nums1, vector& nums2) { + vector *> arrays{&nums1, &nums2}; + if ((nums1.size() + nums2.size()) % 2 == 1) { + return findKthInSortedArrays(arrays, (nums1.size() + nums2.size()) / 2 + 1); + } else { + return (findKthInSortedArrays(arrays, (nums1.size() + nums2.size()) / 2) + + findKthInSortedArrays(arrays, (nums1.size() + nums2.size()) / 2 + 1)) / 2.0; + } + } + +private: + int findKthInSortedArrays(const vector *>& arrays, int k) { + int left = numeric_limits::max(); + int right = numeric_limits::min(); + for (const auto array : arrays) { + if (!array->empty()) { + left = min(left, array->front()); + right = max(right, array->back()); + } + } + // left xxxxxxxooooooo right, find first xo or oo + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (match(arrays, mid, k)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } + + bool match(const vector *>& arrays, int num, int target) { + int res = 0; + for (const auto array : arrays) { + if (!array->empty()) { + res += distance(upper_bound(array->cbegin(), array->cend(), num), + array->cend()); + } + } + return res < target; + } +}; diff --git a/C++/meeting-rooms-ii.cpp b/C++/meeting-rooms-ii.cpp new file mode 100644 index 000000000..e6489db1b --- /dev/null +++ b/C++/meeting-rooms-ii.cpp @@ -0,0 +1,40 @@ +// Time: O(nlogn) +// Space: O(n) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + int minMeetingRooms(vector& intervals) { + vector starts, ends; + for (const auto& i : intervals) { + starts.emplace_back(i.start); + ends.emplace_back(i.end); + } + + sort(starts.begin(), starts.end()); + sort(ends.begin(), ends.end()); + + int min_rooms = 0, cnt_rooms = 0; + int s = 0, e = 0; + while (s < starts.size()) { + if (starts[s] < ends[e]) { + ++cnt_rooms; // Acquire a room. + // Update the min number of rooms. + min_rooms = max(min_rooms, cnt_rooms); + ++s; + } else { + --cnt_rooms; // Release a room. + ++e; + } + } + return min_rooms; + } +}; diff --git a/C++/meeting-rooms.cpp b/C++/meeting-rooms.cpp new file mode 100644 index 000000000..7568e7990 --- /dev/null +++ b/C++/meeting-rooms.cpp @@ -0,0 +1,25 @@ +// Time: O(nlogn) +// Space: O(n) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + bool canAttendMeetings(vector& intervals) { + sort(intervals.begin(), intervals.end(), + [](const Interval& x, const Interval& y) { return x.start < y.start; }); + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i].start < intervals[i - 1].end) { + return false; + } + } + return true; + } +}; diff --git a/C++/merge-intervals.cpp b/C++/merge-intervals.cpp new file mode 100644 index 000000000..09b707d65 --- /dev/null +++ b/C++/merge-intervals.cpp @@ -0,0 +1,36 @@ +// Time: O(nlogn) +// Space: O(1) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + vector merge(vector& intervals) { + if (intervals.empty()) { + return intervals; + } + + sort(intervals.begin(), intervals.end(), + [](const Interval& a, const Interval& b) { + return a.start < b.start; + }); + + vector result{intervals[0]}; + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i].start <= result.back().end) { + result.back().end = max(result.back().end, intervals[i].end); + } else { + result.emplace_back(intervals[i]); + } + } + + return result; + } +}; diff --git a/C++/merge-k-sorted-lists.cpp b/C++/merge-k-sorted-lists.cpp new file mode 100644 index 000000000..b508c84cf --- /dev/null +++ b/C++/merge-k-sorted-lists.cpp @@ -0,0 +1,134 @@ +// Time: O(n * logk) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ + +// Merge two by two solution. +class Solution { +public: + ListNode *mergeKLists(vector &lists) { + if (lists.empty()) { + return nullptr; + } + + int left = 0, right = lists.size() - 1; + while (right > 0) { + if (left >= right) { + left = 0; + } else { + lists[left] = mergeTwoLists(lists[left], lists[right]); + ++left; + --right; + } + } + return lists[0]; + } + +private: + ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode dummy{0}; + auto curr = &dummy; + + while (l1 && l2) { + if (l1->val <= l2->val) { + curr->next = l1; + l1 = l1->next; + } else { + curr->next = l2; + l2 = l2->next; + } + curr = curr->next; + } + curr->next = l1 ? l1 : l2; + + return dummy.next; + } +}; + + +// Time: O(n * logk) +// Space: O(logk) +// Divide and Conquer solution. +class Solution2 { +public: + ListNode *mergeKLists(vector &lists) { + return mergeKListsHelper(lists, 0, lists.size() - 1); + } + +private: + ListNode *mergeKListsHelper(const vector &lists, int begin, int end) { + if (begin > end) { + return nullptr; + } + if (begin == end) { + return lists[begin]; + } + return mergeTwoLists(mergeKListsHelper(lists, begin, (begin + end) / 2), + mergeKListsHelper(lists, (begin + end) / 2 + 1, end)); + } + + ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode dummy{0}; + auto curr = &dummy; + + while (l1 && l2) { + if (l1->val <= l2->val) { + curr->next = l1; + l1 = l1->next; + } else { + curr->next = l2; + l2 = l2->next; + } + curr = curr->next; + } + curr->next = l1 ? l1 : l2; + + return dummy.next; + } +}; + + +// Time: O(n * logk) +// Space: O(k) +// Heap solution. +class Solution3 { +public: + ListNode* mergeKLists(vector& lists) { + ListNode dummy(0); + auto *cur = &dummy; + + struct Compare { + bool operator() (const ListNode *a, const ListNode *b) { + return a->val > b->val; + } + }; + + // Use min heap to keep the smallest node of each list + priority_queue, Compare> min_heap; + for (const auto& n : lists) { + if (n) { + min_heap.emplace(n); + } + } + + while (!min_heap.empty()) { + // Get min of k lists. + auto *node = min_heap.top(); + min_heap.pop(); + cur->next = node; + cur = cur->next; + if (node->next) { + min_heap.emplace(node->next); + } + } + + return dummy.next; + } +}; diff --git a/C++/merge-sorted-array.cpp b/C++/merge-sorted-array.cpp new file mode 100644 index 000000000..a5f688ddb --- /dev/null +++ b/C++/merge-sorted-array.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void merge(vector& nums1, int m, vector& nums2, int n) { + int i = m + n; + while (m > 0 && n > 0) { + if (nums1[m - 1] > nums2[n - 1]) { + nums1[i - 1] = nums1[m - 1]; + --m; + } else { + nums1[i - 1] = nums2[n - 1]; + --n; + } + --i; + } + + while (n > 0) { + nums1[i - 1] = nums2[n - 1]; + --n; + --i; + } + } +}; diff --git a/C++/merge-two-binary-trees.cpp b/C++/merge-two-binary-trees.cpp new file mode 100644 index 000000000..dde23b16f --- /dev/null +++ b/C++/merge-two-binary-trees.cpp @@ -0,0 +1,27 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { + if (!t1) { + return t2; + } + if (!t2) { + return t1; + } + t1->val += t2->val; + t1->left = mergeTrees(t1->left, t2->left); + t1->right = mergeTrees(t1->right, t2->right); + return t1; + } +}; diff --git a/C++/merge-two-sorted-lists.cpp b/C++/merge-two-sorted-lists.cpp new file mode 100644 index 000000000..a11d16b63 --- /dev/null +++ b/C++/merge-two-sorted-lists.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode dummy{0}; + auto curr = &dummy; + + while (l1 && l2) { + if (l1->val <= l2->val) { + curr->next = l1; + l1 = l1->next; + } else { + curr->next = l2; + l2 = l2->next; + } + curr = curr->next; + } + curr->next = l1 ? l1 : l2; + + return dummy.next; + } +}; diff --git a/C++/merge.cpp b/C++/merge.cpp deleted file mode 100644 index b161ee7ac..000000000 --- a/C++/merge.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(1) - -/** - * Definition for an interval. - * struct Interval { - * int start; - * int end; - * Interval() : start(0), end(0) {} - * Interval(int s, int e) : start(s), end(e) {} - * }; - */ -class Solution { - public: - vector merge(vector &intervals) { - vector ans; - for(auto i : intervals) { - ans = insert(ans, i); - } - return ans; - } - private: - vector insert(vector &intervals, Interval newInterval) { - vector ans; - auto n = intervals.size(); - for(int i = 0; i < n; ++i) { - if (newInterval.end < intervals[i].start) { // not overlapped - ans.push_back(newInterval); - for(; i < n; ++i) - ans.push_back(intervals[i]); - return ans; - } - else if (newInterval.start > intervals[i].end) { // not overlapped - ans.push_back(intervals[i]); - } - else { // merge - newInterval.start = min(newInterval.start, intervals[i].start); - newInterval.end = max(newInterval.end, intervals[i].end); - } - } - - ans.push_back(newInterval); - return ans; - } -}; diff --git a/C++/mergeKLists.cpp b/C++/mergeKLists.cpp deleted file mode 100644 index f75d4d8ce..000000000 --- a/C++/mergeKLists.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Time Complexity: O(n * logk) -// Space Complexity: O(k) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *mergeKLists(vector &lists) { - return mergeKLists(lists, 0, lists.size() - 1); - } - private: - ListNode *mergeKLists(vector &lists, int begin, int end) { - if(begin > end) - return NULL; - if(begin == end) - return lists[begin]; - return mergeTwoLists(mergeKLists(lists, begin, (begin + end) / 2), mergeKLists(lists, (begin + end) / 2 + 1, end)); - } - - ListNode *mergeTwoLists(ListNode *left, ListNode *right) { - ListNode dummy(INT_MIN); - ListNode *p = &dummy; - for(; left && right; p = p->next) { - if(left->val < right->val) { - p->next = left; - left = left->next; - } - else { - p->next = right; - right = right->next; - } - } - if(left) { - p->next = left; - } - else { - p->next = right; - } - - return dummy.next; - } -}; diff --git a/C++/min-cost-climbing-stairs.cpp b/C++/min-cost-climbing-stairs.cpp new file mode 100644 index 000000000..531aba227 --- /dev/null +++ b/C++/min-cost-climbing-stairs.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int minCostClimbingStairs(vector& cost) { + vector dp(3); + for (int i = cost.size() - 1; i >= 0; --i) { + dp[i % 3] = cost[i] + + min(dp[(i + 1) % 3], + dp[(i + 2) % 3]); + } + return min(dp[0], dp[1]); + } +}; diff --git a/C++/min-stack.cpp b/C++/min-stack.cpp new file mode 100644 index 000000000..3f59d21a3 --- /dev/null +++ b/C++/min-stack.cpp @@ -0,0 +1,77 @@ +// Time: O(n) +// Space: O(1) + +class MinStack { +public: + void push(int number) { + if (elements_.empty()) { + elements_.emplace(0); + stack_min_ = number; + } else { + elements_.emplace(static_cast(number) - stack_min_); + if (number < stack_min_) { + stack_min_ = number; // Update min. + } + } + } + + void pop() { + auto diff = elements_.top(); + elements_.pop(); + if (diff < 0) { + stack_min_ -= diff; // Restore previous min. + } + } + + int top() { + if (elements_.top() > 0) { + return stack_min_ + elements_.top(); + } else { + return stack_min_; + } + } + + int getMin() { + return stack_min_; + } + +private: + stack elements_; + int stack_min_; +}; + + +// Time: O(n) +// Space: O(n) +class MinStack2 { +public: + void push(int number) { + if (cached_min_with_count_.empty() || cached_min_with_count_.top().first > number) { + cached_min_with_count_.emplace(number, 1); + } else if (cached_min_with_count_.top().first == number) { + ++cached_min_with_count_.top().second; + } + elements_.emplace(number); + } + + void pop() { + if (cached_min_with_count_.top().first == elements_.top()) { + if (--cached_min_with_count_.top().second == 0) { + cached_min_with_count_.pop(); + } + } + elements_.pop(); + } + + int top() { + return elements_.top(); + } + + int getMin() { + return cached_min_with_count_.top().first; + } + +private: + stack elements_; + stack> cached_min_with_count_; +}; diff --git a/C++/minWindow.cpp b/C++/minWindow.cpp deleted file mode 100644 index 0f24c2a75..000000000 --- a/C++/minWindow.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Time Complexity: O(n), where n is string length -// Space Complexity: O(m), where m is alphabet size - -class Solution { - public: - string minWindow(string S, string T) { - if(S.empty() || S.length() < T.length()) return ""; - const int ASCII_MAX = 256; - - vector expCnt(ASCII_MAX, 0); - vector curCnt(ASCII_MAX, 0); - int cnt = 0; - int start = 0; - int min_width = INT_MAX; - int min_start = 0; - - for(auto const &c : T) ++expCnt[c]; - - for(int i = 0; i < S.length(); ++i) { - if(expCnt[S[i]] > 0) { - ++curCnt[S[i]]; - if(curCnt[S[i]] <= expCnt[S[i]]) // counting expected elements - ++cnt; - } - if(cnt == T.size()) { // if window meets the requirement - while(expCnt[S[start]] == 0 || curCnt[S[start]] > expCnt[S[start]]) { // adjust left bound of window - --curCnt[S[start]]; - ++start; - } - - if(min_width > i - start + 1) { // update minimum window - min_width = i - start + 1; - min_start = start; - } - } - } - - if(min_width == INT_MAX) return ""; - return S.substr(min_start, min_width); - } -}; diff --git a/C++/minesweeper.cpp b/C++/minesweeper.cpp new file mode 100644 index 000000000..88fbb15f4 --- /dev/null +++ b/C++/minesweeper.cpp @@ -0,0 +1,108 @@ +// Time: O(m * n) +// Space: O(m + n) + +class Solution { +public: + vector> updateBoard(vector>& board, vector& click) { + queue> q; + q.emplace(click); + while (!q.empty()) { + int row = q.front()[0], col = q.front()[1]; + q.pop(); + if (board[row][col] == 'M') { + board[row][col] = 'X'; + } else { + int count = 0; + for (int i = -1; i < 2; ++i) { + for (int j = -1; j < 2; ++j) { + if (i == 0 && j == 0) { + continue; + } + int r = row + i, c = col + j; + if (r < 0 || r >= board.size() || c < 0 || c < 0 || c >= board[r].size()) { + continue; + } + if (board[r][c] == 'M' || board[r][c] == 'X') { + ++count; + } + } + } + + if (count > 0) { + board[row][col] = count + '0'; + } else { + board[row][col] = 'B'; + for (int i = -1; i < 2; ++i) { + for (int j = -1; j < 2; ++j) { + if (i == 0 && j == 0) { + continue; + } + int r = row + i, c = col + j; + if (r < 0 || r >= board.size() || c < 0 || c < 0 || c >= board[r].size()) { + continue; + } + if (board[r][c] == 'E') { + vector next_click = {r, c}; + q.emplace(next_click); + board[r][c] = 'B'; + } + } + } + } + } + } + + return board; + } +}; + +// Time: O(m * n) +// Space: O(m * n) +class Solution2 { +public: + vector> updateBoard(vector>& board, vector& click) { + int row = click[0], col = click[1]; + if (board[row][col] == 'M') { + board[row][col] = 'X'; + } else { + int count = 0; + for (int i = -1; i < 2; ++i) { + for (int j = -1; j < 2; ++j) { + if (i == 0 && j == 0) { + continue; + } + int r = row + i, c = col + j; + if (r < 0 || r >= board.size() || c < 0 || c < 0 || c >= board[r].size()) { + continue; + } + if (board[r][c] == 'M' || board[r][c] == 'X') { + ++count; + } + } + } + + if (count > 0) { + board[row][col] = count + '0'; + } else { + board[row][col] = 'B'; + for (int i = -1; i < 2; ++i) { + for (int j = -1; j < 2; ++j) { + if (i == 0 && j == 0) { + continue; + } + int r = row + i, c = col + j; + if (r < 0 || r >= board.size() || c < 0 || c < 0 || c >= board[r].size()) { + continue; + } + if (board[r][c] == 'E') { + vector next_click = {r, c}; + updateBoard(board, next_click); + } + } + } + } + } + + return board; + } +}; diff --git a/C++/mini-parser.cpp b/C++/mini-parser.cpp new file mode 100644 index 000000000..7c7cd6229 --- /dev/null +++ b/C++/mini-parser.cpp @@ -0,0 +1,136 @@ +// Time: O(n) +// Space: O(h) + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * class NestedInteger { + * public: + * // Constructor initializes an empty nested list. + * NestedInteger(); + * + * // Constructor initializes a single integer. + * NestedInteger(int value); + * + * // Return true if this NestedInteger holds a single integer, rather than a nested list. + * bool isInteger() const; + * + * // Return the single integer that this NestedInteger holds, if it holds a single integer + * // The result is undefined if this NestedInteger holds a nested list + * int getInteger() const; + * + * // Set this NestedInteger to hold a single integer. + * void setInteger(int value); + * + * // Set this NestedInteger to hold a nested list and adds a nested integer to it. + * void add(const NestedInteger &ni); + * + * // Return the nested list that this NestedInteger holds, if it holds a nested list + * // The result is undefined if this NestedInteger holds a single integer + * const vector &getList() const; + * }; + */ + +// Iterative solution. +class Solution { +public: + NestedInteger deserialize(string s) { + if (s.empty()) { + return NestedInteger(); + } + + if (s[0] != '[') { + return NestedInteger(stoi(s)); + } + + stack stk; + for (int i = 0, j = 0; j < s.length(); ++j) { + if (s[j] == '[') { + stk.emplace(NestedInteger()); + i = j + 1; + } else if (s[j] == ',' || s[j] == ']') { + if (isdigit(s[j - 1])) { + stk.top().add(NestedInteger(stoi(s.substr(i, j - i)))); + } + if (s[j] == ']' && stk.size() > 1) { + NestedInteger cur = stk.top(); + stk.pop(); + stk.top().add(cur); + } + i = j + 1; + } + } + return stk.top(); + } +}; + +// Time: O(n) +// Space: O(h) +// Recursive solution. +class Solution2 { +public: + NestedInteger deserialize(string s) { + if (s.empty()) { + return NestedInteger(); + } + int i = 0; + return deserializeHelper(s, &i); + } + +private: + NestedInteger deserializeHelper(const string& s, int *i) { + NestedInteger result; + if (s[*i] != '[') { + int j = *i; + while (j < s.length() && (s[j] == '-' || isdigit(s[j]))) { + ++j; + } + result.setInteger(stoi(s.substr(*i, j - *i + 1))); + *i = j; + } else { + ++(*i); + while (*i < s.length() && s[*i] != ']') { + result.add(deserializeHelper(s, i)); + if (*i < s.length() && s[*i] == ',') { + ++(*i); + } + } + ++(*i); + } + return result; + } +}; + +// Time: O(n) +// Space: O(n) +// Recursive solution. +class Solution3 { +public: + NestedInteger deserialize(string s) { + if (s.empty()) { + return NestedInteger(); + } + istringstream in(s); // copy string: extra O(n) space + return deserializeHelper(in); + } + +private: + NestedInteger deserializeHelper(istringstream &in) { + NestedInteger result; + int num = 0; + if (in >> num) { + result.setInteger(num); + } else { + in.clear(); + in.get(); + while (in.peek() != ']') { + result.add(deserializeHelper(in)); + if (in.peek() == ',') { + in.get(); + } + } + in.get(); + } + return result; + } +}; diff --git a/C++/minimum-absolute-difference-in-bst.cpp b/C++/minimum-absolute-difference-in-bst.cpp new file mode 100644 index 000000000..038991bd2 --- /dev/null +++ b/C++/minimum-absolute-difference-in-bst.cpp @@ -0,0 +1,39 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int getMinimumDifference(TreeNode* root) { + int result = numeric_limits::max(); + TreeNode *prev = nullptr; + + inorderTraversal(root, &prev, &result); + + return result; + } + +private: + void inorderTraversal(TreeNode *root, TreeNode **prev, int *result) { + if (!root) { + return; + } + + inorderTraversal(root->left, prev, result); + + if (*prev) { + *result = min(*result, root->val - (*prev)->val); + } + *prev = root; + + inorderTraversal(root->right, prev, result); + } +}; diff --git a/C++/minimum-ascii-delete-sum-for-two-strings.cpp b/C++/minimum-ascii-delete-sum-for-two-strings.cpp new file mode 100644 index 000000000..6c68db3d8 --- /dev/null +++ b/C++/minimum-ascii-delete-sum-for-two-strings.cpp @@ -0,0 +1,55 @@ +// Time: O(m * n) +// Space: O(n) + +// DP with rolling window. +class Solution { +public: + int minimumDeleteSum(string s1, string s2) { + vector> dp(2, vector(s2.length() + 1)); + for (int j = 0; j < s2.length(); ++j) { + dp[0][j + 1] = dp[0][j] + s2[j]; + } + + for (int i = 0; i < s1.length(); ++i) { + dp[(i + 1) % 2][0] = dp[i % 2][0] + s1[i]; + for (int j = 0; j < s2.length(); ++j) { + if (s1[i] == s2[j]) { + dp[(i + 1) % 2][j + 1] = dp[i % 2][j]; + } else { + dp[(i + 1) % 2][j + 1] = min(dp[i % 2][j + 1] + s1[i], + dp[(i + 1) % 2][j] + s2[j]); + } + } + } + + return dp[s1.length() % 2][s2.length()]; + } +}; + +// Time: O(m * n) +// Space: O(m * n) +class Solution2 { +public: + int minimumDeleteSum(string s1, string s2) { + vector> dp(s1.length() + 1, vector(s2.length() + 1)); + for (int i = 0; i < s1.length(); ++i) { + dp[i + 1][0] = dp[i][0] + s1[i]; + } + for (int j = 0; j < s2.length(); ++j) { + dp[0][j + 1] = dp[0][j] + s2[j]; + } + + for (int i = 0; i < s1.length(); ++i) { + for (int j = 0; j < s2.length(); ++j) { + if (s1[i] == s2[j]) { + dp[i + 1][j + 1] = dp[i][j]; + } else { + dp[i + 1][j + 1] = min(dp[i][j + 1] + s1[i], + dp[i + 1][j] + s2[j]); + } + } + } + + return dp[s1.length()][s2.length()]; + } +}; diff --git a/C++/minimum-factorization.cpp b/C++/minimum-factorization.cpp new file mode 100644 index 000000000..633c9b048 --- /dev/null +++ b/C++/minimum-factorization.cpp @@ -0,0 +1,21 @@ +// Time: O(loga) +// Space: O(1) + +class Solution { +public: + int smallestFactorization(int a) { + if (a < 2) { + return a; + } + long result = 0, mul = 1; + for (int i = 9; i >= 2; --i) { + while (a % i == 0) { + a /= i; + result = mul * i + result; + mul *= 10; + } + } + return a == 1 && result <= numeric_limits::max() ? static_cast(result) : 0; + } +}; + diff --git a/C++/minimum-genetic-mutation.cpp b/C++/minimum-genetic-mutation.cpp new file mode 100644 index 000000000..9aa1defc6 --- /dev/null +++ b/C++/minimum-genetic-mutation.cpp @@ -0,0 +1,40 @@ +// Time: O(n * b), n is the length of gene string, b is size of bank +// Space: O(b) + +class Solution { +public: + int minMutation(string start, string end, vector& bank) { + unordered_map lookup; + for (const auto& b : bank) { + lookup.emplace(b, false); + } + + queue> q; + q.emplace(start, 0); + while (!q.empty()) { + string cur; + int level; + tie(cur, level) = q.front(); q.pop(); + + if (cur == end) { + return level; + } + + for (int i = 0; i < cur.size(); ++i) { + auto cur_copy = cur; + for (const auto& c : {'A', 'T', 'C', 'G'}) { + if (cur_copy[i] == c) { + continue; + } + cur_copy[i] = c; + if (lookup.count(cur_copy) && lookup[cur_copy] == false) { + q.emplace(cur_copy, level + 1); + lookup[cur_copy] = true; + } + } + } + } + + return -1; + } +}; diff --git a/C++/minimum-height-trees.cpp b/C++/minimum-height-trees.cpp new file mode 100644 index 000000000..feba813fc --- /dev/null +++ b/C++/minimum-height-trees.cpp @@ -0,0 +1,50 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector findMinHeightTrees(int n, vector>& edges) { + if (n == 1) { + return {0}; + } + + unordered_map> neighbors; + for (const auto& e : edges) { + int u, v; + tie(u, v) = e; + neighbors[u].emplace(v); + neighbors[v].emplace(u); + } + + vector pre_level, cur_level; + unordered_set unvisited; + for (int i = 0; i < n; ++i) { + if (neighbors[i].size() == 1) { // A leaf. + pre_level.emplace_back(i); + } + unvisited.emplace(i); + } + + // A graph can have 2 MHTs at most. + // BFS from the leaves until the number + // of the unvisited nodes is less than 3. + while (unvisited.size() > 2) { + cur_level.clear(); + for (const auto& u : pre_level) { + unvisited.erase(u); + for (const auto& v : neighbors[u]) { + if (unvisited.count(v)) { + neighbors[v].erase(u); + if (neighbors[v].size() == 1) { + cur_level.emplace_back(v); + } + } + } + } + swap(pre_level, cur_level); + } + + vector res(unvisited.begin(), unvisited.end()); + return res; + } +}; diff --git a/C++/minimum-index-sum-of-two-lists.cpp b/C++/minimum-index-sum-of-two-lists.cpp new file mode 100644 index 000000000..4657e28fb --- /dev/null +++ b/C++/minimum-index-sum-of-two-lists.cpp @@ -0,0 +1,26 @@ +// Time: O((m + n) * l), m is the size of list1, n is the size of list2 +// Space: O(m * l), l is the average string length + +class Solution { +public: + vector findRestaurant(vector& list1, vector& list2) { + unordered_map lookup; + for (int i = 0; i < list1.size(); ++i) { + lookup[list1[i]] = i; + } + vector result; + int min_sum = numeric_limits::max(); + for (int j = 0; j < list2.size() && j <= min_sum; ++j) { + if (lookup.count(list2[j])) { + auto sum = j + lookup[list2[j]]; + if (sum < min_sum) { + result.clear(); + result.emplace_back(list2[j]); + min_sum = sum; + } else if (sum == min_sum) + result.emplace_back(list2[j]); + } + } + return result; + } +}; diff --git a/C++/minimum-moves-to-equal-array-elements-ii.cpp b/C++/minimum-moves-to-equal-array-elements-ii.cpp new file mode 100644 index 000000000..1597aa985 --- /dev/null +++ b/C++/minimum-moves-to-equal-array-elements-ii.cpp @@ -0,0 +1,17 @@ +// Time: O(n) on average +// Space: O(1) + +// Quick select solution. +class Solution { +public: + int minMoves2(vector& nums) { + auto it = nums.begin() + nums.size() / 2; + nth_element(nums.begin(), it, nums.end()); + const auto median = *it; + int result = 0; + for (const auto &i : nums) { + result += abs(i - median); + } + return result; + } +}; diff --git a/C++/minimum-moves-to-equal-array-elements.cpp b/C++/minimum-moves-to-equal-array-elements.cpp new file mode 100644 index 000000000..330d91dbd --- /dev/null +++ b/C++/minimum-moves-to-equal-array-elements.cpp @@ -0,0 +1,10 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int minMoves(vector& nums) { + return accumulate(nums.cbegin(), nums.cend(), 0) - + nums.size() * *min_element(nums.cbegin(), nums.cend()); + } +}; diff --git a/C++/minimum-number-of-arrows-to-burst-balloons.cpp b/C++/minimum-number-of-arrows-to-burst-balloons.cpp new file mode 100644 index 000000000..2bc27dbc0 --- /dev/null +++ b/C++/minimum-number-of-arrows-to-burst-balloons.cpp @@ -0,0 +1,26 @@ +// Time: O(nlogn) +// Space: O(1) + +class Solution { +public: + int findMinArrowShots(vector>& points) { + if (points.empty()) { + return 0; + } + + sort(points.begin(), points.end()); + + int result = 0; + for (int i = 0; i < points.size(); ++i) { + int j = i + 1; + int right_bound = points[i].second; + while (j < points.size() && points[j].first <= right_bound) { + right_bound = min(right_bound, points[j].second); + ++j; + } + ++result; + i = j - 1; + } + return result; + } +}; diff --git a/C++/minimum-size-subarray-sum.cpp b/C++/minimum-size-subarray-sum.cpp new file mode 100644 index 000000000..cb3a91994 --- /dev/null +++ b/C++/minimum-size-subarray-sum.cpp @@ -0,0 +1,46 @@ +// Time: O(n) +// Space: O(1) + +// Sliding window solution. +class Solution { +public: + int minSubArrayLen(int s, vector& nums) { + int start = -1, sum = 0, min_size = numeric_limits::max(); + for (int i = 0; i < nums.size(); ++i) { + sum += nums[i]; + while (sum >= s) { + min_size = min(min_size, i - start); + sum -= nums[++start]; + } + } + if (min_size == numeric_limits::max()) { + return 0; + } + return min_size; + } +}; + +// Time: O(nlogn) +// Space: O(n) +// Binary search solution. +class Solution2 { +public: + int minSubArrayLen(int s, vector& nums) { + int min_size = numeric_limits::max(); + vector sum_from_start(nums.size() + 1); + partial_sum(nums.cbegin(), nums.cend(), sum_from_start.begin() + 1); + for (int i = 0; i < nums.size(); ++i) { + const auto& end_it = lower_bound(sum_from_start.cbegin() + i, + sum_from_start.cend(), + sum_from_start[i] + s); + if (end_it != sum_from_start.cend()) { + int end = static_cast(end_it - sum_from_start.cbegin()); + min_size = min(min_size, end - i); + } + } + if (min_size == numeric_limits::max()) { + return 0; + } + return min_size; + } +}; diff --git a/C++/minimum-time-difference.cpp b/C++/minimum-time-difference.cpp new file mode 100644 index 000000000..145cf6dce --- /dev/null +++ b/C++/minimum-time-difference.cpp @@ -0,0 +1,19 @@ +// Time: O(nlogn) +// Space: O(n) + +class Solution { +public: + int findMinDifference(vector& timePoints) { + static const int N = 60 * 24; + vector minutes; + for (const auto& t : timePoints) { + minutes.emplace_back(stoi(t.substr(0, 2)) * 60 + stoi(t.substr(3))); + } + sort(minutes.begin(), minutes.end()); + int result = numeric_limits::max(); + for (int i = 0; i < timePoints.size(); ++i) { + result = min(result, (N + minutes[(i + 1) % timePoints.size()] - minutes[i]) % N); + } + return result; + } +}; diff --git a/C++/minimum-unique-word-abbreviation.cpp b/C++/minimum-unique-word-abbreviation.cpp new file mode 100644 index 000000000..3d15a89b3 --- /dev/null +++ b/C++/minimum-unique-word-abbreviation.cpp @@ -0,0 +1,75 @@ +// Time: O(2^n) +// Space: O(n) + +class Solution { +public: + string minAbbreviation(string target, vector& dictionary) { + vector diffs; + dictionary_to_diffs(target, dictionary, &diffs); + + if (diffs.empty()) { + return to_string(target.length()); + } + + int bits = (1 << target.length()) - 1; + for (int i = 0; i < (1 << target.length()); ++i) { + if (all_of(diffs.begin(), diffs.end(), [&i](int d) { return d & i; } )) { + if (bits_len(target, i) > bits_len(target, bits)) { + bits = i; + } + } + } + + return bits_to_abbr(target, bits); + } + +private: + void dictionary_to_diffs(const string& target, const vector& dictionary, + vector *diffs) { + + for (const auto& word : dictionary) { + if (word.length() != target.length()) { + continue; + } + + int bits = 0; + for (int i = 0; i < word.length(); ++i) { + if (target[i] != word[i]) { + bits |= 1 << i; + } + } + diffs->emplace_back(bits); + } + } + + int bits_len(const string& target, int bits) { + int sum = 0; + + for (int i = 0; i < target.length() - 1; ++i) { + if (((bits >> i) & 3) == 0) { + ++sum; + } + } + + return sum; + } + + string bits_to_abbr(const string& target, int bits) { + string abbr; + + int pre = 0; + for (int i = 0, prev = 0; i < target.length(); ++i, bits >>= 1) { + if (bits & 1) { + if (i - pre > 0) { + abbr += to_string(i - pre); + } + pre = i + 1; + abbr.push_back(target[i]); + } else if (i == target.length() - 1) { + abbr += to_string(i - pre + 1); + } + } + + return abbr; + } +}; diff --git a/C++/minimum-window-subsequence.cpp b/C++/minimum-window-subsequence.cpp new file mode 100644 index 000000000..984aae5f4 --- /dev/null +++ b/C++/minimum-window-subsequence.cpp @@ -0,0 +1,36 @@ +// Time: O(s * t) +// Space: O(s) + +class Solution { +public: + string minWindow(string S, string T) { + vector> dp(2, vector(S.length(), -1)); + for (int j = 0; j < S.length(); ++j) { + if (S[j] == T[0]) { + dp[0][j] = j; + } + } + + for (int i = 1; i < T.length(); ++i) { + int prev = -1; + dp[i % 2] = vector(S.length(), -1); + for (int j = 0; j < S.length(); ++j) { + if (prev != -1 && S[j] == T[i]) { + dp[i % 2][j] = prev; + } + if (dp[(i - 1) % 2][j] != -1) { + prev = dp[(i - 1) % 2][j]; + } + } + } + + int start = 0, end = S.length(); + for (int j = 0; j < S.length(); ++j) { + int i = dp[(T.length() - 1) % 2][j]; + if (i >= 0 && j - i < end - start) { + tie(start, end) = make_pair(i, j); + } + } + return end < S.length() ? S.substr(start, end - start + 1) : ""; + } +}; diff --git a/C++/minimum-window-substring.cpp b/C++/minimum-window-substring.cpp new file mode 100644 index 000000000..cf593f4b4 --- /dev/null +++ b/C++/minimum-window-substring.cpp @@ -0,0 +1,51 @@ +// Time: O(n) +// Space: O(k) + +class Solution { +public: + string minWindow(string s, string t) { + if (s.empty() || s.length() < t.length()) { + return ""; + } + + const int ASCII_MAX = 256; + vector exp_cnt(ASCII_MAX, 0); + vector cur_cnt(ASCII_MAX, 0); + + int cnt = 0; + int start = 0; + int min_start = 0; + int min_width = numeric_limits::max(); + + for (const auto& c : t) { + ++exp_cnt[c]; + } + + for (int i = 0; i < s.length(); ++i) { + if (exp_cnt[s[i]] > 0) { + ++cur_cnt[s[i]]; + if (cur_cnt[s[i]] <= exp_cnt[s[i]]) { // Counting expected elements. + ++cnt; + } + } + if (cnt == t.size()) { // If window meets the requirement. + while (exp_cnt[s[start]] == 0 || // Adjust left bound of window. + cur_cnt[s[start]] > exp_cnt[s[start]]) { + --cur_cnt[s[start]]; + ++start; + } + + if (min_width > i - start + 1) { // Update minimum window. + min_width = i - start + 1; + min_start = start; + } + } + } + + if (min_width == numeric_limits::max()) { + return ""; + } + + return s.substr(min_start, min_width); + } +}; diff --git a/C++/missing-number.cpp b/C++/missing-number.cpp new file mode 100644 index 000000000..c6acf3901 --- /dev/null +++ b/C++/missing-number.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { + public: + int missingNumber(vector& nums) { + int num = 0; + for (int i = 0; i < nums.size(); ++i) { + num ^= nums[i] ^ (i + 1); + } + return num; + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { + public: + int missingNumber(vector& nums) { + vector expected(nums.size()); + iota(expected.begin(), expected.end(), 1); // Costs extra space O(n) + return accumulate(nums.cbegin(), nums.cend(), 0, bit_xor()) ^ + accumulate(expected.cbegin(), expected.cend(), 0, bit_xor()); + } +}; diff --git a/C++/missing-ranges.cpp b/C++/missing-ranges.cpp new file mode 100644 index 000000000..e097d37b6 --- /dev/null +++ b/C++/missing-ranges.cpp @@ -0,0 +1,28 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findMissingRanges(vector& nums, int lower, int upper) { + vector ranges; + for (int i = 0, pre = lower - 1, cur = 0; i <= nums.size(); ++i, pre = cur) { + if (i == nums.size()) { + cur = upper + 1; + } else { + cur = nums[i]; + } + if (cur - pre >= 2) { + ranges.emplace_back(getRange(pre + 1, cur - 1)); + } + } + return ranges; + } + + string getRange(const int lower, const int upper) { + if (lower == upper) { + return to_string(lower); + } else { + return to_string(lower) + "->" + to_string(upper); + } + } +}; diff --git a/C++/monotone-increasing-digits.cpp b/C++/monotone-increasing-digits.cpp new file mode 100644 index 000000000..b9cf59927 --- /dev/null +++ b/C++/monotone-increasing-digits.cpp @@ -0,0 +1,20 @@ +// Time: O(logn) = O(1) +// Space: O(logn) = O(1) + +class Solution { +public: + int monotoneIncreasingDigits(int N) { + string s = to_string(N); + int leftmost_inverted_idx = s.length(); + for (int i = s.length() - 1; i > 0; --i) { + if (s[i - 1] > s[i]) { + leftmost_inverted_idx = i; + --s[i - 1]; + } + } + for (int i = leftmost_inverted_idx; i < s.length(); ++i) { + s[i] = '9'; + } + return stoi(s); + } +}; diff --git a/C++/most-frequent-subtree-sum.cpp b/C++/most-frequent-subtree-sum.cpp new file mode 100644 index 000000000..cb3ff6f6c --- /dev/null +++ b/C++/most-frequent-subtree-sum.cpp @@ -0,0 +1,41 @@ +// Time: O(n) +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector findFrequentTreeSum(TreeNode* root) { + unordered_map counts; + int max_count = 0; + countSubtreeSumsHelper(root, &counts, &max_count); + + vector result; + for (const auto& kvp : counts){ + if (kvp.second == max_count) { + result.emplace_back(kvp.first); + } + } + return result; + } + +private: + int countSubtreeSumsHelper(TreeNode *root, unordered_map *counts, int *max_count) { + if (!root) { + return 0; + } + auto sum = root->val + + countSubtreeSumsHelper(root->left, counts, max_count) + + countSubtreeSumsHelper(root->right, counts, max_count); + ++(*counts)[sum]; + (*max_count) = max((*max_count), (*counts)[sum]); + return sum; + } +}; diff --git a/C++/move-zeroes.cpp b/C++/move-zeroes.cpp new file mode 100644 index 000000000..8f984a02e --- /dev/null +++ b/C++/move-zeroes.cpp @@ -0,0 +1,27 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void moveZeroes(vector& nums) { + int pos = 0; + for (auto& num : nums) { + if (num) { + swap(nums[pos++], num); + } + } + } +}; + +class Solution2 { +public: + void moveZeroes(vector& nums) { + int pos = 0; + for (const auto& num : nums) { + if (num) { + nums[pos++] = num; + } + } + fill(next(nums.begin(), pos), nums.end(), 0); + } +}; diff --git a/C++/moving-average-from-data-stream.cpp b/C++/moving-average-from-data-stream.cpp new file mode 100644 index 000000000..e4ac8d76e --- /dev/null +++ b/C++/moving-average-from-data-stream.cpp @@ -0,0 +1,31 @@ +// Time: O(1) +// Space: O(w) + +class MovingAverage { +public: + /** Initialize your data structure here. */ + MovingAverage(int size) : size_(size), sum_(0) { + } + + double next(int val) { + if (q_.size() == size_) { + sum_ -= q_.front(); + q_.pop(); + } + q_.emplace(val); + sum_ += val; + return 1.0 * sum_ / q_.size(); + } + +private: + int size_; + int sum_; + queue q_; +}; + +/** + * Your MovingAverage object will be instantiated and called as such: + * MovingAverage obj = new MovingAverage(size); + * double param_1 = obj.next(val); + */ + diff --git a/C++/multiply-strings.cpp b/C++/multiply-strings.cpp new file mode 100644 index 000000000..a661246f4 --- /dev/null +++ b/C++/multiply-strings.cpp @@ -0,0 +1,89 @@ +// Time: O(m * n) +// Space: O(m + n) + +class Solution { +public: + string multiply(string num1, string num2) { + const auto char_to_int = [](const char c) { return c - '0'; }; + const auto int_to_char = [](const int i) { return i + '0'; }; + + vector n1; + transform(num1.rbegin(), num1.rend(), back_inserter(n1), char_to_int); + vector n2; + transform(num2.rbegin(), num2.rend(), back_inserter(n2), char_to_int); + + vector tmp(n1.size() + n2.size()); + for(int i = 0; i < n1.size(); ++i) { + for(int j = 0; j < n2.size(); ++j) { + tmp[i + j] += n1[i] * n2[j]; + tmp[i + j + 1] += tmp[i + j] / 10; + tmp[i + j] %= 10; + } + } + + string res; + transform(find_if(tmp.rbegin(), prev(tmp.rend()), + [](const int i) { return i != 0; }), + tmp.rend(), back_inserter(res), int_to_char); + return res; + } +}; + +// Time: O(m * n) +// Space: O(m + n) +// Define a new BigInt class solution. +class Solution2 { +public: + string multiply(string num1, string num2) { + return BigInt(num1) * BigInt(num2); + } + + class BigInt { + public: + BigInt(const string& s) { + transform(s.rbegin(), s.rend(), back_inserter(n_), + [](const char c) { return c - '0'; }); + } + + operator string() { + string s; + transform(find_if(n_.rbegin(), prev(n_.rend()), + [](const int i) { return i != 0; }), + n_.rend(), back_inserter(s), + [](const int i) { return i + '0'; }); + return s; + } + + BigInt operator*(const BigInt &rhs) const { + BigInt res(n_.size() + rhs.size(), 0); + for(auto i = 0; i < n_.size(); ++i) { + for(auto j = 0; j < rhs.size(); ++j) { + res[i + j] += n_[i] * rhs[j]; + res[i + j + 1] += res[i + j] / 10; + res[i + j] %= 10; + } + } + return res; + } + + private: + vector n_; + + BigInt(int num, int val): n_(num, val) { + } + + // Getter. + int operator[] (int i) const { + return n_[i]; + } + + // Setter. + int & operator[] (int i) { + return n_[i]; + } + + size_t size() const { + return n_.size(); + } + }; +}; diff --git a/C++/multiply.cpp b/C++/multiply.cpp deleted file mode 100644 index 6989e837b..000000000 --- a/C++/multiply.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class BigInt { - public: - BigInt(string s) { - transform(s.rbegin(), s.rend(), back_inserter(n), - [](const char c) { return c - '0';}); - } - - operator string() { - string s; - transform(find_if(this->n.rbegin(), prev(this->n.rend()), - [](const int i) { return i != 0; }), this->n.rend(), back_inserter(s), - [](const int i) { return i + '0'; }); - - return s; - } - - BigInt operator*(const BigInt &rhs) const { - BigInt z(n.size() + rhs.size() + 1, 0); - for(auto i = 0; i < n.size(); ++i) { - for(auto j = 0; j < rhs.size(); ++j) { - z[i + j] += n[i] * rhs[j]; - z[i + j + 1] += z[i + j] / 10; - z[i + j] %= 10; - } - } - return z; - } - private: - vector n; - - BigInt(int num, int val): n(num, val) { - } - - // getter - int operator[] (int i) const { - return this->n[i]; - } - - // setter - int & operator[] (int i) { - return this->n[i]; - } - - int size() const { - return this->n.size(); - } -}; - -class Solution { - public: - string multiply(string num1, string num2) { - return BigInt(num1) * BigInt(num2); - } -}; diff --git a/C++/my-calendar-i.cpp b/C++/my-calendar-i.cpp new file mode 100644 index 000000000..28d1b911a --- /dev/null +++ b/C++/my-calendar-i.cpp @@ -0,0 +1,32 @@ +// Time: O(nlogn) +// Space: O(n) + +class MyCalendar { +public: + MyCalendar() { + + } + + bool book(int s, int e) { + auto next = books_.lower_bound(s); + if (next != books_.end() && next->first < e) { + return false; + } + if (next != books_.begin() && s < (--next)->second) { + return false; + } + books_[s] = e; + return true; + } + +private: + map books_; + +}; + +/** + * Your MyCalendar object will be instantiated and called as such: + * MyCalendar obj = new MyCalendar(); + * bool param_1 = obj.book(start,end); + */ + diff --git a/C++/my-calendar-ii.cpp b/C++/my-calendar-ii.cpp new file mode 100644 index 000000000..60e26aa42 --- /dev/null +++ b/C++/my-calendar-ii.cpp @@ -0,0 +1,34 @@ +// Time: O(n^2) +// Space: O(n) + +class MyCalendarTwo { +public: + MyCalendarTwo() { + + } + + bool book(int start, int end) { + for (const auto& p : overlaps_) { + if (start < p.second && end > p.first) { + return false; + } + } + for (const auto& p : calendar_) { + if (start < p.second && end > p.first) { + overlaps_.emplace_back(max(start, p.first), min(end, p.second)); + } + } + calendar_.emplace_back(start, end); + return true; + } + +private: + vector> overlaps_; + vector> calendar_; +}; + +/** + * Your MyCalendarTwo object will be instantiated and called as such: + * MyCalendarTwo obj = new MyCalendarTwo(); + * bool param_1 = obj.book(start,end); + */ diff --git a/C++/my-calendar-iii.cpp b/C++/my-calendar-iii.cpp new file mode 100644 index 000000000..895b389dd --- /dev/null +++ b/C++/my-calendar-iii.cpp @@ -0,0 +1,30 @@ +// Time: O(n^2) +// Space: O(n) + +class MyCalendarThree { +public: + MyCalendarThree() { + + } + + int book(int start, int end) { + ++books_[start]; + --books_[end]; + int result = 0; + int cnt = 0; + for (const auto &book : books_) { + cnt += book.second; + result = max(result, cnt); + } + return result; + } + +private: + map books_; +}; + +/** + * Your MyCalendarThree object will be instantiated and called as such: + * MyCalendarThree obj = new MyCalendarThree(); + * int param_1 = obj.book(start,end); + */ diff --git a/C++/nested-list-weight-sum-ii.cpp b/C++/nested-list-weight-sum-ii.cpp new file mode 100644 index 000000000..61be50f94 --- /dev/null +++ b/C++/nested-list-weight-sum-ii.cpp @@ -0,0 +1,49 @@ +// Time: O(n) +// Space: O(h) + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * class NestedInteger { + * public: + * // Return true if this NestedInteger holds a single integer, rather than a nested list. + * bool isInteger() const; + * + * // Return the single integer that this NestedInteger holds, if it holds a single integer + * // The result is undefined if this NestedInteger holds a nested list + * int getInteger() const; + * + * // Return the nested list that this NestedInteger holds, if it holds a nested list + * // The result is undefined if this NestedInteger holds a single integer + * const vector &getList() const; + * }; + */ +class Solution { +public: + int depthSumInverse(vector& nestedList) { + vector result; + for (const auto& list : nestedList) { + depthSumInverseHelper(list, 0, &result); + } + + int sum = 0; + for (int i = result.size() - 1; i >= 0; --i) { + sum += result[i] * (result.size() - i); + } + return sum; + } + +private: + void depthSumInverseHelper(const NestedInteger &list, int depth, vector *result) { + if (result->size() < depth + 1) { + result->emplace_back(0); + } + if (list.isInteger()) { + (*result)[depth] += list.getInteger(); + } else { + for (const auto& l : list.getList()) { + depthSumInverseHelper(l, depth + 1, result); + } + } + } +}; diff --git a/C++/nested-list-weight-sum.cpp b/C++/nested-list-weight-sum.cpp new file mode 100644 index 000000000..0a58943f3 --- /dev/null +++ b/C++/nested-list-weight-sum.cpp @@ -0,0 +1,39 @@ +// Time: O(n) +// Space: O(h) + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * class NestedInteger { + * public: + * // Return true if this NestedInteger holds a single integer, rather than a nested list. + * bool isInteger() const; + * + * // Return the single integer that this NestedInteger holds, if it holds a single integer + * // The result is undefined if this NestedInteger holds a nested list + * int getInteger() const; + * + * // Return the nested list that this NestedInteger holds, if it holds a nested list + * // The result is undefined if this NestedInteger holds a single integer + * const vector &getList() const; + * }; + */ +class Solution { +public: + int depthSum(vector& nestedList) { + return depthSumHelper(nestedList, 1); + } + +private: + int depthSumHelper(const vector& nestedList, int depth) { + int sum = 0; + for (const auto& list : nestedList) { + if (list.isInteger()) { + sum += list.getInteger() * depth; + } else { + sum += depthSumHelper(list.getList(), depth + 1); + } + } + return sum; + } +}; diff --git a/C++/network-delay-time.cpp b/C++/network-delay-time.cpp new file mode 100644 index 000000000..444e033dd --- /dev/null +++ b/C++/network-delay-time.cpp @@ -0,0 +1,33 @@ +// Time: O(|E| + |V|log|V|) +// Space: O(|E| + |V|) + +// Dijkstra's algorithm +class Solution { +public: + int networkDelayTime(vector>& times, int N, int K) { + using P = pair; + vector> adj(N); + for (const auto& time : times) { + int u, v, w; + tie(u, v, w) = make_tuple(time[0] - 1, time[1] - 1, time[2]); + adj[u].emplace_back(v, w); + } + + int result = 0; + unordered_set lookup; + priority_queue, greater

> min_heap; + min_heap.emplace(0, K - 1); + while (!min_heap.empty() && lookup.size() != N) { + int u; + tie(result, u) = min_heap.top(); min_heap.pop(); + lookup.emplace(u); + for (const auto& kvp : adj[u]) { + int v, w; + tie(v, w) = kvp; + if (lookup.count(v)) continue; + min_heap.emplace(result + w, v); + } + } + return lookup.size() == N ? result : -1; + } +}; diff --git a/C++/next-closest-time.cpp b/C++/next-closest-time.cpp new file mode 100644 index 000000000..c5a9922ae --- /dev/null +++ b/C++/next-closest-time.cpp @@ -0,0 +1,23 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + string nextClosestTime(string time) { + static const vector mins = { 600, 60, 10, 1 }; + auto npos = time.find(':'); + auto curr = stoi(time.substr(0, npos)) * 60 + + stoi(time.substr(npos + 1)); + string result = "0000"; + for (int i = 1, d = 0; i <= 1440 && d < 4; ++i) { + int m = (curr + i) % 1440; + for (d = 0; d < 4; ++d) { + result[d] = '0' + m / mins[d]; m %= mins[d]; + if (time.find(result[d]) == string::npos) { + break; + } + } + } + return result.substr(0, 2) + ':' + result.substr(2, 2); + } +}; diff --git a/C++/next-greater-element-i.cpp b/C++/next-greater-element-i.cpp new file mode 100644 index 000000000..28bdc2623 --- /dev/null +++ b/C++/next-greater-element-i.cpp @@ -0,0 +1,27 @@ +// Time: O(m + n) +// Space: O(m + n) + +class Solution { +public: + vector nextGreaterElement(vector& findNums, vector& nums) { + stack stk; + unordered_map lookup; + for (const auto& num : nums) { + while (!stk.empty() && num > stk.top()) { + lookup[stk.top()] = num; + stk.pop(); + } + stk.emplace(num); + } + while (!stk.empty()) { + lookup[stk.top()] = -1; + stk.pop(); + } + + vector result; + for (const auto& num : findNums) { + result.emplace_back(lookup[num]); + } + return result; + } +}; diff --git a/C++/next-greater-element-ii.cpp b/C++/next-greater-element-ii.cpp new file mode 100644 index 000000000..04c6440bf --- /dev/null +++ b/C++/next-greater-element-ii.cpp @@ -0,0 +1,18 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector nextGreaterElements(vector& nums) { + vector result(nums.size()); + stack stk; + for (int i = 2 * nums.size() - 1; i >= 0; --i) { + while (!stk.empty() && stk.top() <= nums[i % nums.size()]) { + stk.pop(); + } + result[i % nums.size()] = stk.empty() ? -1 : stk.top(); + stk.emplace(nums[i % nums.size()]); + } + return result; + } +}; diff --git a/C++/next-greater-element-iii.cpp b/C++/next-greater-element-iii.cpp new file mode 100644 index 000000000..2f086500c --- /dev/null +++ b/C++/next-greater-element-iii.cpp @@ -0,0 +1,39 @@ +// Time: O(logn) = O(1) +// Space: O(logn) = O(1) + +class Solution { +public: + int nextGreaterElement(int n) { + auto digits = to_string(n); + nextPermutation(begin(digits), end(digits)); // self-implemented next_permutattion() + auto result = stoll(digits); + return (result > numeric_limits::max() || result <= n) ? -1 : result; + } + +private: + template + bool nextPermutation(BidiIt begin, BidiIt end) { + const auto rbegin = reverse_iterator(end); + const auto rend = reverse_iterator(begin); + + // Find the first element (pivot) which is less than its successor. + auto pivot = next(rbegin); + while (pivot != rend && *pivot >= *prev(pivot)) { + ++pivot; + } + + bool is_greater = true; + if (pivot != rend) { + // Find the number which is greater than pivot, and swap it with pivot + auto change = find_if(rbegin, pivot, bind1st(less(), *pivot)); + swap(*change, *pivot); + } else { + is_greater = false; + } + + // Make the sequence after pivot non-descending + reverse(rbegin, pivot); + + return is_greater; + } +}; diff --git a/C++/next-permutation.cpp b/C++/next-permutation.cpp new file mode 100644 index 000000000..a6f8a9e4b --- /dev/null +++ b/C++/next-permutation.cpp @@ -0,0 +1,43 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void nextPermutation(vector &num) { + nextPermutation(num.begin(), num.end()); + } + +private: + template + bool nextPermutation(BidiIt begin, BidiIt end) { + const auto rbegin = reverse_iterator(end); + const auto rend = reverse_iterator(begin); + + // Find the first element (pivot) which is less than its successor. + auto pivot = next(rbegin); + while (pivot != rend && *pivot >= *prev(pivot)) { + ++pivot; + } + + bool is_greater = true; + if (pivot != rend) { + // Find the number which is greater than pivot, and swap it with pivot + auto change = find_if(rbegin, pivot, bind1st(less(), *pivot)); + swap(*change, *pivot); + } else { + is_greater = false; + } + + // Make the sequence after pivot non-descending + reverse(rbegin, pivot); + + return is_greater; + } +}; + +class Solution2 { +public: + void nextPermutation(vector &num) { + next_permutation(num.begin(), num.end()); + } +}; diff --git a/C++/nextPermutation.cpp b/C++/nextPermutation.cpp deleted file mode 100644 index 371f8b07c..000000000 --- a/C++/nextPermutation.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - void nextPermutation(vector &num) { - nextPermutation(begin(num), end(num)); - } - - private: - template - bool nextPermutation(BidiIt begin, BidiIt end) { - const auto rbegin = reverse_iterator(end); - const auto rend = reverse_iterator(begin); - - // find the firt element (pivot) which is less than its successor - auto pivot = next(rbegin); - while(pivot != rend && *pivot >= *prev(pivot)) { - ++pivot; - } - - // no next permutation, just reverse the whole sequence - if(pivot == rend) { - reverse(rbegin, rend); - return false; - } - - // find the number which is greater than pivot, and swap it with pivot - auto change = find_if(rbegin, pivot, bind1st(less(), *pivot)); - swap(*change, *pivot); - - // make the sequence after pivot non-descending - reverse(rbegin, pivot); - - return true; // return next permutation - } -}; diff --git a/C++/nim-game.cpp b/C++/nim-game.cpp new file mode 100644 index 000000000..f0b3470bb --- /dev/null +++ b/C++/nim-game.cpp @@ -0,0 +1,9 @@ +// Time: O(1) +// Soace: O(1) + +class Solution { +public: + bool canWinNim(int n) { + return n % 4 != 0; + } +}; diff --git a/C++/non-decreasing-array.cpp b/C++/non-decreasing-array.cpp new file mode 100644 index 000000000..87e288d8e --- /dev/null +++ b/C++/non-decreasing-array.cpp @@ -0,0 +1,24 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool checkPossibility(vector& nums) { + int cnt = 0; + for (int i = 1, prev = nums[0]; i < nums.size(); ++i) { + if (prev > nums[i]) { + if (cnt++) { + return false; + } + if (i - 2 < 0 || nums[i - 2] <= nums[i]) { + prev = nums[i]; // nums[i - 1] = nums[i], prev = nums[i] +// } else { +// prev = nums[i - 1]; // nums[i] = nums[i - 1], prev = nums[i] + } + } else { + prev = nums[i]; + } + } + return true; + } +}; diff --git a/C++/non-negative-integers-without-consecutive-ones.cpp b/C++/non-negative-integers-without-consecutive-ones.cpp new file mode 100644 index 000000000..02fbe7862 --- /dev/null +++ b/C++/non-negative-integers-without-consecutive-ones.cpp @@ -0,0 +1,28 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int findIntegers(int num) { + vector dp(32); + dp[0] = 1; + dp[1] = 2; + for (int i = 2; i < dp.size(); ++i) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + int result = 0, prev_bit = 0; + for (int i = 30; i >= 0; --i) { + if ((num & (1 << i)) != 0) { + result += dp[i]; + if (prev_bit == 1) { + --result; + break; + } + prev_bit = 1; + } else { + prev_bit = 0; + } + } + return result + 1; + } +}; diff --git a/C++/non-overlapping-intervals.cpp b/C++/non-overlapping-intervals.cpp new file mode 100644 index 000000000..54728e436 --- /dev/null +++ b/C++/non-overlapping-intervals.cpp @@ -0,0 +1,32 @@ +// Time: O(nlogn) +// Space: O(1) + +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + int eraseOverlapIntervals(vector& intervals) { + sort(intervals.begin(), intervals.end(), + [](const Interval& a, const Interval& b) { return a.start < b.start; }); + + int result = 0, prev = 0; + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i].start < intervals[prev].end) { + if (intervals[i].end < intervals[prev].end) { + prev = i; + } + ++result; + } else { + prev = i; + } + } + return result; + } +}; diff --git a/C++/nth-digit.cpp b/C++/nth-digit.cpp new file mode 100644 index 000000000..afe69e929 --- /dev/null +++ b/C++/nth-digit.cpp @@ -0,0 +1,20 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int findNthDigit(int n) { + int digit_len = 1; + while (n > digit_len * 9 * pow(10, digit_len - 1)) { + n -= digit_len * 9 * pow(10, digit_len - 1); + ++digit_len; + } + + const int num = pow(10, digit_len - 1) + (n - 1) / digit_len; + + int nth_digit = num / pow(10, (digit_len - 1) - (n - 1) % digit_len); + nth_digit %= 10; + + return nth_digit; + } +}; diff --git a/C++/numDecodings.cpp b/C++/numDecodings.cpp deleted file mode 100644 index 1f77e5d0a..000000000 --- a/C++/numDecodings.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int numDecodings(string s) { - if(s.empty()) return 0; - - int prev = 0; // f[n - 2] - int cur = 1; // f[n - 1] - - for(int i = 1; i <= s.length(); ++i) { - if(s[i - 1] == '0') - cur = 0; // f[n - 1] = 0 - if(i < 2 || !(s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) - prev = 0; // f[n - 2] = 0; - - int tmp = cur; - cur += prev; // f[n] = f[n - 1] + f[n - 2] - prev = tmp; - } - - return cur; - } -}; diff --git a/C++/number-complement.cpp b/C++/number-complement.cpp new file mode 100644 index 000000000..d07a6b8e1 --- /dev/null +++ b/C++/number-complement.cpp @@ -0,0 +1,13 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int findComplement(int num) { + unsigned int i = 1; + while (i <= num) { + i <<= 1; + } + return (i - 1) ^ num; + } +}; diff --git a/C++/number-of-1-bits.cpp b/C++/number-of-1-bits.cpp new file mode 100644 index 000000000..38c66af18 --- /dev/null +++ b/C++/number-of-1-bits.cpp @@ -0,0 +1,13 @@ +// Time: O(logn) = O(32) +// Space: O(1) + +class Solution { +public: + int hammingWeight(uint32_t n) { + int count = 0; + for (; n; n &= n - 1) { + ++count; + } + return count; + } +}; diff --git a/C++/number-of-atoms.cpp b/C++/number-of-atoms.cpp new file mode 100644 index 000000000..64aa73f1f --- /dev/null +++ b/C++/number-of-atoms.cpp @@ -0,0 +1,40 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string countOfAtoms(string formula) { + stack> stk; + stk.emplace(); + int submatches[] = { 1, 2, 3, 4, 5 }; + const auto e = regex("([A-Z][a-z]*)(\\d*)|(\\()|(\\))(\\d*)"); + for (regex_token_iterator it(formula.begin(), formula.end(), e, submatches), end; + it != end;) { + const auto& name = (it++)->str(); + const auto& m1 = (it++)->str(); + const auto& left_open = (it++)->str(); + const auto& right_open = (it++)->str(); + const auto& m2 = (it++)->str(); + if (!name.empty()) { + stk.top()[name] += stoi(!m1.empty() ? m1 : "1"); + } + if (!left_open.empty()) { + stk.emplace(); + } + if (!right_open.empty()) { + const auto top = move(stk.top()); stk.pop(); + for (const auto& kvp: top) { + stk.top()[kvp.first] += kvp.second * stoi(!m2.empty() ? m2 : "1"); + } + } + } + string result; + for (const auto& kvp : stk.top()) { + result += kvp.first; + if (kvp.second > 1) { + result += to_string(kvp.second); + } + } + return result; + } +}; diff --git a/C++/number-of-boomerangs.cpp b/C++/number-of-boomerangs.cpp new file mode 100644 index 000000000..e5b813cc8 --- /dev/null +++ b/C++/number-of-boomerangs.cpp @@ -0,0 +1,29 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + int numberOfBoomerangs(vector>& points) { + int result = 0; + + for (int i = 0; i < points.size(); ++i) { + unordered_map group; + for (int j = 0; j < points.size(); ++j) { + if (j == i) { + continue; + } + const auto dx = points[i].first - points[j].first; + const auto dy = points[i].second - points[j].second; + ++group[dx * dx + dy * dy]; + } + + for (const auto& p : group) { + if (p.second > 1) { + result += p.second * (p.second - 1); + } + } + } + + return result; + } +}; diff --git a/C++/number-of-connected-components-in-an-undirected-graph.cpp b/C++/number-of-connected-components-in-an-undirected-graph.cpp new file mode 100644 index 000000000..73bbdf533 --- /dev/null +++ b/C++/number-of-connected-components-in-an-undirected-graph.cpp @@ -0,0 +1,44 @@ +// Time: O(nlog*n) ~= O(n), n is the length of the positions +// Space: O(n) + +class Solution { +public: + int countComponents(int n, vector>& edges) { + UnionFind union_find(n); + for (const auto& e : edges) { + union_find.union_set(e.first, e.second); + } + return union_find.length(); + } + +private: + class UnionFind { + public: + UnionFind(const int n) : set_(n), count_(n) { + iota(set_.begin(), set_.end(), 0); + } + + int find_set(const int x) { + if (set_[x] != x) { + set_[x] = find_set(set_[x]); // Path compression. + } + return set_[x]; + } + + void union_set(const int x, const int y) { + int x_root = find_set(x), y_root = find_set(y); + if (x_root != y_root) { + set_[min(x_root, y_root)] = max(x_root, y_root); + --count_; + } + } + + int length() const { + return count_; + } + + private: + vector set_; + int count_; + }; +}; diff --git a/C++/number-of-corner-rectangles.cpp b/C++/number-of-corner-rectangles.cpp new file mode 100644 index 000000000..7d2b7a2a5 --- /dev/null +++ b/C++/number-of-corner-rectangles.cpp @@ -0,0 +1,32 @@ +// Time: O(m^2 * n), m is the number of rows with 1s, n is the number of cols with 1s +// Space: O(m * n) + +class Solution { +public: + int countCornerRectangles(vector>& grid) { + vector> rows; + for (int i = 0; i < grid.size(); ++i) { + vector row; + for (int j = 0; j < grid[i].size(); ++j) { + if (grid[i][j]) { + row.emplace_back(j); + } + } + if (!row.empty()) { + rows.emplace_back(move(row)); + } + } + int result = 0; + for (int i = 0; i < rows.size(); ++i) { + unordered_set lookup(rows[i].begin(), rows[i].end()); + for (int j = 0; j < i; ++j) { + int count = 0; + for (const auto& c : rows[j]) { + count += lookup.count(c); + } + result += count * (count - 1) / 2; + } + } + return result; + } +}; diff --git a/C++/number-of-digit-one.cpp b/C++/number-of-digit-one.cpp new file mode 100644 index 000000000..3b6f3f35d --- /dev/null +++ b/C++/number-of-digit-one.cpp @@ -0,0 +1,34 @@ +// Time: O(logn) = O(1) +// Space: O(1) + +class Solution { +public: + int countDigitOne(int n) { + const int k = 1; + int cnt = 0, multiplier = 1, left_part = n; + + while (left_part > 0) { + // split number into: left_part, curr, right_part + int curr = left_part % 10; + int right_part = n % multiplier; + + // count of (c000 ~ oooc000) = (ooo + (k < curr)? 1 : 0) * 1000 + cnt += (left_part / 10 + (k < curr)) * multiplier; + + // if k == 0, oooc000 = (ooo - 1) * 1000 + if (k == 0 && multiplier > 1) { + cnt -= multiplier; + } + + // count of (oook000 ~ oookxxx): count += xxx + 1 + if (curr == k) { + cnt += right_part + 1; + } + + left_part /= 10; + multiplier *= 10; + } + + return cnt; + } +}; diff --git a/C++/number-of-distinct-islands-ii.cpp b/C++/number-of-distinct-islands-ii.cpp new file mode 100644 index 000000000..7f09919ec --- /dev/null +++ b/C++/number-of-distinct-islands-ii.cpp @@ -0,0 +1,73 @@ +// Time: O((m * n) * log(m * n)) +// Space: O(m * n) + +class Solution { +public: + int numDistinctIslands2(vector>& grid) { + unordered_set>, VectorHash> islands; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[i].size(); ++j) { + if (grid[i][j] == 1) { + vector> island; + if (dfs(i, j, &grid, &island)) { + islands.emplace(normalize(island)); + } + } + } + } + return islands.size(); + } + +private: + struct VectorHash { + size_t operator()(const std::vector>& v) const { + size_t seed = 0; + for (const auto& i : v) { + seed ^= std::hash{}(i.first) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= std::hash{}(i.second) + 0x9e3779b9 + (seed<<6) + (seed>>2); + } + return seed; + } + }; + + bool dfs(const int i, const int j, + vector> *grid, vector> *island) { + + static const vector> directions{{1, 0}, {-1, 0}, + {0, 1}, {0, -1}}; + + if (i < 0 || i >= grid->size() || + j < 0 || j >= (*grid)[0].size() || + (*grid)[i][j] <= 0) { + return false; + } + (*grid)[i][j] *= -1; + island->emplace_back(i, j); + for (const auto& direction : directions) { + dfs(i + direction.first, j + direction.second, grid, island); + } + return true; + } + + vector> normalize(const vector>& island) { + vector>> shapes(8); + for (const auto& p : island) { + int x, y; + tie(x, y) = p; + vector> rotations_and_reflections{{ x, y}, { x, -y}, {-x, y}, {-x, -y}, + { y, x}, { y, -x}, {-y, x}, {-y, -x}}; + for (int i = 0; i < rotations_and_reflections.size(); ++i) { + shapes[i].emplace_back(rotations_and_reflections[i]); + } + } + for (auto& shape : shapes) { + sort(shape.begin(), shape.end()); // Time: O(ilogi), i is the size of the island, the max would be (m * n) + const auto origin = shape.front(); + for (auto& p : shape) { + p = {p.first - origin.first, + p.second - origin.second}; + } + } + return *min_element(shapes.begin(), shapes.end()); + } +}; diff --git a/C++/number-of-distinct-islands.cpp b/C++/number-of-distinct-islands.cpp new file mode 100644 index 000000000..09f50532f --- /dev/null +++ b/C++/number-of-distinct-islands.cpp @@ -0,0 +1,39 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + int numDistinctIslands(vector>& grid) { + unordered_set islands; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + string island; + if (dfs(i, j, &grid, &island)) { + islands.emplace(island); + } + } + } + return islands.size(); + } + +private: + bool dfs(const int i, const int j, + vector> *grid, string *island) { + + static const unordered_map> + directions = { {'l', {-1, 0} }, {'r', { 1, 0} }, + {'u', { 0, 1} }, {'d', { 0, -1} }}; + + if (i < 0 || i >= grid->size() || + j < 0 || j >= (*grid)[0].size() || + (*grid)[i][j] <= 0) { + return false; + } + (*grid)[i][j] *= -1; + for (const auto& kvp : directions) { + island->push_back(kvp.first); + dfs(i + kvp.second.first, j + kvp.second.second, grid, island); + } + return true; + } +}; diff --git a/C++/number-of-islands-ii.cpp b/C++/number-of-islands-ii.cpp new file mode 100644 index 000000000..cc234784d --- /dev/null +++ b/C++/number-of-islands-ii.cpp @@ -0,0 +1,119 @@ +// Time: O(klog*k) ~= O(k), k is the length of the positions +// Space: O(k) + +// Using unordered_map. +class Solution { +public: + vector numIslands2(int m, int n, vector>& positions) { + vector numbers; + int number = 0; + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + unordered_map set; + for (const auto& position : positions) { + const auto& node = make_pair(position.first, position.second); + set[node_id(node, n)] = node_id(node, n); + ++number; + + for (const auto& d : directions) { + const auto& neighbor = make_pair(position.first + d.first, + position.second + d.second); + if (neighbor.first >= 0 && neighbor.first < m && + neighbor.second >= 0 && neighbor.second < n && + set.find(node_id(neighbor, n)) != set.end()) { + if (find_set(node_id(node, n), &set) != + find_set(node_id(neighbor, n), &set)) { + // Merge different islands, amortised time: O(log*k) ~= O(1) + union_set(&set, node_id(node, n), node_id(neighbor, n)); + --number; + } + } + } + numbers.emplace_back(number); + } + + return numbers; + } + + int node_id(const pair& node, const int n) { + return node.first * n + node.second; + } + + int find_set(int x, unordered_map *set) { + if ((*set)[x] != x) { + (*set)[x] = find_set((*set)[x], set); // path compression. + } + return (*set)[x]; + } + + void union_set(unordered_map *set, const int x, const int y) { + int x_root = find_set(x, set), y_root = find_set(y, set); + (*set)[min(x_root, y_root)] = max(x_root, y_root); + } +}; + + +// Time: O(klog*k) ~= O(k), k is the length of the positions +// Space: O(m * n) +// Using vector. +class Solution2 { +public: + /** + * @param n an integer + * @param m an integer + * @param operators an array of point + * @return an integer array + */ + vector numIslands2(int m, int n, vector>& positions) { + vector numbers; + int number = 0; + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + vector set(m * n, -1); + for (const auto& position : positions) { + const auto& node = make_pair(position.first, position.second); + set[node_id(node, n)] = node_id(node, n); + ++number; + + for (const auto& d : directions) { + const auto& neighbor = make_pair(position.first + d.first, + position.second + d.second); + if (neighbor.first >= 0 && neighbor.first < m && + neighbor.second >= 0 && neighbor.second < n && + set[node_id(neighbor, n)] != -1) { + if (find_set(node_id(node, n), &set) != + find_set(node_id(neighbor, n), &set)) { + // Merge different islands, amortised time: O(log*k) ~= O(1) + union_set(&set, node_id(node, n), node_id(neighbor, n)); + --number; + } + } + } + numbers.emplace_back(number); + } + + return numbers; + } + + int node_id(const pair& node, const int m) { + return node.first * m + node.second; + } + + int find_set(int x, vector *set) { + int parent = x; + while ((*set)[parent] != parent) { + parent = (*set)[parent]; + } + while ((*set)[x] != x) { + int tmp = (*set)[x]; + (*set)[x] = parent; + x = tmp; + } + return parent; + } + + void union_set(vector *set, const int x, const int y) { + int x_root = find_set(x, set), y_root = find_set(y, set); + (*set)[min(x_root, y_root)] = max(x_root, y_root); + } +}; diff --git a/C++/number-of-longest-increasing-subsequence.cpp b/C++/number-of-longest-increasing-subsequence.cpp new file mode 100644 index 000000000..5c9588a42 --- /dev/null +++ b/C++/number-of-longest-increasing-subsequence.cpp @@ -0,0 +1,28 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + int findNumberOfLIS(vector& nums) { + auto result = 0, max_len = 0; + vector> dp(nums.size(), {1, 1}); // {length, number} pair + for (int i = 0; i < nums.size(); ++i) { + for (int j = 0; j < i; ++j) { + if (nums[i] > nums[j]) { + if (dp[i].first == dp[j].first + 1) { + dp[i].second += dp[j].second; + } else if (dp[i].first < dp[j].first + 1) { + dp[i] = {dp[j].first + 1, dp[j].second}; + } + } + } + if (max_len == dp[i].first) { + result += dp[i].second; + } else if (max_len < dp[i].first) { + max_len = dp[i].first; + result = dp[i].second; + } + } + return result; + } +}; diff --git a/C++/number-of-segments-in-a-string.cpp b/C++/number-of-segments-in-a-string.cpp new file mode 100644 index 000000000..73b078893 --- /dev/null +++ b/C++/number-of-segments-in-a-string.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int countSegments(string s) { + int result = static_cast(!s.empty() && s.back() != ' '); + for (int i = 1; i < s.size(); ++i) { + if (s[i] == ' ' && s[i - 1] != ' ') { + ++result; + } + } + return result; + } +}; diff --git a/C++/odd-even-linked-list.cpp b/C++/odd-even-linked-list.cpp new file mode 100644 index 000000000..1897ec415 --- /dev/null +++ b/C++/odd-even-linked-list.cpp @@ -0,0 +1,28 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* oddEvenList(ListNode* head) { + if (head) { + for (auto odd_tail = head, curr = head->next; + curr && curr->next; + curr = curr->next) { + ListNode *even_head = odd_tail->next; + odd_tail->next = curr->next; + odd_tail = odd_tail->next; + curr->next = odd_tail->next; + odd_tail->next = even_head; + } + } + return head; + } +}; diff --git a/C++/one-edit-distance.cpp b/C++/one-edit-distance.cpp new file mode 100644 index 000000000..586fc8200 --- /dev/null +++ b/C++/one-edit-distance.cpp @@ -0,0 +1,28 @@ +// Time: O(m + n) +// Space: O(1) + +class Solution { +public: + bool isOneEditDistance(string s, string t) { + const int m = s.length(), n = t.length(); + if (m > n) { + return isOneEditDistance(t, s); + } + if (n - m > 1) { + return false; + } + + int i = 0, shift = n - m; + while (i < m && s[i] == t[i]) { + ++i; + } + if (shift == 0) { + ++i; + } + while (i < m && s[i] == t[i + shift]) { + ++i; + } + + return i == m; + } +}; diff --git a/C++/ones-and-zeroes.cpp b/C++/ones-and-zeroes.cpp new file mode 100644 index 000000000..5abc12520 --- /dev/null +++ b/C++/ones-and-zeroes.cpp @@ -0,0 +1,26 @@ +// Time: O(s * m * n), s is the size of the array. +// Space: O(m * n) + +class Solution { +public: + int findMaxForm(vector& strs, int m, int n) { + vector> dp(m + 1, vector(n + 1)); + for (const auto &str : strs) { + int zero_count = 0, one_count = 0; + for (const auto& c : str) { + if (c == '0') { + ++zero_count; + } else if (c == '1') { + ++one_count; + } + } + + for (int i = m; i - zero_count >= 0; --i) { + for (int j = n; j - one_count >= 0; --j) { + dp[i][j] = max(dp[i][j], dp[i - zero_count][j - one_count] + 1); + } + } + } + return dp[m][n]; + } +}; diff --git a/C++/optimal-account-balancing.cpp b/C++/optimal-account-balancing.cpp new file mode 100644 index 000000000..ec33dedef --- /dev/null +++ b/C++/optimal-account-balancing.cpp @@ -0,0 +1,48 @@ +// Time: O(n * 2^n), n is the size of the debt. +// Space: O(n * 2^n) + +class Solution { +public: + int minTransfers(vector>& transactions) { + unordered_map account; + for (const auto& transaction : transactions) { + account[transaction[0]] += transaction[2]; + account[transaction[1]] -= transaction[2]; + } + + vector debt; + for (const auto& kvp : account) { + if (kvp.second) { + debt.emplace_back(kvp.second); + } + } + if (debt.empty()) { + return 0; + } + + const auto n = 1 << debt.size(); + vector dp(n, numeric_limits::max()), subset; + for (int i = 1; i < n; ++i) { + int net_debt = 0, number = 0; + for (int j = 0; j < debt.size(); ++j) { + if (i & 1 << j) { + net_debt += debt[j]; + ++number; + } + } + if (net_debt == 0) { + dp[i] = number - 1; + for (const auto& s : subset) { + if ((i & s) == s) { + if (dp[s] != numeric_limits::max() && + dp[i - s] != numeric_limits::max()) { + dp[i] = min(dp[i], dp[s] + dp[i - s]); + } + } + } + subset.emplace_back(i); + } + } + return dp.back(); + } +}; diff --git a/C++/optimal-division.cpp b/C++/optimal-division.cpp new file mode 100644 index 000000000..899ab0fa3 --- /dev/null +++ b/C++/optimal-division.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string optimalDivision(vector& nums) { + if (nums.size() == 1) { + return to_string(nums[0]); + } + if (nums.size() == 2) { + return to_string(nums[0]) + "/" + to_string(nums[1]); + } + string result = to_string(nums[0]) + "/(" + to_string(nums[1]); + for (int i = 2; i < nums.size(); ++i) { + result += "/" + to_string(nums[i]); + } + result.push_back(')'); + return result; + } +}; diff --git a/C++/out-of-boundary-paths.cpp b/C++/out-of-boundary-paths.cpp new file mode 100644 index 000000000..a0c829858 --- /dev/null +++ b/C++/out-of-boundary-paths.cpp @@ -0,0 +1,22 @@ +// Time: O(N * m * n) +// Space: O(m * n) + +class Solution { +public: + int findPaths(int m, int n, int N, int x, int y) { + const auto M = 1000000000 + 7; + vector>> dp(2, vector>(m, vector(n))); + int result = 0; + for (int moves = 0; moves < N; ++moves) { + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + dp[(moves + 1) % 2][i][j] = (((i == 0 ? 1 : dp[moves % 2][i - 1][j]) + + (i == m - 1 ? 1 : dp[moves % 2][i + 1][j])) % M + + ((j == 0 ? 1 : dp[moves % 2][i][j - 1]) + + (j == n - 1 ? 1 : dp[moves % 2][i][j + 1])) % M) % M; + } + } + } + return dp[N % 2][x][y]; + } +}; diff --git a/C++/output-contest-matches.cpp b/C++/output-contest-matches.cpp new file mode 100644 index 000000000..b97d47a3e --- /dev/null +++ b/C++/output-contest-matches.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string findContestMatch(int n) { + vector matches(n); + for (int i = 0; i < n; ++i) { + matches[i] = to_string(i + 1); + } + while (matches.size() / 2) { + vector next_matches; + for (int i = 0; i < matches.size() / 2; ++i) { + next_matches.emplace_back("(" + matches[i] + "," + matches[matches.size() - 1 - i] + ")"); + } + swap(matches, next_matches); + } + return matches[0]; + } +}; diff --git a/C++/pacific-atlantic-water-flow.cpp b/C++/pacific-atlantic-water-flow.cpp new file mode 100644 index 000000000..1128de3e5 --- /dev/null +++ b/C++/pacific-atlantic-water-flow.cpp @@ -0,0 +1,50 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + + vector> pacificAtlantic(vector>& matrix) { + if (matrix.empty()) { + return {}; + } + + vector> res; + const auto m = matrix.size(), n = matrix[0].size(); + vector> visited(m, vector(n)); + + for (int i = 0; i < m; ++i) { + pacificAtlanticHelper(matrix, i, 0, numeric_limits::min(), PACIFIC, &visited, &res); + pacificAtlanticHelper(matrix, i, n - 1, numeric_limits::min(), ATLANTIC, &visited, &res); + } + for (int j = 0; j < n; ++j) { + pacificAtlanticHelper(matrix, 0, j, numeric_limits::min(), PACIFIC, &visited, &res); + pacificAtlanticHelper(matrix, m - 1, j, numeric_limits::min(), ATLANTIC, &visited, &res); + } + + return res; + } + +private: + void pacificAtlanticHelper(const vector>& matrix, int x, int y, int prev_height, int prev_val, + vector> *visited, vector> *res) { + + if (x < 0 || x >= matrix.size() || + y < 0 || y >= matrix[0].size() || + matrix[x][y] < prev_height || ((*visited)[x][y] | prev_val) == (*visited)[x][y]) { + return; + } + + (*visited)[x][y] |= prev_val; + if ((*visited)[x][y] == (PACIFIC | ATLANTIC)) { + res->emplace_back(x, y); + } + + for (const auto& dir : directions) { + pacificAtlanticHelper(matrix, x + dir.first, y + dir.second, matrix[x][y], (*visited)[x][y], visited, res); + } + } + + enum ocean { PACIFIC = 1, ATLANTIC = 2 }; + const vector> directions{ {0, -1}, {0, 1}, {-1, 0}, {1, 0} }; +}; diff --git a/C++/paint-fence.cpp b/C++/paint-fence.cpp new file mode 100644 index 000000000..6dd44afb8 --- /dev/null +++ b/C++/paint-fence.cpp @@ -0,0 +1,42 @@ +// Time: O(n) +// Space: O(1) + +// DP with rolling window. +class Solution { +public: + int numWays(int n, int k) { + if (n == 0) { + return 0; + } else if (n == 1) { + return k; + } + vector ways(3, 0); + ways[0] = k; + ways[1] = (k - 1) * ways[0] + k; + for (int i = 2; i < n; ++i) { + ways[i % 3] = (k - 1) * (ways[(i - 1) % 3] + ways[(i - 2) % 3]); + } + return ways[(n - 1) % 3]; + } +}; + +// Time: O(n) +// Space: O(n) +// DP solution. +class Solution2 { +public: + int numWays(int n, int k) { + if (n == 0) { + return 0; + } else if (n == 1) { + return k; + } + vector ways(n, 0); + ways[0] = k; + ways[1] = (k - 1) * ways[0] + k; + for (int i = 2; i < n; ++i) { + ways[i] = (k - 1) * (ways[i - 1] + ways[i - 2]); + } + return ways[n - 1]; + } +}; diff --git a/C++/paint-house-ii.cpp b/C++/paint-house-ii.cpp new file mode 100644 index 000000000..7a4fc3851 --- /dev/null +++ b/C++/paint-house-ii.cpp @@ -0,0 +1,58 @@ +// Time: O(n * k) +// Space: O(k) + +class Solution { +public: + int minCostII(vector>& costs) { + if (costs.empty()) { + return 0; + } + + vector> min_cost(2, costs[0]); + + const int n = costs.size(); + const int k = costs[0].size(); + for (int i = 1; i < n; ++i) { + int smallest = numeric_limits::max(), second_smallest = numeric_limits::max(); + for (int j = 0; j < k; ++j) { + if (min_cost[(i - 1) % 2][j] < smallest) { + second_smallest = smallest; + smallest = min_cost[(i - 1) % 2][j]; + } else if (min_cost[(i - 1) % 2][j] < second_smallest) { + second_smallest = min_cost[(i - 1) % 2][j]; + } + } + for (int j = 0; j < k; ++j) { + const int min_j = (min_cost[(i - 1) % 2][j] != smallest) ? smallest : second_smallest; + min_cost[i % 2][j] = costs[i][j] + min_j; + } + } + + return *min_element(min_cost[(n - 1) % 2].cbegin(), min_cost[(n - 1) % 2].cend()); + } +}; + +// Time: O(n * k) +// Space: O(k) +class Solution2{ +public: + int minCostII(vector>& costs) { + if (costs.empty()) { + return 0; + } + auto combine = [](const vector& tmp, const vector& house) { + const int smallest = *min_element(tmp.cbegin(), tmp.cend()); + const int i = distance(tmp.begin(), find(tmp.cbegin(), tmp.cend(), smallest)); + vector tmp2(tmp); + tmp2.erase(tmp2.begin() + i); + const int second_smallest = *min_element(tmp2.cbegin(), tmp2.cend()); + vector min_cost(tmp.size(), smallest); + min_cost[i] = second_smallest; + transform(min_cost.cbegin(), min_cost.cend(), house.cbegin(), + min_cost.begin(), std::plus()); + return min_cost; + }; + vector min_cost = accumulate(costs.cbegin(), costs.cend(), vector(costs[0].size(), 0), combine); + return *min_element(min_cost.cbegin(), min_cost.cend()); + } +}; diff --git a/C++/paint-house.cpp b/C++/paint-house.cpp new file mode 100644 index 000000000..d93d65527 --- /dev/null +++ b/C++/paint-house.cpp @@ -0,0 +1,46 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int minCost(vector>& costs) { + if (costs.empty()) { + return 0; + } + + vector> min_cost(2, costs[0]); + + const int n = costs.size(); + for (int i = 1; i < n; ++i) { + min_cost[i % 2][0] = costs[i][0] + + min(min_cost[(i - 1) % 2][1], min_cost[(i - 1) % 2][2]); + min_cost[i % 2][1] = costs[i][1] + + min(min_cost[(i - 1) % 2][0], min_cost[(i - 1) % 2][2]); + min_cost[i % 2][2] = costs[i][2] + + min(min_cost[(i - 1) % 2][0], min_cost[(i - 1) % 2][1]); + } + + return min(min_cost[(n - 1) % 2][0], + min(min_cost[(n - 1) % 2][1], min_cost[(n - 1) % 2][2])); + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + int minCost(vector>& costs) { + if (costs.empty()) { + return 0; + } + + const int n = costs.size(); + for (int i = 1; i < n; ++i) { + costs[i][0] += min(costs[i - 1][1], costs[i - 1][2]); + costs[i][1] += min(costs[i - 1][0], costs[i - 1][2]); + costs[i][2] += min(costs[i - 1][0], costs[i - 1][1]); + } + + return min(costs[n - 1][0], min(costs[n - 1][1], costs[n - 1][2])); + } +}; diff --git a/C++/palindrome-linked-list.cpp b/C++/palindrome-linked-list.cpp new file mode 100644 index 000000000..af5feef28 --- /dev/null +++ b/C++/palindrome-linked-list.cpp @@ -0,0 +1,43 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + bool isPalindrome(ListNode* head) { + // Reverse the first half list. + ListNode *reverse = nullptr, *fast = head; + while (fast && fast->next) { + fast = fast->next->next; + const auto head_next = head->next; + head->next = reverse; + reverse = head; + head = head_next; + } + + // If the number of the nodes is odd, + // set the head of the tail list to the next of the median node. + ListNode *tail = fast ? head->next : head; + + // Compare the reversed first half list with the second half list. + // And restore the reversed first half list. + bool is_palindrome = true; + while (reverse) { + is_palindrome = is_palindrome && reverse->val == tail->val; + const auto reverse_next = reverse->next; + reverse->next = head; + head = reverse; + reverse = reverse_next; + tail = tail->next; + } + + return is_palindrome; + } +}; diff --git a/C++/palindrome-number.cpp b/C++/palindrome-number.cpp new file mode 100644 index 000000000..6c32423e2 --- /dev/null +++ b/C++/palindrome-number.cpp @@ -0,0 +1,44 @@ +// Time: O(logx) = O(1) +// Space: O(1) + +class Solution { +public: + bool isPalindrome(int x) { + if (x < 0) { + return false; + } + int temp = x; + int reversed = 0; + while (temp != 0) { + reversed = reversed * 10 + temp % 10; + temp = temp / 10; + } + return reversed == x; + } +}; + +// Time: O(logx) = O(1) +// Space: O(1) +class Solution2 { +public: + bool isPalindrome(int x) { + if(x < 0) { + return false; + } + + int divisor = 1; + while (x / divisor >= 10) { + divisor *= 10; + } + + for (; x > 0; x = (x % divisor) / 10, divisor /= 100) { + int left = x / divisor; + int right = x % 10; + if (left != right) { + return false; + } + } + + return true; + } +}; diff --git a/C++/palindrome-pairs.cpp b/C++/palindrome-pairs.cpp new file mode 100644 index 000000000..8b108b478 --- /dev/null +++ b/C++/palindrome-pairs.cpp @@ -0,0 +1,181 @@ +// Time: O(n * k^2), n is the number of the words, k is the max length of the words. +// Space: O(n * k) + +class Solution { +public: + vector> palindromePairs(vector& words) { + vector> res; + unordered_map lookup; + for (int i = 0; i < words.size(); ++i) { + lookup[words[i]] = i; + } + + for (int i = 0; i < words.size(); ++i) { + for (int j = 0; j <= words[i].length(); ++j) { + if (is_palindrome(words[i], j, words[i].length() - 1)) { + string suffix = words[i].substr(0, j); + reverse(suffix.begin(), suffix.end()); + if (lookup.find(suffix) != lookup.end() && i != lookup[suffix]) { + res.push_back({i, lookup[suffix]}); + } + } + if (j > 0 && is_palindrome(words[i], 0, j - 1)) { + string prefix = words[i].substr(j); + reverse(prefix.begin(), prefix.end()); + if (lookup.find(prefix) != lookup.end() && lookup[prefix] != i) { + res.push_back({lookup[prefix], i}); + } + } + } + } + return res; + } + +private: + bool is_palindrome(string& s, int start, int end) { + while (start < end) { + if (s[start++] != s[end--]) { + return false; + } + } + return true; + } +}; + +// Time: O(n * k^2), n is the number of the words, k is the max length of the words. +// Space: O(n * k^2) +// Manacher solution. +class Solution2 { +public: + vector> palindromePairs(vector& words) { + unordered_multimap prefix, suffix; + for (int i = 0; i < words.size(); ++i) { // O(n) + vector P; + manacher(words[i], &P); + for (int j = 0; j < P.size(); ++j) { // O(k) + if (j - P[j] == 1) { + prefix.emplace(words[i].substr((j + P[j]) / 2), i); // O(k) + } + if (j + P[j] == P.size() - 2) { + suffix.emplace(words[i].substr(0, (j - P[j]) / 2), i); + } + } + } + + vector> res; + for (int i = 0; i < words.size(); ++i) { // O(n) + string reversed_word(words[i].rbegin(), words[i].rend()); // O(k) + auto its = prefix.equal_range(reversed_word); + for (auto it = its.first; it != its.second; ++it) { + if (it->second != i) { + res.push_back({i, it->second}); + } + } + its = suffix.equal_range(reversed_word); + for (auto it = its.first; it != its.second; ++it) { + if (words[i].size() != words[it->second].size()) { + res.push_back({it->second, i}); + } + } + } + return res; + } + + void manacher(const string& s, vector *P) { + string T = preProcess(s); + const int n = T.length(); + P->resize(n); + int C = 0, R = 0; + for (int i = 1; i < n - 1; ++i) { + int i_mirror = 2 * C - i; + (*P)[i] = (R > i) ? min(R - i, (*P)[i_mirror]) : 0; + while (T[i + 1 + (*P)[i]] == T[i - 1 - (*P)[i]]) { + ++(*P)[i]; + } + if (i + (*P)[i] > R) { + C = i; + R = i + (*P)[i]; + } + } + } + + string preProcess(const string& s) { + if (s.empty()) { + return "^$"; + } + string ret = "^"; + for (int i = 0; i < s.length(); ++i) { + ret += "#" + s.substr(i, 1); + } + ret += "#$"; + return ret; + } +}; + +// Time: O(n * k^2), n is the number of the words, k is the max length of the words. +// Space: O(n * k) +// Trie solution. +class Solution_MLE { +public: + vector> palindromePairs(vector& words) { + vector> res; + TrieNode trie; + for (int i = 0; i < words.size(); ++i) { + trie.insert(words[i], i); + } + for (int i = 0; i < words.size(); ++i) { + trie.find(words[i], i, &res); + } + return res; + } + +private: + struct TrieNode { + int word_idx = -1; + unordered_map leaves; + + void insert(const string& s, int i) { + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + p->leaves[c] = new TrieNode; + } + p = p->leaves[c]; + } + p->word_idx = i; + } + + void find(const string& s, int idx, vector> *res) { + auto* p = this; + for (int i = s.length() - 1; i >= 0; --i) { // O(k) + if (p->leaves.find(s[i]) != p->leaves.cend()) { + p = p->leaves[s[i]]; + if (p->word_idx != -1 && p->word_idx != idx && + is_palindrome(s, i - 1)) { // O(k) + res->push_back({p->word_idx, idx}); + } + } else { + break; + } + } + } + + bool is_palindrome(const string& s, int j) { + int i = 0; + while (i <= j) { + if (s[i++] != s[j--]) { + return false; + } + } + return true; + } + + ~TrieNode() { + for (auto& kv : leaves) { + if (kv.second) { + delete kv.second; + } + } + } + }; +}; diff --git a/C++/palindrome-permutation-ii.cpp b/C++/palindrome-permutation-ii.cpp new file mode 100644 index 000000000..806824177 --- /dev/null +++ b/C++/palindrome-permutation-ii.cpp @@ -0,0 +1,96 @@ +// Time: O(n * n!) +// Space: O(n) + +class Solution { +public: + vector generatePalindromes(string s) { + if (s.empty()) { + return {}; + } + + unordered_map cnt; + for (const auto& c : s) { + ++cnt[c]; + } + + string mid, chars; + for (const auto& kvp : cnt) { + if (kvp.second % 2) { + if (mid.empty()) { + mid.push_back(kvp.first); + } else { // The count of the middle char is at most one. + return {}; + } + } + chars.append(kvp.second / 2, kvp.first); + } + return permuteUnique(mid, chars); + } + + vector permuteUnique(const string& mid, string& chars) { + vector result; + sort(chars.begin(), chars.end()); + do { + string reverse_chars(chars.crbegin(), chars.crend()); + result.emplace_back(chars + mid + reverse_chars); + } while (next_permutation(chars.begin(), chars.end())); + return result; + } +}; + +class Solution2 { +public: + vector generatePalindromes(string s) { + if (s.empty()) { + return {}; + } + + unordered_map cnt; + for (const auto& c : s) { + ++cnt[c]; + } + + string mid, chars; + for (const auto& kvp : cnt) { + if (kvp.second % 2) { + if (mid.empty()) { + mid.append(1, kvp.first); + } else { // The count of the middle char is at most one. + return {}; + } + } + chars.append(kvp.second / 2, kvp.first); + } + + return permuteUnique(mid, chars); + } + + vector permuteUnique(const string& mid, string& s) { + vector result; + vector used(s.length(), false); + string ans; + + sort(s.begin(), s.end()); + permuteUniqueRecu(mid, s, &used, &ans, &result); + return result; + } + + void permuteUniqueRecu(const string& mid, const string& s, vector *used, + string *ans, vector *result) { + if (ans->length() == s.length()) { + string reverse_ans(ans->crbegin(), ans->crend()); + result->emplace_back(*ans + mid + reverse_ans); + return; + } + + for (int i = 0; i < s.length(); ++i) { + if (!(*used)[i] && !(i != 0 && s[i - 1] == s[i] && (*used)[i - 1])) { + (*used)[i] = true; + ans->push_back(s[i]); + permuteUniqueRecu(mid, s, used, ans, result); + ans->pop_back(); + (*used)[i] = false; + } + } + } +}; diff --git a/C++/palindrome-permutation.cpp b/C++/palindrome-permutation.cpp new file mode 100644 index 000000000..f68d5cba3 --- /dev/null +++ b/C++/palindrome-permutation.cpp @@ -0,0 +1,13 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool canPermutePalindrome(string s) { + bitset<256> bits; + for (const auto& c : s) { + bits.flip(c); + } + return bits.count() < 2; + } +}; diff --git a/C++/palindromic-substrings.cpp b/C++/palindromic-substrings.cpp new file mode 100644 index 000000000..f3012a70f --- /dev/null +++ b/C++/palindromic-substrings.cpp @@ -0,0 +1,46 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int countSubstrings(string s) { + auto result = 0; + for (const auto& max_len : manacher(s)) { + result += (max_len + 1) / 2; + } + return result; + } + +private: + vector manacher(const string& s) { + string T = preProcess(s); + const int n = T.length(); + vector P(n); + int C = 0, R = 0; + for (int i = 1; i < n - 1; ++i) { + int i_mirror = 2 * C - i; + P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; + while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) { + ++P[i]; + } + if (i + P[i] > R) { + C = i; + R = i + P[i]; + } + } + return P; + } + + string preProcess(const string& s) { + if (s.empty()) { + return "^$"; + } + string ret = "^"; + for (int i = 0; i < s.length(); ++i) { + ret += "#" + s.substr(i, 1); + } + ret += "#$"; + return ret; + } +}; + diff --git a/C++/parse-lisp-expression.cpp b/C++/parse-lisp-expression.cpp new file mode 100644 index 000000000..9fdb3b225 --- /dev/null +++ b/C++/parse-lisp-expression.cpp @@ -0,0 +1,50 @@ +// Time: O(n^2) +// Space: O(n^2) + +class Solution { +public: + int evaluate(string expression) { + vector tokens{""}; + unordered_map lookup; + vector, unordered_map>> stk; + for (const auto& c : expression) { + if (c == '(') { + if (tokens[0] == "let") { + evaluate(tokens, &lookup); + } + stk.emplace_back(move(tokens), lookup); + tokens = {""}; + } else if (c == ' ') { + tokens.emplace_back(); + } else if (c == ')') { + const auto& val = evaluate(tokens, &lookup); + tie(tokens, lookup) = move(stk.back()); + stk.pop_back(); + tokens.back() += val; + } else { + tokens.back().push_back(c); + } + } + return stoi(tokens[0]); + } + +private: + string evaluate(const vector& tokens, unordered_map* lookup) { + static const unordered_set operators{"add", "mult"}; + if (operators.count(tokens[0])) { + const auto& a = stoi(getval(*lookup, tokens[1])); + const auto& b = stoi(getval(*lookup, tokens[2])); + return to_string(tokens[0] == "add" ? a + b : a * b); + } + for (int i = 1; i < tokens.size() - 1; i += 2) { + if (!tokens[i + 1].empty()) { + (*lookup)[tokens[i]] = getval(*lookup, tokens[i + 1]); + } + } + return getval(*lookup, tokens.back()); + } + + string getval(const unordered_map& lookup, const string& x) { + return lookup.count(x) ? lookup.at(x) : x; + } +}; diff --git a/C++/partition-equal-subset-sum.cpp b/C++/partition-equal-subset-sum.cpp new file mode 100644 index 000000000..d9723bb52 --- /dev/null +++ b/C++/partition-equal-subset-sum.cpp @@ -0,0 +1,23 @@ +// Time: O(n * s), s is the sum of nums. +// Space: O(s) + +class Solution { +public: + bool canPartition(vector& nums) { + const auto sum = accumulate(nums.cbegin(), nums.cend(), 0); + if (sum % 2) { + return false; + } + + vector dp(sum / 2 + 1); + dp[0] = true; + for (const auto& num : nums) { + for (int i = 1; i < dp.size(); ++i) { + if (num <= i) { + dp[i] = dp[i] || dp[i - num]; + } + } + } + return dp.back(); + } +}; diff --git a/C++/partition-list.cpp b/C++/partition-list.cpp new file mode 100644 index 000000000..b3a38a912 --- /dev/null +++ b/C++/partition-list.cpp @@ -0,0 +1,35 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *partition(ListNode *head, int x) { + ListNode dummy_smaller{0}; + ListNode dummy_larger{0}; + auto smaller = &dummy_smaller; + auto larger = &dummy_larger; + + while (head) { + if (head->val < x) { + smaller->next = head; + smaller = smaller->next; + } else { + larger->next = head; + larger = larger->next; + } + head = head->next; + } + smaller->next = dummy_larger.next; + larger->next = nullptr; + + return dummy_smaller.next; + } +}; diff --git a/C++/partition-to-k-equal-sum-subsets.cpp b/C++/partition-to-k-equal-sum-subsets.cpp new file mode 100644 index 000000000..cc1dab60c --- /dev/null +++ b/C++/partition-to-k-equal-sum-subsets.cpp @@ -0,0 +1,72 @@ +// Time: O(n*2^n) +// Space: O(2^n) + +// Memoization solution. +class Solution { +public: + bool canPartitionKSubsets(vector& nums, int k) { + auto sum = accumulate(nums.begin(), nums.end(), 0); + if (sum % k != 0 || *max_element(nums.begin(), nums.end()) > sum / k) { + return false; + } + unordered_map lookup; + lookup[(1 << nums.size()) - 1] = true; + return dfs(nums, sum / k, 0, sum, &lookup); + } + +private: + bool dfs(const vector& nums, const int target, + const int used, const int todo, + unordered_map *lookup) { + if (!lookup->count(used)) { + const auto targ = (todo - 1) % target + 1; + for (int i = 0; i < nums.size(); ++i) { + if (((used >> i) & 1) == 0 && nums[i] <= targ) { + if (dfs(nums, target, used | (1 << i), todo - nums[i], lookup)) { + (*lookup)[used] = true; + break; + } + } + } + } + return (*lookup)[used]; + } +}; + +// Time: O(k^(n-k) * k!) +// Space: O(n) +// DFS solution with pruning. +class Solution2 { +public: + bool canPartitionKSubsets(vector& nums, int k) { + auto sum = accumulate(nums.begin(), nums.end(), 0); + if (sum % k != 0 || *max_element(nums.begin(), nums.end()) > sum / k) { + return false; + } + sort(nums.begin(), nums.end(), greater()); // speedup dfs + vector subset_sums(k); + return dfs(nums, sum / k, 0, &subset_sums); + } + +private: + bool dfs(const vector &nums, const int target, + const int i, vector *subset_sums) { + if (i == nums.size()) { + return true; + } + for (auto& subset_sum : *subset_sums) { + if (subset_sum + nums[i] > target) { + continue; + } + subset_sum += nums[i]; + if (dfs(nums, target, i + 1, subset_sums)) { + return true; + } + subset_sum -= nums[i]; + if (subset_sum == 0) { // pruning + break; + } + } + return false; + } +}; diff --git a/C++/partition.cpp b/C++/partition.cpp deleted file mode 100644 index 70e9b8da0..000000000 --- a/C++/partition.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *partition(ListNode *head, int x) { - ListNode left_dummy(-1); - ListNode right_dummy(-1); - auto left_cur = &left_dummy; - auto right_cur = &right_dummy; - - for(auto cur = head; cur; cur = cur->next) { - if(cur->val < x) { - left_cur->next = cur; - left_cur = cur; - } - else { - right_cur->next = cur; - right_cur = cur; - } - } - - left_cur->next = right_dummy.next; - right_cur->next = nullptr; - return left_dummy.next; - } -}; diff --git a/C++/pascals-triangle-ii.cpp b/C++/pascals-triangle-ii.cpp new file mode 100644 index 000000000..5c11c9346 --- /dev/null +++ b/C++/pascals-triangle-ii.cpp @@ -0,0 +1,18 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + vector getRow(int rowIndex) { + vector result(rowIndex + 1); + for (int i = 0; i < result.size(); ++i) { + int prev_result = result[0] = 1; + for (int j = 1; j <= i; ++j) { + const int tmp = result[j]; + result[j] += prev_result; + prev_result = tmp; + } + } + return result; + } +}; diff --git a/C++/pascals-triangle.cpp b/C++/pascals-triangle.cpp new file mode 100644 index 000000000..95a723551 --- /dev/null +++ b/C++/pascals-triangle.cpp @@ -0,0 +1,21 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + vector> generate(int numRows) { + vector> result; + for (int i = 0; i < numRows; ++i) { + result.push_back({}); + for (int j = 0; j <= i; ++j) { + if (j == 0 || j == i) { + result[i].emplace_back(1); + } else { + result[i].emplace_back(result[i - 1][j - 1] + + result[i - 1][j]); + } + } + } + return result; + } +}; diff --git a/C++/patching-array.cpp b/C++/patching-array.cpp new file mode 100644 index 000000000..81e054547 --- /dev/null +++ b/C++/patching-array.cpp @@ -0,0 +1,18 @@ +// Time: O(s + logn), s is the number of elements in the array +// Space: O(1) + +class Solution { +public: + int minPatches(vector& nums, int n) { + int patch = 0; + for (uint64_t miss = 1, i = 0; miss <= n;) { + if (i < nums.size() && nums[i] <= miss) { + miss += nums[i++]; + } else { + miss += miss; // miss may overflow, thus prefer to use uint64_t. + ++patch; + } + } + return patch; + } +}; diff --git a/C++/path-sum-iii.cpp b/C++/path-sum-iii.cpp new file mode 100644 index 000000000..7723668dc --- /dev/null +++ b/C++/path-sum-iii.cpp @@ -0,0 +1,58 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int pathSum(TreeNode* root, int sum) { + unordered_map lookup; + lookup[0] = 1; + return pathSumHelper(root, 0, sum, &lookup); + } + +private: + int pathSumHelper(TreeNode* root, int curr, int sum, unordered_map *lookup) { + if (!root) { + return 0; + } + curr += root->val; + int result = lookup->count(curr - sum) ? (*lookup)[curr - sum] : 0; + ++(*lookup)[curr]; + result += pathSumHelper(root->left, curr, sum, lookup) + pathSumHelper(root->right, curr, sum, lookup); + --(*lookup)[curr]; + if ((*lookup)[curr] == 0) { + lookup->erase(curr); + } + return result; + } +}; + + +// Time: O(n^2) +// Space: O(h) +class Solution2 { +public: + int pathSum(TreeNode* root, int sum) { + if (!root) { + return 0; + } + return pathSumHelper(root, 0, sum) + pathSum(root->left, sum) + pathSum(root->right, sum); + } + +private: + int pathSumHelper(TreeNode* root, int prev, int sum) { + if (!root) { + return 0; + } + int curr = prev + root->val; + return (curr == sum) + pathSumHelper(root->left, curr, sum) + pathSumHelper(root->right, curr, sum); + } +}; diff --git a/C++/path-sum-iv.cpp b/C++/path-sum-iv.cpp new file mode 100644 index 000000000..6d6bbec0f --- /dev/null +++ b/C++/path-sum-iv.cpp @@ -0,0 +1,41 @@ +// Time: O(n) +// Space: O(p), p is the number of paths + +class Solution { +public: + int pathSum(vector& nums) { + if (nums.empty()) { + return 0; + } + int result = 0; + queue q; + node dummy(10); + auto parent_ptr = &dummy; + for (const auto& num : nums) { + node child(num); + while (!parent_ptr->isParent(child)) { + result += parent_ptr->leaf ? parent_ptr->val : 0; + parent_ptr = &q.front(); + q.pop(); + } + parent_ptr->leaf = false; + child.val += parent_ptr->val; + q.emplace(move(child)); + } + while (!q.empty()) { + result += q.front().val; + q.pop(); + } + return result; + } + +private: + struct node { + int level, i, val; + bool leaf; + node(int n) : level(n / 100 - 1), i((n % 100) / 10 - 1), val(n % 10), leaf(true) {}; + inline bool isParent(const node& other) { + return level == other.level - 1 && i == other.i / 2; + }; + }; +}; diff --git a/C++/peeking-iterator.cpp b/C++/peeking-iterator.cpp new file mode 100644 index 000000000..fa5e500be --- /dev/null +++ b/C++/peeking-iterator.cpp @@ -0,0 +1,54 @@ +// Time: O(1) per peek(), next(), hasNext() +// Space: O(1) + +// Below is the interface for Iterator, which is already defined for you. +// **DO NOT** modify the interface for Iterator. +class Iterator { + struct Data; + Data* data; +public: + Iterator(const vector& nums); + Iterator(const Iterator& iter); + virtual ~Iterator(); + // Returns the next element in the iteration. + int next(); + // Returns true if the iteration has more elements. + bool hasNext() const; +}; + + +class PeekingIterator : public Iterator { +public: + PeekingIterator(const vector& nums) : Iterator(nums), has_next_(Iterator::hasNext()) { + // Initialize any member here. + // **DO NOT** save a copy of nums and manipulate it directly. + // You should only use the Iterator interface methods. + } + + // Returns the next element in the iteration without advancing the iterator. + int peek() { + if (!has_peeked_) { + has_peeked_ = true; + val_ = Iterator::next(); + } + return val_; + } + + // hasNext() and next() should behave the same as in the Iterator interface. + // Override them if needed. + int next() { + val_ = peek(); + has_peeked_ = false; + has_next_ = Iterator::hasNext(); + return val_; + } + + bool hasNext() const { + return has_next_; + } + +private: + int val_; + bool has_next_; + bool has_peeked_ = false; +}; diff --git a/C++/perfect-number.cpp b/C++/perfect-number.cpp new file mode 100644 index 000000000..c3516c4ca --- /dev/null +++ b/C++/perfect-number.cpp @@ -0,0 +1,21 @@ +// Time: O(sqrt(n)) +// Space: O(1) + +class Solution { +public: + bool checkPerfectNumber(int num) { + if (num <= 0) { + return false; + } + int sum = 0; + for (int i = 1; i * i <= num; ++i) { + if (num % i == 0) { + sum += i; + if (i * i != num) { + sum += num / i; + } + } + } + return sum - num == num; + } +}; diff --git a/C++/perfect-rectangle.cpp b/C++/perfect-rectangle.cpp new file mode 100644 index 000000000..96d72b5df --- /dev/null +++ b/C++/perfect-rectangle.cpp @@ -0,0 +1,49 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + bool isRectangleCover(vector>& rectangles) { + enum Location {L = 0, B = 1, R = 2, T = 3}; + int left = numeric_limits::max(), bottom = numeric_limits::max(), + right = numeric_limits::min(), top = numeric_limits::min(); + for (const auto& rect : rectangles) { + left = min(left, rect[L]); + bottom = min(bottom, rect[B]); + right = max(right, rect[R]); + top = max(top, rect[T]); + } + + using P = pair, int>; + enum Corner {LB = 1, RB = 2, LT = 4, RT = 8}; + unordered_map> corner_count; + vector

corners{{{L, B}, LB}, {{R, B}, RB}, {{L, T}, LT}, {{R, T}, RT}}; + for (const auto& rect : rectangles) { + for (const auto& corner : corners) { + const auto x = rect[corner.first.first]; + const auto y = rect[corner.first.second]; + if (corner_count[x][y] & corner.second) { + return false; + } + corner_count[x][y] |= corner.second; + } + } + + bitset<16> is_valid; + is_valid[LB | RB] = is_valid[LB | LT] = is_valid[RB | RT] = is_valid[LT | RT] = is_valid[LB | RB | LT | RT] = true; + for (auto itx = corner_count.cbegin(); itx != corner_count.cend(); ++itx) { + const auto x = itx->first; + for (auto ity = itx->second.cbegin(); ity != itx->second.cend(); ++ity) { + const auto y = ity->first; + const auto mask = ity->second; + if ((left < x && x < right) || (bottom < y && y < top)) { + if (!is_valid[mask]) { + return false; + } + } + } + } + + return true; + } +}; diff --git a/C++/perfect-squares.cpp b/C++/perfect-squares.cpp new file mode 100644 index 000000000..15188df34 --- /dev/null +++ b/C++/perfect-squares.cpp @@ -0,0 +1,33 @@ +// Time: O(n * sqrt(n)) +// Space: O(n) + +class Solution { +public: + int numSquares(int n) { + static vector num{0}; + while (num.size() <= n) { + int squares = numeric_limits::max(); + for (int i = 1; i * i <= num.size(); ++i) { + squares = min(squares, num[num.size() - i * i] + 1); + } + num.emplace_back(squares); + } + return num[n]; + } +}; + +// Time: O(n * sqrt(n)) +// Space: O(n) +class Solution2 { +public: + int numSquares(int n) { + vector num(n + 1, numeric_limits::max()); + num[0] = 0; + for (int i = 0; i <= n; ++i) { + for (int j = i - 1, k = 1; j >= 0; ++k, j = i - k * k) { + num[i] = min(num[i], num[j] + 1); + } + } + return num[n]; + } +}; diff --git a/C++/permutation-in-string.cpp b/C++/permutation-in-string.cpp new file mode 100644 index 000000000..daaf56889 --- /dev/null +++ b/C++/permutation-in-string.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool checkInclusion(string s1, string s2) { + vector counts(256); + for (const auto& c : s1) { + ++counts[c]; + } + for (int i = 0, l = s1.length(); i < s2.length(); ++i) { + if (counts[s2[i]]-- > 0) { + --l; + } + if (l == 0) { + return true; + } + int start = i + 1 - s1.length(); + if (start >= 0 && ++counts[s2[start]] > 0) { + ++l; + } + } + return false; + } +}; diff --git a/C++/permutation-sequence.cpp b/C++/permutation-sequence.cpp new file mode 100644 index 000000000..c3a4e3c98 --- /dev/null +++ b/C++/permutation-sequence.cpp @@ -0,0 +1,33 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + string getPermutation(int n, int k) { + vector nums; + int total = 1; + for (int i = 1; i <= n; ++i) { + nums.emplace_back(i); + total *= i; + } + + // Cantor Ordering: + // Construct the k-th permutation with a list of n numbers + // Idea: group all permutations according to their first number (so n groups, each of + // (n - 1)! numbers), find the group where the k-th permutation belongs, remove the common + // first number from the list and append it to the resulting string, and iteratively + // construct the (((k - 1) % (n - 1)!) + 1)-th permutation with the remaining n-1 numbers + int group = total; + stringstream permutation; + while (n > 0) { + group /= n; + int idx = (k - 1) / group; + permutation << nums[idx]; + nums.erase(nums.begin() + idx); + k = (k - 1) % group + 1; + --n; + } + + return permutation.str(); + } +}; diff --git a/C++/plus-one-linked-list.cpp b/C++/plus-one-linked-list.cpp new file mode 100644 index 000000000..f7e097520 --- /dev/null +++ b/C++/plus-one-linked-list.cpp @@ -0,0 +1,88 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ + // Two pointers solution. +class Solution { +public: + ListNode* plusOne(ListNode* head) { + if (!head) { + return nullptr; + } + + auto dummy = new ListNode{0}; + dummy->next = head; + + auto left = dummy, right = head; + while (right->next) { + if (right->val != 9) { + left = right; + } + right = right->next; + } + + if (right->val != 9) { + ++right->val; + } else { + ++left->val; + right = left->next; + while (right) { + right->val = 0; + right = right->next; + } + } + + if (dummy->val == 0) { + head = dummy->next; + delete dummy; + return head; + } + + return dummy; + } +}; + +// Time: O(n) +// Space: O(1) +class Solution2 { +public: + ListNode* plusOne(ListNode* head) { + auto rev_head = reverseList(head); + + auto curr = rev_head; + int carry = 1; + while (curr && carry) { + curr->val += carry; + carry = curr->val / 10; + curr->val %= 10; + if (carry && !curr->next) { + curr->next = new ListNode(0); + } + curr = curr->next; + } + + return reverseList(rev_head); + } + +private: + ListNode* reverseList(ListNode* head) { + ListNode dummy{0}; + auto curr = head; + + while (curr) { + auto tmp = curr->next; + curr->next = dummy.next; + dummy.next = curr; + curr = tmp; + } + + return dummy.next; + } +}; diff --git a/C++/plus-one.cpp b/C++/plus-one.cpp new file mode 100644 index 000000000..78d484a18 --- /dev/null +++ b/C++/plus-one.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector plusOne(vector& digits) { + vector result(digits.cbegin(), digits.cend()); + int carry = 1; + for (auto it = result.rbegin(); it != result.rend(); ++it) { + *it += carry; + carry = *it / 10; + *it %= 10; + } + if (carry == 1) { + result.emplace(result.begin(), carry); + } + return result; + } +}; diff --git a/C++/plusOne.cpp b/C++/plusOne.cpp deleted file mode 100644 index d158b2a77..000000000 --- a/C++/plusOne.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - vector plusOne(vector &digits) { - int c = 1; - - for(auto it = digits.rbegin(); it != digits.rend(); ++it) { - *it += c; - c = *it / 10; - *it %= 10; - } - - if(c > 0) { - digits.insert(digits.begin(), 1); - } - - return digits; - } -}; diff --git a/C++/poor-pigs.cpp b/C++/poor-pigs.cpp new file mode 100644 index 000000000..bee9ffa4b --- /dev/null +++ b/C++/poor-pigs.cpp @@ -0,0 +1,9 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int poorPigs(int buckets, int minutesToDie, int minutesToTest) { + return ceil(log(buckets) / log(minutesToTest / minutesToDie + 1)); + } +}; diff --git a/C++/pow.cpp b/C++/pow.cpp deleted file mode 100644 index 4877d7443..000000000 --- a/C++/pow.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Time Complexity: O(logn) -// Space Complexity: O(logn) - -class Solution { - public: - double pow(double x, int n) { - if(n < 0) - return 1.0 / power(x, -n); // be careful: -1 * -2147483648 is still -2147483648 - else - return power(x, n); - } - - private: - double power(double x, int n) { - if(n == 0) - return 1; - double v = power(x, n / 2); - - if(n % 2 != 0) - return v * v * x; - else - return v * v; - } -}; diff --git a/C++/power-of-four.cpp b/C++/power-of-four.cpp new file mode 100644 index 000000000..0bcca2d46 --- /dev/null +++ b/C++/power-of-four.cpp @@ -0,0 +1,22 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + bool isPowerOfFour(int num) { + return num > 0 && (num & (num - 1)) == 0 && + ((num & 0b01010101010101010101010101010101) == num); + } +}; + +// Time: O(1) +// Space: O(1) +class Solution2 { +public: + bool isPowerOfFour(int num) { + while (num && !(num & 0b11)) { + num >>= 2; + } + return (num == 1); + } +}; diff --git a/C++/power-of-three.cpp b/C++/power-of-three.cpp new file mode 100644 index 000000000..73f196331 --- /dev/null +++ b/C++/power-of-three.cpp @@ -0,0 +1,12 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + static const int max_log3 = log(numeric_limits::max()) / log(3); + static const int max_pow3 = pow(3, max_log3); + + bool isPowerOfThree(int n) { + return n > 0 && max_pow3 % n == 0; + } +}; diff --git a/C++/power-of-two.cpp b/C++/power-of-two.cpp new file mode 100644 index 000000000..d0261cad9 --- /dev/null +++ b/C++/power-of-two.cpp @@ -0,0 +1,16 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + bool isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +}; + +class Solution2 { +public: + bool isPowerOfTwo(int n) { + return n > 0 && (n & ~-n) == 0; + } +}; diff --git a/C++/powx-n.cpp b/C++/powx-n.cpp new file mode 100644 index 000000000..652600ee8 --- /dev/null +++ b/C++/powx-n.cpp @@ -0,0 +1,40 @@ +// Time: O(logn) = O(1) +// Space: O(1) + +// Iterative solution. +class Solution { +public: + double myPow(double x, int n) { + double result = 1; + long long abs_n = abs(static_cast(n)); + while (abs_n > 0) { + if (abs_n & 1) { + result *= x; + } + abs_n >>= 1; + x *= x; + } + return n < 0 ? 1 / result : result; + } +}; + +// Time: O(logn) = O(1) +// Space: O(logn) = O(1) +// Recursive solution. +class Solution2 { +public: + double myPow(double x, int n) { + if (n < 0 && n != -n) { + return 1.0 / myPow(x, -n); + } + if (n == 0) { + return 1; + } + double v = myPow(x, n / 2); + if (n % 2 == 0) { + return v * v; + } else { + return v * v * x; + } + } +}; diff --git a/C++/predict-the-winner.cpp b/C++/predict-the-winner.cpp new file mode 100644 index 000000000..4cda5afd5 --- /dev/null +++ b/C++/predict-the-winner.cpp @@ -0,0 +1,21 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + bool PredictTheWinner(vector& nums) { + if (nums.size() % 2 == 0 || nums.size() == 1) { + return true; + } + + vector dp(nums.size()); + for (int i = nums.size() - 1; i >= 0; --i) { + dp[i] = nums[i]; + for (int j = i + 1; j < nums.size(); ++j) { + dp[j] = max(nums[i] - dp[j], nums[j] - dp[j - 1]); + } + } + + return dp.back() >= 0; + } +}; diff --git a/C++/prefix-and-suffix-search.cpp b/C++/prefix-and-suffix-search.cpp new file mode 100644 index 000000000..644b4378d --- /dev/null +++ b/C++/prefix-and-suffix-search.cpp @@ -0,0 +1,139 @@ +// Time: ctor: O(w * l^2), w is the number of words, l is the word length on average +// search: O(p + s) , p is the length of the prefix, s is the length of the suffix, +// Space: O(t), t is the number of trie nodes + +class WordFilter { +public: + WordFilter(vector words) { + for (int i = 0; i < words.size(); ++i) { + for (int j = 0; j <= words[i].length(); ++j) { + trie_.insert(words[i].substr(j) + SEPARATOR + words[i], i); + } + } + } + + int f(string prefix, string suffix) { + return trie_.find(suffix + SEPARATOR + prefix); + } + +private: + struct TrieNode { + int weight; + vector leaves; + + TrieNode() : weight(0), leaves(27) {} + + void insert(const string& s, const int weight) { + auto* p = this; + p->weight = weight; + for (const auto& c : s) { + if (!p->leaves[c - 'a']) { + p->leaves[c - 'a'] = new TrieNode; + } + p = p->leaves[c - 'a']; + p->weight = weight; + } + } + + int find(const string& s) const { + auto* p = this; + for (const auto& c : s) { + if (!p->leaves[c - 'a']) { + return -1; + } + p = p->leaves[c - 'a']; + } + return p->weight; + } + + ~TrieNode() { + for (auto& node : leaves) { + if (node) { + delete node; + } + } + } + }; + const string SEPARATOR = "{"; // ascii code of 'z' + 1 + TrieNode trie_; +}; + +// Time: ctor: O(w * l), w is the number of words, l is the word length on average +// search: O(p + s + max(m, n)), p is the length of the prefix, s is the length of the suffix, +// m is the number of the prefix match, n is the number of the suffix match +// Space: O(w * l) +class WordFilter2 { +public: + WordFilter(vector words) { + for (int i = words.size() - 1; i >= 0; --i) { + auto word = words[i]; + prefix_trie_.insert(word, i); + reverse(word.begin(), word.end()); + suffix_trie_.insert(word, i); + } + } + + int f(string prefix, string suffix) { + const auto& prefix_match = prefix_trie_.find(prefix); + reverse(suffix.begin(), suffix.end()); + const auto& suffix_match = suffix_trie_.find(suffix); + int i = 0, j = 0; + while (i != prefix_match.size() && j != suffix_match.size()) { + if (prefix_match[i] == suffix_match[j]) { + return prefix_match[i]; + } else if (prefix_match[i] > suffix_match[j]) { + ++i; + } else { + ++j; + } + } + return -1; + } + +private: + struct TrieNode { + vector words; // index of words + vector leaves; + + TrieNode() : leaves(26) {} + + void insert(const string& s, const int i) { + auto* p = this; + p->words.emplace_back(i); + for (const auto& c : s) { + if (!p->leaves[c - 'a']) { + p->leaves[c - 'a'] = new TrieNode; + } + p = p->leaves[c - 'a']; + p->words.emplace_back(i); + } + } + + const vector& find(const string& s) const { + auto* p = this; + for (const auto& c : s) { + if (!p->leaves[c - 'a']) { + static const vector empty; + return empty; + } + p = p->leaves[c - 'a']; + } + return p->words; + } + + ~TrieNode() { + for (auto& node : leaves) { + if (node) { + delete node; + } + } + } + }; + TrieNode prefix_trie_, suffix_trie_; +}; + +/** + * Your WordFilter object will be instantiated and called as such: + * WordFilter obj = new WordFilter(words); + * int param_1 = obj.f(prefix,suffix); + */ diff --git a/C++/print-binary-tree.cpp b/C++/print-binary-tree.cpp new file mode 100644 index 000000000..12f1ac47d --- /dev/null +++ b/C++/print-binary-tree.cpp @@ -0,0 +1,46 @@ +// Time: O(h * 2^h) +// Space: O(h * 2^h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector> printTree(TreeNode* root) { + auto h = getHeight(root), w = getWidth(root); + vector> result(h, vector(w, "")); + preorderTraversal(root, 0, 0, w - 1, &result); + return result; + } + +private: + int getHeight(TreeNode* root) { + if (!root) { + return 0; + } + return max(getHeight(root->left), getHeight(root->right)) + 1; + } + + int getWidth(TreeNode* root) { + if (!root) { + return 0; + } + return 2 * max(getWidth(root->left), getWidth(root->right)) + 1; + } + + void preorderTraversal(TreeNode *root, int level, int left, int right, vector> *result) { + if (!root) { + return; + } + auto mid = left + (right - left) / 2; + (*result)[level][mid] = to_string(root->val); + preorderTraversal(root->left, level + 1, left, mid - 1, result); + preorderTraversal(root->right, level + 1, mid + 1, right, result); + } +}; diff --git a/C++/product-of-array-except-self.cpp b/C++/product-of-array-except-self.cpp new file mode 100644 index 000000000..0d516b10e --- /dev/null +++ b/C++/product-of-array-except-self.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector productExceptSelf(vector& nums) { + if (nums.empty()) { + return {}; + } + + vector left_product(nums.size()); + + left_product[0] = 1; + for (int i = 1; i < nums.size(); ++i) { + left_product[i] = left_product[i - 1] * nums[i - 1]; + } + + int right_product = 1; + for (int i = static_cast(nums.size()) - 2; i >= 0; --i) { + right_product *= nums[i + 1]; + left_product[i] = left_product[i] * right_product; + } + + return left_product; + } +}; diff --git a/C++/queue-reconstruction-by-height.cpp b/C++/queue-reconstruction-by-height.cpp new file mode 100644 index 000000000..0f5bf98cf --- /dev/null +++ b/C++/queue-reconstruction-by-height.cpp @@ -0,0 +1,57 @@ +// Time: O(n * sqrt(n)) +// Space: O(n) + +class Solution { +public: + vector> reconstructQueue(vector>& people) { + sort(people.begin(), people.end(), + [](const pair& a, pair& b) { + return b.first == a.first ? a.second < b.second : b.first < a.first; + }); + + vector>> blocks(1); + for (const auto& p : people) { + auto index = p.second; + int i = 0; + for (; i < blocks.size(); ++i) { + if (index <= blocks[i].size()) { + break; + } + index -= blocks[i].size(); + } + blocks[i].emplace(blocks[i].begin() + index, p); + + if (blocks[i].size() * blocks[i].size() > people.size()) { + blocks.emplace(blocks.begin() + i + 1, + blocks[i].begin() + blocks[i].size() / 2, + blocks[i].end()); + blocks[i].erase(blocks[i].begin() + blocks[i].size() / 2, blocks[i].end()); + } + } + + vector> result; + for (const auto& block : blocks) { + for (const auto& p : block) { + result.emplace_back(p); + } + } + return result; + } +}; + +// Time: O(n^2) +// Space: O(n) +class Solution2 { +public: + vector> reconstructQueue(vector>& people) { + sort(people.begin(), people.end(), + [](const pair& a, pair& b) { + return b.first == a.first ? a.second < b.second : b.first < a.first; + }); + vector> result; + for (const auto& p : people) { + result.emplace(result.begin() + p.second, p); + } + return result; + } +}; diff --git a/C++/random-pick-index.cpp b/C++/random-pick-index.cpp new file mode 100644 index 000000000..27e16a51c --- /dev/null +++ b/C++/random-pick-index.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + Solution(vector nums) : nums_(nums) { + + } + + int pick(int target) { + auto reservoir = -1; + auto n = 0; + for (int i = 0; i < nums_.size(); ++i) { + if (nums_[i] != target) { + continue; + } + if (rand() % ++n == 0) { + reservoir = i; + } + } + return reservoir; + } + +private: + const vector nums_; +}; + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(nums); + * int param_1 = obj.pick(target); + */ diff --git a/C++/range-addition-ii.cpp b/C++/range-addition-ii.cpp new file mode 100644 index 000000000..e9218c9d4 --- /dev/null +++ b/C++/range-addition-ii.cpp @@ -0,0 +1,13 @@ +// Time: O(p), p is the number of ops +// Space: O(1) + +class Solution { +public: + int maxCount(int m, int n, vector>& ops) { + for (const auto& op : ops) { + m = min(m, op[0]); + n = min(n, op[1]); + } + return m * n; + } +}; diff --git a/C++/range-addition.cpp b/C++/range-addition.cpp new file mode 100644 index 000000000..0664e622d --- /dev/null +++ b/C++/range-addition.cpp @@ -0,0 +1,22 @@ +// Time: O(k + n) +// Space: O(1) + +class Solution { +public: + vector getModifiedArray(int length, vector>& updates) { + vector result(length, 0); + + for (const auto& update: updates) { + result[update[0]] += update[2]; + if (update[1] + 1 < length) { + result[update[1] + 1] -= update[2]; + } + } + + for (int i = 1; i < length; ++i) { + result[i] += result[i - 1]; + } + + return result; + } +}; diff --git a/C++/range-module.cpp b/C++/range-module.cpp new file mode 100644 index 000000000..53e2c5402 --- /dev/null +++ b/C++/range-module.cpp @@ -0,0 +1,84 @@ +// Time: addRange: O(n) +// removeRange: O(n) +// queryRange: O(logn) +// Space: O(n) + +class RangeModule { +public: + RangeModule() { + + } + + // Time: O(n) + void addRange(int left, int right) { + vector> tmp; + int i = 0; + for (const auto& interval: intervals_) { + if (right < interval.first ) { + tmp.emplace_back(left, right); + break; + } else if (interval.second < left) { + tmp.emplace_back(interval); + } else { + left = min(left, interval.first); + right = max(right, interval.second); + } + ++i; + } + if (i == intervals_.size()) { + tmp.emplace_back(left, right); + } + while (i < intervals_.size()) { + tmp.emplace_back(intervals_[i++]); + } + swap(intervals_, tmp); + } + + // Time: O(logn) + bool queryRange(int left, int right) { + const auto it = lower_bound(intervals_.begin(), intervals_.end(), make_pair(left, right), + [](const pair& lhs, + const pair& rhs) { + return less{}(lhs.second, rhs.first); + }); + return it != intervals_.end() && it->first <= left && it->second >= right; + } + + // Time: O(logn) + bool queryRange2(int left, int right) { + auto it = lower_bound(intervals_.begin(), intervals_.end(), make_pair(left, numeric_limits::max())); + if (it != intervals_.begin()) { + it = prev(it); + } + return it != intervals_.end() && it->first <= left && it->second >= right; + } + + // Time: O(n) + void removeRange(int left, int right) { + vector> tmp; + for (const auto& interval : intervals_) { + if (interval.second <= left || interval.first >= right) { + tmp.emplace_back(interval); + } else { + if (interval.first < left) { + tmp.emplace_back(interval.first, left); + } + if (right < interval.second) { + tmp.emplace_back(right, interval.second); + } + } + } + swap(intervals_, tmp); + } + +private: + vector> intervals_; +}; + +/** + * Your RangeModule object will be instantiated and called as such: + * RangeModule obj = new RangeModule(); + * obj.addRange(left,right); + * bool param_2 = obj.queryRange(left,right); + * obj.removeRange(left,right); + */ diff --git a/C++/range-sum-query-2d-immutable.cpp b/C++/range-sum-query-2d-immutable.cpp new file mode 100644 index 000000000..b38183c27 --- /dev/null +++ b/C++/range-sum-query-2d-immutable.cpp @@ -0,0 +1,41 @@ +// Time: ctor: O(m * n), +// lookup: O(1) +// Space: O(m * n) + +class NumMatrix { +public: + NumMatrix(vector> &matrix) { + if (matrix.empty()) { + return; + } + + const auto m = matrix.size(), n = matrix[0].size(); + for (int i = 0; i <= m; ++i) { + sums_.emplace_back(n + 1, 0); + } + for (int i = 1; i <= m; ++i) { + for (int j = 0; j <= n; ++j) { + sums_[i][j] = sums_[i][j - 1] + matrix[i - 1][j - 1]; + } + } + for (int j = 0; j <= n; ++j) { + for (int i = 1; i <= m; ++i) { + sums_[i][j] += sums_[i - 1][j]; + } + } + } + + int sumRegion(int row1, int col1, int row2, int col2) { + return sums_[row2 + 1][col2 + 1] - sums_[row2 + 1][col1] - + sums_[row1][col2 + 1] + sums_[row1][col1]; + } + +private: + vector> sums_; +}; + + +// Your NumMatrix object will be instantiated and called as such: +// NumMatrix numMatrix(matrix); +// numMatrix.sumRegion(0, 1, 2, 3); +// numMatrix.sumRegion(1, 2, 3, 4); diff --git a/C++/range-sum-query-2d-mutable.cpp b/C++/range-sum-query-2d-mutable.cpp new file mode 100644 index 000000000..391094098 --- /dev/null +++ b/C++/range-sum-query-2d-mutable.cpp @@ -0,0 +1,199 @@ +// Time: ctor: O(m * n), +// update: O(logm + logn), +// query: O(logm + logn) +// Space: O(m * n) + +// Segment Tree solution. +class NumMatrix { +public: + NumMatrix(vector> &matrix) : matrix_(matrix) { + if (!matrix.empty() && !matrix[0].empty()) { + const int m = matrix.size(); + const int n = matrix[0].size(); + root_ = buildHelper(matrix, + make_pair(0, 0), + make_pair(m - 1, n - 1)); + } + } + + void update(int row, int col, int val) { + if (matrix_[row][col] != val) { + matrix_[row][col] = val; + updateHelper(root_, make_pair(row, col), val); + } + } + + int sumRegion(int row1, int col1, int row2, int col2) { + return sumRangeHelper(root_, make_pair(row1, col1), make_pair(row2, col2)); + } + +private: + vector>& matrix_; + + class SegmentTreeNode { + public: + pair start, end; + int sum; + vector neighbor; + SegmentTreeNode(const pair& i, const pair& j, int s) : + start(i), end(j), sum(s) { + } + }; + + SegmentTreeNode *root_; + + // Build segment tree. + SegmentTreeNode *buildHelper(const vector>& matrix, + const pair& start, + const pair& end) { + if (start.first > end.first || start.second > end.second) { + return nullptr; + } + + // The root's start and end is given by build method. + SegmentTreeNode *root = new SegmentTreeNode(start, end, 0); + + // If start equals to end, there will be no children for this node. + if (start == end) { + root->sum = matrix[start.first][start.second]; + return root; + } + + int mid_x = (start.first + end.first) / 2; + int mid_y = (start.second + end.second) / 2; + root->neighbor.emplace_back(buildHelper(matrix, start, make_pair(mid_x, mid_y))); + root->neighbor.emplace_back(buildHelper(matrix, make_pair(start.first, mid_y + 1), make_pair(mid_x, end.second))); + root->neighbor.emplace_back(buildHelper(matrix, make_pair(mid_x + 1, start.second), make_pair(end.first, mid_y))); + root->neighbor.emplace_back(buildHelper(matrix, make_pair(mid_x + 1, mid_y + 1), end)); + for (auto& node : root->neighbor) { + if (node) { + root->sum += node->sum; + } + } + return root; + } + + void updateHelper(SegmentTreeNode *root, const pair& i, int val) { + // Out of range. + if (root == nullptr || + (root->start.first > i.first || root->start.second > i.second) || + (root->end.first < i.first || root->end.second < i.second)) { + return; + } + + // Change the node's value with [i] to the new given value. + if ((root->start.first == i.first && root->start.second == i.second) && + (root->end.first == i.first && root->end.second == i.second)) { + root->sum = val; + return; + } + for (auto& node : root->neighbor) { + updateHelper(node, i, val); + } + + root->sum = 0; + for (auto& node : root->neighbor) { + if (node) { + root->sum += node->sum; + } + } + } + + int sumRangeHelper(SegmentTreeNode *root, const pair& start, const pair& end) { + // Out of range. + if (root == nullptr || + (root->start.first > end.first || root->start.second > end.second) || + (root->end.first < start.first || root->end.second < start.second)) { + return 0; + } + + // Current segment is totally within range [start, end] + if ((root->start.first >= start.first && root->start.second >= start.second) && + (root->end.first <= end.first && root->end.second <= end.second)) { + return root->sum; + } + int sum = 0; + for (auto& node : root->neighbor) { + if (node) { + sum += sumRangeHelper(node, start, end); + } + } + return sum; + } +}; + +// Time: ctor: O(m * n) +// update: O(logm * logn) +// query: O(logm * logn) +// Space: O(m * n) +// Binary Indexed Tree (BIT) solution. +class NumMatrix2 { +public: + NumMatrix(vector> &matrix) : matrix_(matrix) { + if (matrix_.empty()) { + return; + } + bit_ = vector>(matrix_.size() + 1, + vector(matrix_[0].size() + 1)); + for (int i = 1; i < bit_.size(); ++i) { + for (int j = 1; j < bit_[0].size(); ++j) { + bit_[i][j] = matrix[i - 1][j - 1] + bit_[i - 1][j] + + bit_[i][j - 1] - bit_[i - 1][j - 1]; + } + } + for (int i = bit_.size() - 1; i >= 1; --i) { + for (int j = bit_[0].size() - 1; j >= 1; --j) { + int last_i = i - lower_bit(i), last_j = j - lower_bit(j); + bit_[i][j] = bit_[i][j] - bit_[i][last_j] - + bit_[last_i][j] + bit_[last_i][last_j]; + } + } + } + + void update(int row, int col, int val) { + if (val - matrix_[row][col]) { + add(row, col, val - matrix_[row][col]); + matrix_[row][col] = val; + } + } + + int sumRegion(int row1, int col1, int row2, int col2) { + return sum(row2, col2) - sum(row2, col1 - 1) - + sum(row1 - 1, col2) + sum(row1 - 1, col1 - 1); + } + +private: + vector> &matrix_; + vector> bit_; + + int sum(int row, int col) { + ++row, ++col; + int sum = 0; + for (int i = row; i > 0; i -= lower_bit(i)) { + for (int j = col; j > 0; j -= lower_bit(j)) { + sum += bit_[i][j]; + } + } + return sum; + } + + void add(int row, int col, int val) { + ++row, ++col; + for (int i = row; i <= matrix_.size(); i += lower_bit(i)) { + for (int j = col; j <= matrix_[0].size(); j += lower_bit(j)) { + bit_[i][j] += val; + } + } + } + + inline int lower_bit(int i) { + return i & -i; + } +}; + + +// Your NumMatrix object will be instantiated and called as such: +// NumMatrix numMatrix(matrix); +// numMatrix.sumRegion(0, 1, 2, 3); +// numMatrix.update(1, 1, 10); +// numMatrix.sumRegion(1, 2, 3, 4); diff --git a/C++/range-sum-query-immutable.cpp b/C++/range-sum-query-immutable.cpp new file mode 100644 index 000000000..0a8c7e7b9 --- /dev/null +++ b/C++/range-sum-query-immutable.cpp @@ -0,0 +1,26 @@ +// Time: ctor: O(n), +// lookup: O(1) +// Space: O(n) + +class NumArray { +public: + NumArray(vector &nums) { + accu.emplace_back(0); + for (const auto& num : nums) { + accu.emplace_back(accu.back() + num); + } + } + + int sumRange(int i, int j) { + return accu[j + 1] - accu[i]; + } + +private: + vector accu; +}; + + +// Your NumArray object will be instantiated and called as such: +// NumArray numArray(nums); +// numArray.sumRange(0, 1); +// numArray.sumRange(1, 2); diff --git a/C++/range-sum-query-mutable.cpp b/C++/range-sum-query-mutable.cpp new file mode 100644 index 000000000..9119904ba --- /dev/null +++ b/C++/range-sum-query-mutable.cpp @@ -0,0 +1,161 @@ +// Time: ctor: O(n), +// update: O(logn), +// query: O(logn) +// Space: O(n) + +// Binary Indexed Tree (BIT) solution. +class NumArray { +public: + NumArray(vector &nums) : nums_(nums) { + bit_ = vector(nums_.size() + 1); + for (int i = 1; i < bit_.size(); ++i) { + bit_[i] = nums[i - 1] + bit_[i - 1]; + } + for (int i = bit_.size() - 1; i >= 1; --i) { + int last_i = i - lower_bit(i); + bit_[i] -= bit_[last_i]; + } + } + + void update(int i, int val) { + if (val - nums_[i]) { + add(i, val - nums_[i]); + nums_[i] = val; + } + } + + int sumRange(int i, int j) { + return sum(j) - sum(i - 1); + } + +private: + vector &nums_; + vector bit_; + + int sum(int i) { + ++i; + int sum = 0; + for (; i > 0; i -= lower_bit(i)) { + sum += bit_[i]; + } + return sum; + } + + void add(int i, int val) { + ++i; + for (; i <= nums_.size(); i += lower_bit(i)) { + bit_[i] += val; + } + } + + inline int lower_bit(int i) { + return i & -i; + } +}; + +// Time: ctor: O(n), +// update: O(logn), +// query: O(logn) +// Space: O(n) +// Segment Tree solution. +class NumArray2 { +public: + NumArray(vector &nums) : nums_(nums) { + root_ = buildHelper(nums, 0, nums.size() - 1); + } + + void update(int i, int val) { + if (nums_[i] != val) { + nums_[i] = val; + updateHelper(root_, i, val); + } + } + + int sumRange(int i, int j) { + return sumRangeHelper(root_, i, j); + } + +private: + vector& nums_; + + class SegmentTreeNode { + public: + int start, end; + int sum; + SegmentTreeNode *left, *right; + SegmentTreeNode(int i, int j, int s) : + start(i), end(j), sum(s), + left(nullptr), right(nullptr) { + } + }; + + SegmentTreeNode *root_; + + // Build segment tree. + SegmentTreeNode *buildHelper(const vector& nums, int start, int end) { + if (start > end) { + return nullptr; + } + + // The root's start and end is given by build method. + SegmentTreeNode *root = new SegmentTreeNode(start, end, 0); + + // If start equals to end, there will be no children for this node. + if (start == end) { + root->sum = nums[start]; + return root; + } + + // Left child: start=numsleft, end=(numsleft + numsright) / 2. + root->left = buildHelper(nums, start, (start + end) / 2); + + // Right child: start=(numsleft + numsright) / 2 + 1, end=numsright. + root->right = buildHelper(nums, (start + end) / 2 + 1, end); + + // Update sum. + root->sum = (root->left != nullptr ? root->left->sum : 0) + + (root->right != nullptr ? root->right->sum : 0); + return root; + } + + void updateHelper(SegmentTreeNode *root, int i, int val) { + // Out of range. + if (root == nullptr || root->start > i || root->end < i) { + return; + } + + // Change the node's value with [i] to the new given value. + if (root->start == i && root->end == i) { + root->sum = val; + return; + } + + updateHelper(root->left, i, val); + updateHelper(root->right, i, val); + + // Update sum. + root->sum = (root->left != nullptr ? root->left->sum : 0) + + (root->right != nullptr ? root->right->sum : 0); + } + + int sumRangeHelper(SegmentTreeNode *root, int start, int end) { + // Out of range. + if (root == nullptr || root->start > end || root->end < start) { + return 0; + } + + // Current segment is totally within range [start, end] + if (root->start >= start && root->end <= end) { + return root->sum; + } + + return sumRangeHelper(root->left, start, end) + + sumRangeHelper(root->right, start, end); + } +}; + +// Your NumArray object will be instantiated and called as such: +// NumArray numArray(nums); +// numArray.sumRange(0, 1); +// numArray.update(1, 10); +// numArray.sumRange(1, 2); diff --git a/C++/ransom-note.cpp b/C++/ransom-note.cpp new file mode 100644 index 000000000..550b4a3ae --- /dev/null +++ b/C++/ransom-note.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool canConstruct(string ransomNote, string magazine) { + vector counts(26); + int letters = 0; + for (const auto& c : ransomNote) { + if (counts[c - 'a']++ == 0) { + ++letters; + } + } + for (const auto& c : magazine) { + if (--counts[c - 'a'] == 0 && --letters == 0) { + // Break as soon as possible if letters have been enough. + break; + } + } + return letters == 0; + } +}; diff --git a/C++/read-n-characters-given-read4-ii-call-multiple-times.cpp b/C++/read-n-characters-given-read4-ii-call-multiple-times.cpp new file mode 100644 index 000000000..fb53207c8 --- /dev/null +++ b/C++/read-n-characters-given-read4-ii-call-multiple-times.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(1) + +// Forward declaration of the read4 API. +int read4(char *buf); + +class Solution { +public: + /** + * @param buf Destination buffer + * @param n Maximum number of characters to read + * @return The number of characters read + */ + int read(char *buf, int n) { + int i = 0; + while (i < n) { + if (i4_ < n4_) { // Any characters in buf4. + buf[i++] = buf4_[i4_++]; + } else if (n4_ = read4(buf4_)) { // Read more characters. + i4_ = 0; + } else { // Buffer has been empty. + break; + } + } + return i; + } + +private: + char buf4_[4]; + int i4_ = 0, n4_ = 0; +}; diff --git a/C++/read-n-characters-given-read4.cpp b/C++/read-n-characters-given-read4.cpp new file mode 100644 index 000000000..7128ab1fa --- /dev/null +++ b/C++/read-n-characters-given-read4.cpp @@ -0,0 +1,24 @@ +// Time: O(n) +// Space: O(1) + +int read4(char *buf); + +class Solution { +public: + /** + * @param buf Destination buffer + * @param n Maximum number of characters to read + * @return The number of characters read + */ + int read(char *buf, int n) { + int read_bytes = 0; + for (int i = 0; i <= n / 4; ++i) { + if (int size = read4(buf + read_bytes)) { + read_bytes += size; + } else { + break; + } + } + return min(read_bytes, n); + } +}; diff --git a/C++/rearrange-string-k-distance-apart.cpp b/C++/rearrange-string-k-distance-apart.cpp new file mode 100644 index 000000000..c19221a65 --- /dev/null +++ b/C++/rearrange-string-k-distance-apart.cpp @@ -0,0 +1,81 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string rearrangeString(string str, int k) { + int cnts [26] = {0}; + for (int i = 0; i < str.length(); ++i) { + ++cnts[str[i] - 'a']; + } + + vector> sorted_cnts; + for (int i = 0; i < 26; ++i) { + sorted_cnts.emplace_back(cnts[i], i + 'a'); + } + sort(sorted_cnts.begin(), sorted_cnts.end(), greater>()); + + const auto max_cnt = sorted_cnts[0].first; + string blocks[max_cnt]; + int i = 0; + for (const auto& cnt : sorted_cnts) { + for (int j = 0; j < cnt.first; ++j) { + blocks[i].push_back(cnt.second); + i = (i + 1) % max(cnt.first, max_cnt - 1); + } + } + + string result; + for (int i = 0; i < max_cnt - 1; ++i) { + if (blocks[i].length() < k) { + return ""; + } else { + result += blocks[i]; + } + } + result += blocks[max_cnt - 1]; + return result; + } +}; + +// Time: O(nlogc), c is the count of unique characters. +// Space: O(c) +class Solution2 { +public: + string rearrangeString(string str, int k) { + if (k == 0) { + return str; + } + + unordered_map cnts; + for (const auto& c : str) { + ++cnts[c]; + } + + priority_queue> heap; + for (const auto& kvp : cnts) { + heap.emplace(kvp.second, kvp.first); + } + + string result; + while (!heap.empty()) { + vector> used_cnt_chars; + int cnt = min(k, static_cast(str.length() - result.length())); + for (int i = 0; i < cnt; ++i) { + if (heap.empty()) { + return ""; + } + auto cnt_char = heap.top(); + heap.pop(); + result.push_back(cnt_char.second); + if (--cnt_char.first > 0) { + used_cnt_chars.emplace_back(move(cnt_char)); + } + } + for (auto& cnt_char: used_cnt_chars) { + heap.emplace(move(cnt_char)); + } + } + return result; + } +}; diff --git a/C++/reconstruct-itinerary.cpp b/C++/reconstruct-itinerary.cpp new file mode 100644 index 000000000..d53398a59 --- /dev/null +++ b/C++/reconstruct-itinerary.cpp @@ -0,0 +1,40 @@ +// Time: O(t! / (n1! * n2! * ... nk!)), t is the total number of tickets, +// ni is the number of the ticket which from is city i, +// k is the total number of cities. +// Space: O(t) + +class Solution { +public: + vector findItinerary(vector> tickets) { + unordered_map> graph; + for (const auto& ticket : tickets) { + ++graph[ticket.first][ticket.second]; + } + const string from{"JFK"}; + vector ans{from}; + routeHelper(from, tickets.size(), &graph, &ans); + return ans; + } + +private: + bool routeHelper(const string& from, const int ticket_cnt, + unordered_map> *graph, vector *ans) { + + if (ticket_cnt == 0) { + return true; + } + + for (auto& to : (*graph)[from]) { + if (to.second) { + --to.second; + ans->emplace_back(to.first); + if (routeHelper(to.first, ticket_cnt - 1, graph, ans)) { + return true; + } + ans->pop_back(); + ++to.second; + } + } + return false; + } +}; diff --git a/C++/reconstruct-original-digits-from-english.cpp b/C++/reconstruct-original-digits-from-english.cpp new file mode 100644 index 000000000..3b8f64548 --- /dev/null +++ b/C++/reconstruct-original-digits-from-english.cpp @@ -0,0 +1,39 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string originalDigits(string s) { + const vector numbers{"zero", "one", "two", "three", + "four", "five", "six", "seven", + "eight", "nine"}; + vector> cnts(numbers.size(), vector(26)); + for (int i = 0; i < numbers.size(); ++i) { + for (const auto& c : numbers[i]) { + ++cnts[i][c - 'a']; + } + } + + // The order for greedy method. + vector order{0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; + + // The unique char in the order. + vector unique_chars{'z', 'o', 'w', 't', 'u', 'f', 'x', 's', 'g', 'n'}; + vector cnt(26); + for (const auto& c : s) { + ++cnt[c - 'a']; + } + + string result; + for (const auto& i : order) { + while (cnt[unique_chars[i] - 'a'] > 0) { + for (int j = 0; j < cnt.size(); ++j) { + cnt[j] -= cnts[i][j]; + } + result.push_back(i + '0'); + } + } + sort(result.begin(), result.end()); + return result; + } +}; diff --git a/C++/recover-binary-search-tree.cpp b/C++/recover-binary-search-tree.cpp new file mode 100644 index 000000000..b0b9105f4 --- /dev/null +++ b/C++/recover-binary-search-tree.cpp @@ -0,0 +1,59 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for binary tree + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode *root) { + MorrisTraversal(root); + } + +private: + void MorrisTraversal(TreeNode *root) { + if (!root) { + return; + } + pair broken; + TreeNode *prev = nullptr; + TreeNode *cur = root; + while (cur) { + if (!cur->left) { + detect(prev, cur, &broken); + prev = cur; + cur = cur->right; + } else { + TreeNode *node = cur->left; + while (node->right && node->right != cur) { + node = node->right; + } + if (!node->right) { + node->right = cur; + cur = cur->left; + } else { + detect(prev, cur, &broken); + prev = cur; + node->right = nullptr; + cur = cur->right; + } + } + } + swap(broken.first->val, broken.second->val); + } + + void detect(TreeNode *prev, TreeNode *cur, pair *broken) { + if (prev && prev->val > cur->val) { + if (!broken->first) { // Find the first broken node. + broken->first = prev; + } + broken->second = cur; // Find the last broken node. + } + } +}; diff --git a/C++/recoverTree.cpp b/C++/recoverTree.cpp deleted file mode 100644 index a260f5329..000000000 --- a/C++/recoverTree.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { - public: - void recoverTree(TreeNode *root) { - MorrisTraversal(root); - } - - private: - /* Function to traverse binary tree without recursion and - without stack */ - void MorrisTraversal(TreeNode *root) - { - if(root == NULL) - return; - - pair broken; - TreeNode *cur = root; - TreeNode *pre = NULL; - - while(cur != NULL) - { - if(cur->left == NULL) - { - detect(broken, pre, cur); - pre = cur; - cur = cur->right; - } - else - { - /* Find the inorder predecessor of current */ - auto node = cur->left; - while(node->right != NULL && node->right != cur) - node = node->right; - - /* Make current as right child of its inorder predecessor */ - if(node->right == NULL) - { - node->right = cur; - cur = cur->left; - } - - /* Revert the changes made in if part to restore the original - tree i.e., fix the right child of predecssor */ - else - { - detect(broken, pre, cur); - node->right = NULL; - pre = cur; - cur = cur->right; - } - } - } - - swap(broken.first->val, broken.second->val); // swap the fist and the last broken node - } - - void detect(pair &broken, TreeNode *pre, TreeNode *cur) { - if(pre && pre->val > cur->val) { - if(!broken.first) { // find the first broken node - broken.first = pre; - } - broken.second = cur; // find the last broken node - } - } -}; diff --git a/C++/rectangle-area.cpp b/C++/rectangle-area.cpp new file mode 100644 index 000000000..5f30c95ea --- /dev/null +++ b/C++/rectangle-area.cpp @@ -0,0 +1,12 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) { + return (D - B) * (C - A) + + (G - E) * (H - F) - + max(0, (min(C, G) - max(A, E))) * + max(0, (min(D, H) - max(B, F))); + } +}; diff --git a/C++/redundant-connection-ii.cpp b/C++/redundant-connection-ii.cpp new file mode 100644 index 000000000..ef039fcaa --- /dev/null +++ b/C++/redundant-connection-ii.cpp @@ -0,0 +1,48 @@ +// Time: O(nlog*n) ~= O(n), n is the length of the positions +// Space: O(n) + +class Solution { +public: + vector findRedundantDirectedConnection(vector>& edges) { + UnionFind union_find(edges.size() + 1); + for (const auto& edge : edges) { + if (!union_find.union_set(edge[0], edge[1])) { + return edge; + } + } + return {}; + } + +private: + class UnionFind { + public: + UnionFind(const int n) : set_(n), count_(n) { + iota(set_.begin(), set_.end(), 0); + } + + int find_set(const int x) { + if (set_[x] != x) { + set_[x] = find_set(set_[x]); // Path compression. + } + return set_[x]; + } + + bool union_set(const int x, const int y) { + int x_root = find_set(x), y_root = find_set(y); + if (x_root == y_root || y != y_root) { + return false; + } + set_[y_root] = x_root; + --count_; + return true; + } + + int length() const { + return count_; + } + + private: + vector set_; + int count_; + }; +}; diff --git a/C++/redundant-connection.cpp b/C++/redundant-connection.cpp new file mode 100644 index 000000000..76f921a91 --- /dev/null +++ b/C++/redundant-connection.cpp @@ -0,0 +1,48 @@ +// Time: O(nlog*n) ~= O(n), n is the length of the positions +// Space: O(n) + +class Solution { +public: + vector findRedundantConnection(vector>& edges) { + UnionFind union_find(edges.size() + 1); + for (const auto& edge : edges) { + if (!union_find.union_set(edge[0], edge[1])) { + return edge; + } + } + return {}; + } + +private: + class UnionFind { + public: + UnionFind(const int n) : set_(n), count_(n) { + iota(set_.begin(), set_.end(), 0); + } + + int find_set(const int x) { + if (set_[x] != x) { + set_[x] = find_set(set_[x]); // Path compression. + } + return set_[x]; + } + + bool union_set(const int x, const int y) { + int x_root = find_set(x), y_root = find_set(y); + if (x_root == y_root) { + return false; + } + set_[min(x_root, y_root)] = max(x_root, y_root); + --count_; + return true; + } + + int length() const { + return count_; + } + + private: + vector set_; + int count_; + }; +}; diff --git a/C++/relative-ranks.cpp b/C++/relative-ranks.cpp new file mode 100644 index 000000000..835aaf44b --- /dev/null +++ b/C++/relative-ranks.cpp @@ -0,0 +1,21 @@ +// Time: O(nlogn) +// Space: O(n) + +class Solution { +public: + vector findRelativeRanks(vector& nums) { + vector indices(nums.size()); + iota(indices.begin(), indices.end(), 0); + sort(indices.begin(), indices.end(), + [&nums](int a, int b) { + return nums[a] > nums[b]; + }); + + const vector ranks = {"Gold Medal", "Silver Medal", "Bronze Medal"}; + vector result(nums.size()); + for (int i = 0; i < nums.size(); ++i) { + result[indices[i]] = i > 2 ? to_string(i + 1) : ranks[i]; + } + return result; + } +}; diff --git a/C++/remove-9.cpp b/C++/remove-9.cpp new file mode 100644 index 000000000..48b926441 --- /dev/null +++ b/C++/remove-9.cpp @@ -0,0 +1,15 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int newInteger(int n) { + int result = 0, base = 1; + while (n > 0) { + result += (n % 9) * base; + n /= 9; + base *= 10; + } + return result; + } +}; diff --git a/C++/remove-boxes.cpp b/C++/remove-boxes.cpp new file mode 100644 index 000000000..b23789130 --- /dev/null +++ b/C++/remove-boxes.cpp @@ -0,0 +1,34 @@ +// Time: O(n^3) ~ O(n^4) +// Space: O(n^3) + +class Solution { +public: + int removeBoxes(vector& boxes) { + int lookup[100][100][100] = {0}; + return removeBoxesHelper(boxes, 0, boxes.size() - 1, 0, lookup); + } + +private: + int removeBoxesHelper(const vector& boxes, int l, int r, int k, int lookup[100][100][100]) { + if (l > r) { + return 0; + } + if (lookup[l][r][k]) { + return lookup[l][r][k]; + } + + auto& result = lookup[l][r][k]; + while (l < r && boxes[l + 1] == boxes[l]) { + ++l, ++k; + } + result = removeBoxesHelper(boxes, l + 1, r, 0, lookup) + (k + 1) * (k + 1); + for (int i = l + 1; i <= r; ++i) { + if (boxes[i] == boxes[l]) { + result = max(result, + removeBoxesHelper(boxes, l + 1, i - 1, 0, lookup) + + removeBoxesHelper(boxes, i, r, k + 1, lookup)); + } + } + return result; + } +}; diff --git a/C++/remove-comments.cpp b/C++/remove-comments.cpp new file mode 100644 index 000000000..ab781fa0e --- /dev/null +++ b/C++/remove-comments.cpp @@ -0,0 +1,30 @@ +// Time: O(n), n is the length of the source +// Space: O(k), k is the max length of a line + +class Solution { +public: + vector removeComments(vector& source) { + bool in_block = false; + vector result; + string newline; + for (const auto& line : source) { + for (int i = 0; i < line.length(); ++i) { + if (!in_block && i + 1 < line.length() && line.substr(i, 2) == "/*") { + in_block = true; + ++i; + } else if (in_block && i + 1 < line.length() && line.substr(i, 2) == "*/") { + in_block = false; + ++i; + } else if (!in_block && i + 1 < line.length() && line.substr(i, 2) == "//") { + break; + } else if (!in_block) { + newline.push_back(line[i]); + } + } + if (!in_block && !newline.empty()) { + result.emplace_back(move(newline)); + } + } + return result; + } +}; diff --git a/C++/remove-duplicate-letters.cpp b/C++/remove-duplicate-letters.cpp new file mode 100644 index 000000000..9034bf7f7 --- /dev/null +++ b/C++/remove-duplicate-letters.cpp @@ -0,0 +1,57 @@ +// Time: O(n) +// Space: O(k), k is size of the alphabet + +// vector solution, need to know size of the alphabet in advance (4ms) +class Solution { +public: + string removeDuplicateLetters(string s) { + const int k = 26; + vector remaining(k); + for (const auto& c : s) { + ++remaining[c - 'a']; + } + + vector in_stack(k); + string stk; + for (const auto& c : s) { + if (!in_stack[c - 'a']) { + while (!stk.empty() && stk.back() > c && remaining[stk.back() - 'a']) { + in_stack[stk.back() - 'a'] = false; + stk.pop_back(); + } + stk.push_back(c); + in_stack[c - 'a'] = true; + } + --remaining[c - 'a']; + } + return stk; + } +}; + +// Time: O(n) +// Space: O(k), k is size of the alphabet +// hash solution, no need to know size of the alphabet in advance (16ms) +class Solution2 { +public: + string removeDuplicateLetters(string s) { + unordered_map remaining; + for (const auto& c : s) { + ++remaining[c]; + } + + unordered_set in_stack; + string stk; + for (const auto& c : s) { + if (!in_stack.count(c)) { + while (!stk.empty() && stk.back() > c && remaining[stk.back()]) { + in_stack.erase(stk.back()); + stk.pop_back(); + } + stk.push_back(c); + in_stack.emplace(c); + } + --remaining[c]; + } + return stk; + } +}; diff --git a/C++/remove-duplicates-from-sorted-array-ii.cpp b/C++/remove-duplicates-from-sorted-array-ii.cpp new file mode 100644 index 000000000..764fdfa74 --- /dev/null +++ b/C++/remove-duplicates-from-sorted-array-ii.cpp @@ -0,0 +1,27 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int removeDuplicates(vector& nums) { + if (nums.empty()) { + return 0; + } + + const int k = 2; // At most k duplicated. + + int left = 0; + int right = 1; + + while (right < nums.size()) { + if (nums[left] != nums[right] || + (left - k + 1 < 0 || nums[left] != nums[left - k + 1])) { + ++left; + nums[left] = nums[right]; + } + ++right; + } + + return left + 1; + } +}; diff --git a/C++/remove-duplicates-from-sorted-array.cpp b/C++/remove-duplicates-from-sorted-array.cpp new file mode 100644 index 000000000..0d8a71832 --- /dev/null +++ b/C++/remove-duplicates-from-sorted-array.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int removeDuplicates(vector& nums) { + int last = -1; + for (const auto& num : nums) { + if (last == -1 || nums[last] != num) { + nums[++last] = num; + } + } + return last + 1; + } +}; diff --git a/C++/remove-duplicates-from-sorted-list-ii.cpp b/C++/remove-duplicates-from-sorted-list-ii.cpp new file mode 100644 index 000000000..5136aa0a4 --- /dev/null +++ b/C++/remove-duplicates-from-sorted-list-ii.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* deleteDuplicates(ListNode* head) { + ListNode dummy{0}; + auto prev = &dummy; + while (head) { + if (head->next && head->next->val == head->val) { + auto val = head->val; + while (head && head->val == val) { + head = head->next; + } + prev->next = head; + } else { + prev->next = head; + prev = head; + head = head->next; + } + } + return dummy.next; + } +}; diff --git a/C++/remove-duplicates-from-sorted-list.cpp b/C++/remove-duplicates-from-sorted-list.cpp new file mode 100644 index 000000000..0a0795c91 --- /dev/null +++ b/C++/remove-duplicates-from-sorted-list.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* deleteDuplicates(ListNode* head) { + auto iter = head; + while (iter) { + auto runner = iter->next; + while (runner && runner->val == iter->val) { + runner = runner->next; + } + iter->next = runner; + iter = runner; + } + return head; + } +}; diff --git a/C++/remove-element.cpp b/C++/remove-element.cpp new file mode 100644 index 000000000..522d6af4b --- /dev/null +++ b/C++/remove-element.cpp @@ -0,0 +1,17 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int removeElement(vector& nums, int val) { + int left = 0, right = nums.size(); + while (left < right) { + if (nums[left] != val) { + ++left; + } else { + swap(nums[left], nums[--right]); + } + } + return right; + } +}; diff --git a/C++/remove-invalid-parentheses.cpp b/C++/remove-invalid-parentheses.cpp new file mode 100644 index 000000000..31242b26c --- /dev/null +++ b/C++/remove-invalid-parentheses.cpp @@ -0,0 +1,248 @@ +// Time: O(C(n, c)), try out all possible substrings with the minimum c deletion. +// Space: O(c), the depth is at most c, and it costs n at each depth + +// DFS solution with removed array. (4ms) +class Solution { +public: + vector removeInvalidParentheses(string s) { + int left_removed = 0, right_removed = 0; + findMinRemove(s, &left_removed, &right_removed); + + vector res; + vector removed; + removeInvalidParenthesesHelper(s, 0, left_removed, right_removed, &removed, &res); + return res; + } + +private: + void findMinRemove(const string& s, int *left_removed, int *right_removed) { + // Calculate the minimum left and right parantheses to remove. + for (const auto& c : s) { + if (c == '(') { + ++(*left_removed); + } else if (c == ')') { + if (!(*left_removed)) { + ++(*right_removed); + } else { + --(*left_removed); + } + } + } + } + + void removeInvalidParenthesesHelper(const string& s, int start, + int left_removed, int right_removed, + vector *removed, vector *res) { + + if (left_removed == 0 && right_removed == 0) { + string tmp; + for (int i = 0, j = 0; i < s.length(); ++i) { + if (j < removed->size() && i == (*removed)[j]) { + ++j; + } else { + tmp.push_back(s[i]); + } + } + if (isValid(tmp)) { + res->emplace_back(tmp); + } + return; + } + + for (int i = start; i < s.length(); ++i) { + if (right_removed == 0 && left_removed > 0 && s[i] == '(') { + if (i == start || s[i] != s[i - 1]) { // Skip duplicated. + removed->emplace_back(i); + removeInvalidParenthesesHelper(s, i + 1, left_removed - 1, right_removed, + removed, res); + removed->pop_back(); + } + } else if (right_removed > 0 && s[i] == ')') { + if (i == start || s[i] != s[i - 1]) { // Skip duplicated. + removed->emplace_back(i); + removeInvalidParenthesesHelper(s, i + 1, left_removed, right_removed - 1, + removed, res); + removed->pop_back(); + } + } + + } + } + + // Check whether s is valid or not. + bool isValid(string s) { + int sum = 0; + for (const auto &c : s) { + if (c == '(') { + ++sum; + } else if (c == ')') { + --sum; + } + if (sum < 0) { + return false; + } + } + return sum == 0; + } +}; + +// Time: O(C(n, c)), try out all possible substrings with the minimum c deletion. +// Space: O(c), the depth is at most c, and it costs n at each depth +// DFS solution with removed hash. (8ms) +class Solution2 { +public: + vector removeInvalidParentheses(string s) { + int left_removed = 0, right_removed = 0; + findMinRemove(s, &left_removed, &right_removed); + + vector res; + unordered_set removed; + removeInvalidParenthesesHelper(s, 0, left_removed, right_removed, &removed, &res); + return res; + } + +private: + void findMinRemove(const string& s, int *left_removed, int *right_removed) { + // Calculate the minimum left and right parantheses to remove. + for (const auto& c : s) { + if (c == '(') { + ++(*left_removed); + } else if (c == ')') { + if (!(*left_removed)) { + ++(*right_removed); + } else { + --(*left_removed); + } + } + } + } + + void removeInvalidParenthesesHelper(const string& s, int start, + int left_removed, int right_removed, + unordered_set *removed, vector *res) { + + if (left_removed == 0 && right_removed == 0) { + string tmp; + for (int i = 0; i < s.length(); ++i) { + if (!removed->count(i)) { + tmp.push_back(s[i]); + } + } + if (isValid(tmp)) { + res->emplace_back(tmp); + } + return; + } + + for (int i = start; i < s.length(); ++i) { + if (right_removed == 0 && left_removed > 0 && s[i] == '(') { + if (i == start || s[i] != s[i - 1]) { // Skip duplicated. + removed->emplace(i); + removeInvalidParenthesesHelper(s, i + 1, left_removed - 1, right_removed, + removed, res); + removed->erase(i); + } + } else if (right_removed > 0 && s[i] == ')') { + if (i == start || s[i] != s[i - 1]) { // Skip duplicated. + removed->emplace(i); + removeInvalidParenthesesHelper(s, i + 1, left_removed, right_removed - 1, + removed, res); + removed->erase(i); + } + } + + } + } + + // Check whether s is valid or not. + bool isValid(string s) { + int sum = 0; + for (const auto &c : s) { + if (c == '(') { + ++sum; + } else if (c == ')') { + --sum; + } + if (sum < 0) { + return false; + } + } + return sum == 0; + } +}; + + +// Time: O(n * C(n, c)), try out all possible substrings with the minimum c deletion. +// Space: O(n * c), the depth is at most c, and it costs n at each depth +// DFS solution. (4ms) +class Solution3 { +public: + vector removeInvalidParentheses(string s) { + int left_removed = 0, right_removed = 0; + findMinRemove(s, &left_removed, &right_removed); + + vector res; + removeInvalidParenthesesHelper(s, 0, left_removed, right_removed, &res); + return res; + } + + void findMinRemove(const string& s, int *left_removed, int *right_removed) { + // Calculate the minimum left and right parantheses to remove. + for (const auto& c : s) { + if (c == '(') { + ++(*left_removed); + } else if (c == ')') { + if (!(*left_removed)) { + ++(*right_removed); + } else { + --(*left_removed); + } + } + } + } + +private: + void removeInvalidParenthesesHelper(const string& s, int start, + int left_removed, int right_removed, vector *res) { + + if (left_removed == 0 && right_removed == 0) { + if (isValid(s)) { + res->emplace_back(s); + } + return; + } + + for (int i = start; i < s.length(); ++i) { + if (right_removed == 0 && left_removed > 0 && s[i] == '(') { + if (i == start || s[i] != s[i - 1]) { // Skip duplicated. + string tmp = s; + tmp.erase(i, 1); + removeInvalidParenthesesHelper(tmp, i, left_removed - 1, right_removed, res); + } + } else if (right_removed > 0 && s[i] == ')') { + if (i == start || s[i] != s[i - 1]) { // Skip duplicated. + string tmp = s; + tmp.erase(i, 1); + removeInvalidParenthesesHelper(tmp, i, left_removed, right_removed - 1, res); + } + } + + } + } + + // Check whether s is valid or not. + bool isValid(string s) { + int sum = 0; + for (const auto &c : s) { + if (c == '(') { + ++sum; + } else if (c == ')') { + --sum; + } + if (sum < 0) { + return false; + } + } + return sum == 0; + } +}; diff --git a/C++/remove-k-digits.cpp b/C++/remove-k-digits.cpp new file mode 100644 index 000000000..bc25f33c2 --- /dev/null +++ b/C++/remove-k-digits.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string removeKdigits(string num, int k) { + // If a digit is greater than next one, delete it. + string s; + for (const auto c : num) { + while (k > 0 && !s.empty() && s.back() > c) { + s.pop_back(); + --k; + } + s.push_back(c); + } + + // If all digits are increasingly sorted, delete last. + s.resize(s.length() - k); + + // Strip all leading '0' + return s.empty() || s == "0" ? "0" : s.substr(s.find_first_not_of('0')); + } +}; diff --git a/C++/remove-linked-list-elements.cpp b/C++/remove-linked-list-elements.cpp new file mode 100644 index 000000000..925e964eb --- /dev/null +++ b/C++/remove-linked-list-elements.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* removeElements(ListNode* head, int val) { + ListNode dummy{0}; + dummy.next = head; + auto *prev = &dummy, *cur = dummy.next; + + while (cur) { + if (cur->val == val) { + prev->next = cur->next; + delete cur; + } else { + prev = cur; + } + cur = cur->next; + } + return dummy.next; + } +}; diff --git a/C++/remove-nth-node-from-end-of-list.cpp b/C++/remove-nth-node-from-end-of-list.cpp new file mode 100644 index 000000000..81568c340 --- /dev/null +++ b/C++/remove-nth-node-from-end-of-list.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *removeNthFromEnd(ListNode *head, int n) { + ListNode dummy{0}; + dummy.next = head; + auto slow = &dummy; + auto fast = &dummy; + + // fast is n-step ahead. + while (n > 0) { + fast = fast->next; + --n; + } + + // When fast reaches the end, slow must be nth to last node. + while (fast->next != nullptr) { + slow = slow->next; + fast = fast->next; + } + + auto node_to_delete = slow->next; + slow->next = slow->next->next; + delete node_to_delete; + + return dummy.next; + } +}; diff --git a/C++/removeDuplicates.cpp b/C++/removeDuplicates.cpp deleted file mode 100644 index f059dfe4c..000000000 --- a/C++/removeDuplicates.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int removeDuplicates(int A[], int n) { - const int occur = 2; - if(n <= occur) return n; - - int cnt = occur; - - for(int i = occur; i < n; ++i) { - if(A[i] != A[cnt - occur]) - A[cnt++] = A[i]; - } - - return cnt; - } -}; diff --git a/C++/removeNthFromEnd.cpp b/C++/removeNthFromEnd.cpp deleted file mode 100644 index f2f71848d..000000000 --- a/C++/removeNthFromEnd.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *removeNthFromEnd(ListNode *head, int n) { - ListNode *slow = head, *fast = head, *pre = NULL; - - while(n > 0) { - fast = fast->next; - --n; - } - - while(fast) { - pre = slow; - slow = slow->next; - fast = fast->next; - } - - if(!pre && !slow->next) - return NULL; - - if(!pre && slow->next) - return slow->next; - - pre->next = slow->next; - delete slow; - - return head; - } -}; diff --git a/C++/reorder-list.cpp b/C++/reorder-list.cpp new file mode 100644 index 000000000..8dc4f303f --- /dev/null +++ b/C++/reorder-list.cpp @@ -0,0 +1,70 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { + public: + void reorderList(ListNode *head) { + if (!head) { + return; + } + + auto slow = head, fast = head; + + while (fast->next && fast->next->next) { + slow = slow->next; + fast = fast->next->next; + } + + // Split into two lists. + auto tmp = slow->next; + slow->next = nullptr; + slow = tmp; + + merge(head, reverse(slow)); + } + +private: + ListNode *reverse(ListNode *head) { + ListNode dummy{0}; + + while (head) { + auto tmp = head->next; + head->next = dummy.next; + dummy.next = head; + head = tmp; + } + + return dummy.next; + } + + ListNode *merge(ListNode *list1, ListNode *list2) { + ListNode dummy{0}; + auto ptr = &dummy; + + while (list1 && list2) { + auto tmp = list1->next; + + ptr->next = list1; + ptr = ptr->next; + ptr->next = list2; + ptr = ptr->next; + + list1 = tmp; + list2 = list2->next; + } + + if (list1) { + ptr->next = list1; + } + + return dummy.next; + } +}; diff --git a/C++/reorderList.cpp b/C++/reorderList.cpp deleted file mode 100644 index 7feadc471..000000000 --- a/C++/reorderList.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - void reorderList(ListNode *head) { - if(!head) return; - - ListNode *slow = head; - ListNode *fast = head; - - while(fast->next && fast->next->next) { - slow = slow->next; - fast = fast->next->next; - } - - // split into two lists - ListNode *tmp = slow->next; - slow->next = nullptr; - slow = tmp; - - merge(head, reverse(slow)); - } - - private: - ListNode *reverse(ListNode *head) { - ListNode dummy(INT_MIN); - - while(head) { - ListNode *tmp = head->next; - - head->next = dummy.next; - dummy.next = head; - - head = tmp; - } - - return dummy.next; - } - - ListNode *merge(ListNode *list1, ListNode *list2) { - ListNode dummy(INT_MIN); - ListNode *ptr = &dummy; - - while(list1 && list2) { - ListNode *tmp = list1->next; // backup list1 next - - ptr->next = list1; - ptr = ptr->next; - ptr->next = list2; // list1 next is overwritten - ptr = ptr->next; - - list1 = tmp; - list2 = list2->next; - } - - if(list1) ptr->next = list1; // append remaining list1 - - return dummy.next; - } -}; diff --git a/C++/repeated-string-match.cpp b/C++/repeated-string-match.cpp new file mode 100644 index 000000000..3f4b8ef73 --- /dev/null +++ b/C++/repeated-string-match.cpp @@ -0,0 +1,66 @@ +// Time: O(n + m) +// Space: O(1) + +// Rabin-Karp Algorithm (rolling hash) +class Solution { +public: + int repeatedStringMatch(string A, string B) { + static const uint64_t M = 1000000007; + static const uint64_t p = 113; + static const uint64_t p_inv = pow(p, M - 2, M); + + const auto q = (B.length() + A.length() - 1) / A.length(); + + uint64_t b_hash = 0, power = 1; + for (int i = 0; i < B.length(); ++i) { + b_hash += power * B[i]; + b_hash %= M; + power = (power * p) % M; + } + + uint64_t a_hash = 0; power = 1; + for (int i = 0; i < B.length(); ++i) { + a_hash += power * A[i % A.length()]; + a_hash %= M; + power = (power * p) % M; + } + if (a_hash == b_hash && check(0, A, B)) { + return q; + } + + power = (power * p_inv) % M; + for (int i = B.length(); i < (q + 1) * A.length(); ++i) { + a_hash -= A[(i - B.length()) % A.length()]; + a_hash *= p_inv; + a_hash += power * A[i % A.length()]; + a_hash %= M; + if (a_hash == b_hash && check(i - B.length() + 1, A, B)) { + return i < q * A.length() ? q : q + 1; + } + } + return -1; + } + +private: + bool check(int index, const string& A, const string& B) { + for (int i = 0; i < B.length(); ++i) { + if (A[(i + index) % A.length()] != B[i]) { + return false; + } + } + return true; + } + + uint64_t pow(uint64_t a,uint64_t b, uint64_t m) { + a %= m; + uint64_t result = 1; + while (b) { + if (b & 1) { + result = (result * a) % m; + } + a = (a * a) % m; + b >>= 1; + } + return result; + } +}; diff --git a/C++/repeated-substring-pattern.cpp b/C++/repeated-substring-pattern.cpp new file mode 100644 index 000000000..afd5e990e --- /dev/null +++ b/C++/repeated-substring-pattern.cpp @@ -0,0 +1,28 @@ +// Time: O(n) +// Space: O(n) + +// KMP solution. +class Solution { +public: + bool repeatedSubstringPattern(string str) { + vector prefix = getPrefix(str); + return prefix.back() != -1 && + (prefix.back() + 1) % (str.length() - prefix.back() - 1) == 0; + } + +private: + vector getPrefix(const string& pattern) { + vector prefix(pattern.length(), -1); + int j = -1; + for (int i = 1; i < pattern.length(); ++i) { + while (j > -1 && pattern[j + 1] != pattern[i]) { + j = prefix[j]; + } + if (pattern[j + 1] == pattern[i]) { + ++j; + } + prefix[i] = j; + } + return prefix; + } +}; diff --git a/C++/replace-words.cpp b/C++/replace-words.cpp new file mode 100644 index 000000000..33633eae6 --- /dev/null +++ b/C++/replace-words.cpp @@ -0,0 +1,50 @@ +// Time: O(n) +// Space: O(t), t is the number of nodes in trie + +class Solution { +public: + string replaceWords(vector& dict, string sentence) { + TrieNode trie; + string result; + for (const auto& s : dict) { + trie.Insert(s); + } + auto curr = ≜ + for (const auto& c : sentence) { + if (c == ' ' || !curr || !curr->isString) { + result += c; + } + if (c == ' ') { + curr = ≜ + } else if (curr && !curr->isString) { + curr = curr->leaves[c]; + } + } + return result; + } + +private: + struct TrieNode { + bool isString = false; + unordered_map leaves; + + void Insert(const string& s) { + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + p->leaves[c] = new TrieNode; + } + p = p->leaves[c]; + } + p->isString = true; + } + + ~TrieNode() { + for (auto& kv : leaves) { + if (kv.second) { + delete kv.second; + } + } + } + }; +}; diff --git a/C++/reshape-the-matrix.cpp b/C++/reshape-the-matrix.cpp new file mode 100644 index 000000000..11ac63605 --- /dev/null +++ b/C++/reshape-the-matrix.cpp @@ -0,0 +1,22 @@ +// Time: O(m * n) +// Space: O(m * n) + +class Solution { +public: + vector> matrixReshape(vector>& nums, int r, int c) { + if (nums.empty() || + r * c != nums.size() * nums[0].size()) { + return nums; + } + + vector> result(r, vector(c)); + int count = 0; + for (int i = 0; i < nums.size(); ++i) { + for (int j = 0; j < nums[0].size(); ++j) { + result[count / c][count % c] = nums[i][j]; + ++count; + } + } + return result; + } +}; diff --git a/C++/reverse-bits.cpp b/C++/reverse-bits.cpp new file mode 100644 index 000000000..6bedc3410 --- /dev/null +++ b/C++/reverse-bits.cpp @@ -0,0 +1,16 @@ +// Time: O(logn) = O(32) +// Space: O(1) + +class Solution { +public: + uint32_t reverseBits(uint32_t n) { + uint32_t result = 0; + int count = 32; + while (count--) { + result <<= 1; + result |= n & 1; + n >>= 1; + } + return result; + } +}; diff --git a/C++/reverse-integer.cpp b/C++/reverse-integer.cpp new file mode 100644 index 000000000..5e00c210e --- /dev/null +++ b/C++/reverse-integer.cpp @@ -0,0 +1,20 @@ +// Time: O(logn) = O(1) +// Space: O(1) + +class Solution { +public: + int reverse(int x) { + int result = 0; + while (x) { + auto prev = result; + result *= 10; + result += x % 10; + if (result / 10 != prev) { + result = 0; + break; + } + x /= 10; + } + return result; + } +}; diff --git a/C++/reverse-linked-list-ii.cpp b/C++/reverse-linked-list-ii.cpp new file mode 100644 index 000000000..a3152d3d3 --- /dev/null +++ b/C++/reverse-linked-list-ii.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* reverseBetween(ListNode* head, int m, int n) { + ListNode dummy{0}; + dummy.next = head; + + auto *prev = &dummy; + + for (int i = 0; i < m - 1; ++i) { + prev = prev->next; + } + + auto *head2 = prev; + + prev = prev->next; + auto *cur = prev->next; + + for (int i = m; i < n; ++i) { + prev->next = cur->next; // Remove cur from the list. + cur->next = head2->next; // Add cur to the head. + head2->next = cur; // Add cur to the head. + cur = prev->next; // Get next cur. + } + + return dummy.next; + } +}; diff --git a/C++/reverse-linked-list.cpp b/C++/reverse-linked-list.cpp new file mode 100644 index 000000000..06ed186a7 --- /dev/null +++ b/C++/reverse-linked-list.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* reverseList(ListNode* head) { + auto dummy = ListNode{0}; + + while (head) { + auto tmp = head->next; + head->next = dummy.next; + dummy.next = head; + head = tmp; + } + + return dummy.next; + } +}; diff --git a/C++/reverse-nodes-in-k-group.cpp b/C++/reverse-nodes-in-k-group.cpp new file mode 100644 index 000000000..5c667d419 --- /dev/null +++ b/C++/reverse-nodes-in-k-group.cpp @@ -0,0 +1,45 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* reverseKGroup(ListNode* head, int k) { + ListNode dummy{0}; + dummy.next = head; + auto curr = head, curr_dummy = &dummy; + int len = 0; + + while (curr) { + auto next_curr = curr->next; + len = (len + 1) % k; + + if (len == 0) { + auto next_dummy = curr_dummy->next; + reverse(&curr_dummy, curr->next); + curr_dummy = next_dummy; + } + curr = next_curr; + } + return dummy.next; + } + + void reverse(ListNode **begin, const ListNode *end) { + ListNode *first = (*begin)->next; + ListNode *curr = first->next; + + while (curr != end) { + first->next = curr->next; + curr->next = (*begin)->next; + (*begin)->next = curr; + curr = first->next; + } + } +}; diff --git a/C++/reverse-pairs.cpp b/C++/reverse-pairs.cpp new file mode 100644 index 000000000..4dcc941d3 --- /dev/null +++ b/C++/reverse-pairs.cpp @@ -0,0 +1,26 @@ +// Time: O(nlogn) +// Space: O(logn) + +class Solution { +public: + int reversePairs(vector& nums) { + return countAndMergeSort(nums.begin(), nums.end()); + } + +private: + int countAndMergeSort(vector::iterator begin, vector::iterator end) { + if (end - begin <= 1) { + return 0; + } + auto mid = begin + (end - begin) / 2; + int count = countAndMergeSort(begin, mid) + countAndMergeSort(mid, end); + for (auto i = begin, j = mid; i != mid; ++i) { + while (j != end && *i > 2L * *j) { + ++j; + } + count += j - mid; + } + inplace_merge(begin, mid, end); + return count; + } +}; diff --git a/C++/reverse-string-ii.cpp b/C++/reverse-string-ii.cpp new file mode 100644 index 000000000..590c24fd1 --- /dev/null +++ b/C++/reverse-string-ii.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string reverseStr(string s, int k) { + for (int left = 0; left < s.size(); left += 2 * k) { + for (int i = left, j = min(left + k - 1, static_cast(s.size()) - 1); + i < j; ++i, --j) { + swap(s[i], s[j]); + } + } + return s; + } +}; diff --git a/C++/reverse-string.cpp b/C++/reverse-string.cpp new file mode 100644 index 000000000..c9fc329bc --- /dev/null +++ b/C++/reverse-string.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string reverseString(string s) { + for (int i = 0, j = s.length() - 1; i < j; ++i, --j) { + swap(s[i], s[j]); + } + return s; + } +}; + +// Time: O(n) +// Space: O(1) +class Solution2 { +public: + string reverseString(string s) { + reverse(s.begin(), s.end()); + return s; + } +}; diff --git a/C++/reverse-vowels-of-a-string.cpp b/C++/reverse-vowels-of-a-string.cpp new file mode 100644 index 000000000..f919e4fdd --- /dev/null +++ b/C++/reverse-vowels-of-a-string.cpp @@ -0,0 +1,24 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string reverseVowels(string s) { + for (int i = 0, j = s.length() - 1; i < j;) { + if (!is_vowel(tolower(s[i]))) { + ++i; + } else if (!is_vowel(tolower(s[j]))) { + --j; + } else { + swap(s[i++], s[j--]); + } + } + return s; + } + +private: + const string vowels_ = "aeiou"; + bool is_vowel(char a){ + return vowels_.find(a) != string::npos; + } +}; diff --git a/C++/reverse-words-in-a-string-ii.cpp b/C++/reverse-words-in-a-string-ii.cpp new file mode 100644 index 000000000..88babb196 --- /dev/null +++ b/C++/reverse-words-in-a-string-ii.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void reverseWords(string &s) { + reverse(s.begin(), s.end()); + for (int i = 0, j = 0; j <= s.length(); ++j) { + if (j == s.length() || s[j] == ' ') { + reverse(s.begin() + i, s.begin() + j); + i = j + 1; + } + } + } +}; diff --git a/C++/reverse-words-in-a-string-iii.cpp b/C++/reverse-words-in-a-string-iii.cpp new file mode 100644 index 000000000..8edc11bbc --- /dev/null +++ b/C++/reverse-words-in-a-string-iii.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string reverseWords(string s) { + for (int i = 0, j = 0; j <= s.length(); ++j) { + if (j == s.length() || s[j] == ' ') { + reverse(s.begin() + i, s.begin() + j); + i = j + 1; + } + } + return s; + } +}; diff --git a/C++/reverse-words-in-a-string.cpp b/C++/reverse-words-in-a-string.cpp new file mode 100644 index 000000000..5621252ec --- /dev/null +++ b/C++/reverse-words-in-a-string.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void reverseWords(string &s) { + // Reverse the whole string first. + reverse(s.begin(), s.end()); + + size_t begin = 0, end = 0, len = 0; + while ((begin = s.find_first_not_of(" ", end)) != string::npos) { + if ((end = s.find(" ", begin)) == string::npos) { + end = s.length(); + } + // Reverse each word in the string. + reverse(s.begin() + begin, s.begin() + end); + + // Shift the word to avoid extra space. + move(s.begin() + begin, s.begin() + end, s.begin() + len); + len += end - begin; + s[len++] = ' '; + } + s.resize(len ? len - 1 : 0); + } +}; diff --git a/C++/reverseBetween.cpp b/C++/reverseBetween.cpp deleted file mode 100644 index 0936b787e..000000000 --- a/C++/reverseBetween.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *reverseBetween(ListNode *head, int m, int n) { - ListNode dummy(-1); - dummy.next = head; - - ListNode *prev = &dummy; - - for(int i = 0; i < m - 1; ++i) { - prev = prev->next; - } - - ListNode *const head2 = prev; - - prev = prev->next; - ListNode *cur = prev->next; - - for(int i = m; i < n; ++i) { - prev->next = cur->next; // remove cur from the list - cur->next = head2->next; // add cur to the head - head2->next = cur; // add cur to the head - cur = prev->next; // get next cur - } - - return dummy.next; - } -}; diff --git a/C++/reverseKGroup.cpp b/C++/reverseKGroup.cpp deleted file mode 100644 index a384ed97a..000000000 --- a/C++/reverseKGroup.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *reverseKGroup(ListNode *head, int k) { - ListNode dummy(INT_MIN); - dummy.next = head; - - ListNode *cur = head; - ListNode *cur_dummy = &dummy; - int len = 0; - - while(cur) { - ListNode *next = cur->next; - len = (len + 1) % k; - if(len == 0) { - ListNode *next_dummy = cur_dummy->next; - reverseKGroup(cur_dummy, cur->next); - cur_dummy = next_dummy; - } - cur = next; - } - - return dummy.next; - } - - void reverseKGroup(ListNode *pre, ListNode *end) { - ListNode *first = pre->next; - ListNode *cur = first->next; - while(cur != end) { - ListNode *next = cur->next; - first->next = cur->next; // connect first node to the one next to current node - cur->next = pre->next; // remove current node from list and add the current node to the head - pre->next = cur; // connect previous node to the current node - cur = next; // set next node as current node - } - } -}; diff --git a/C++/reverseWords.cpp b/C++/reverseWords.cpp deleted file mode 100644 index c481c96b0..000000000 --- a/C++/reverseWords.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Complexity: -// O(n) time -// O(n) space - -class Solution { -public: - void reverseWords(string &s) - { - string rs; - for (int i = s.length()-1; i >= 0; ) - { - while (i >= 0 && s[i] == ' ') i--; - if (i < 0) break; - if (!rs.empty()) rs.push_back(' '); - string t; - while (i >= 0 && s[i] != ' ') t.push_back(s[i--]); - reverse(t.begin(), t.end()); - rs.append(t); - } - s = rs; - } -}; \ No newline at end of file diff --git a/C++/roman-to-integer.cpp b/C++/roman-to-integer.cpp new file mode 100644 index 000000000..13553fdea --- /dev/null +++ b/C++/roman-to-integer.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int romanToInt(string s) { + unordered_map numeral_map = {{'I', 1}, {'V', 5}, {'X', 10}, + {'L', 50}, {'C', 100}, {'D', 500}, + {'M', 1000}}; + int decimal = 0; + for (int i = 0; i < s.length(); ++i) { + if (i > 0 && numeral_map[s[i]] > numeral_map[s[i - 1]]) { + decimal += numeral_map[s[i]] - 2 * numeral_map[s[i - 1]]; + } else { + decimal += numeral_map[s[i]]; + } + } + return decimal; + } +}; diff --git a/C++/rotate-array.cpp b/C++/rotate-array.cpp new file mode 100644 index 000000000..ad98c3b4a --- /dev/null +++ b/C++/rotate-array.cpp @@ -0,0 +1,14 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void rotate(vector& nums, int k) { + if (!nums.empty()) { + k %= nums.size(); + reverse(nums.begin(), nums.begin() + nums.size() - k); + reverse(nums.begin() + nums.size() - k, nums.end()); + reverse(nums.begin(), nums.end()); + } + } +}; diff --git a/C++/rotate-function.cpp b/C++/rotate-function.cpp new file mode 100644 index 000000000..fb15b424d --- /dev/null +++ b/C++/rotate-function.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int maxRotateFunction(vector& A) { + int sum = accumulate(A.begin(), A.end(), 0); + int fi = 0; + for (int i = 0; i < A.size(); ++i) { + fi += i * A[i]; + } + + int result = fi; + for (int i = 1; i <= A.size(); ++i) { + fi += sum - A.size() * A[A.size() - i]; + result = max(result, fi); + } + return result; + } +}; diff --git a/C++/rotate-image.cpp b/C++/rotate-image.cpp new file mode 100644 index 000000000..d3ca7cc1a --- /dev/null +++ b/C++/rotate-image.cpp @@ -0,0 +1,37 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + void rotate(vector>& matrix) { + const int n = matrix.size(); + for (int i = 0; i < n / 2; ++i) { + for (int j = i; j < n - 1 - i; ++j) { + const auto tmp = matrix[i][j]; + matrix[i][j] = matrix[n - 1 - j][i]; + matrix[n - 1- j][i] = matrix[n - 1 - i][n - 1 - j]; + matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i]; + matrix[j][n - 1 - i] = tmp; + } + } + } +}; + +class Solution2 { +public: + void rotate(vector>& matrix) { + const int n = matrix.size(); + // Anti-diagonal mirror. + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n - i; ++j) { + swap(matrix[i][j], matrix[n - 1 - j][n - 1 - i]); + } + } + // Horizontal mirror. + for (int i = 0; i < n / 2; ++i) { + for (int j = 0; j < n; ++j) { + swap(matrix[i][j], matrix[n - 1 - i][j]); + } + } + } +}; diff --git a/C++/rotate-list.cpp b/C++/rotate-list.cpp new file mode 100644 index 000000000..ba6f59d07 --- /dev/null +++ b/C++/rotate-list.cpp @@ -0,0 +1,44 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (head == nullptr || head->next == nullptr) { + return head; + } + + int n = 1; + auto curr = head; + for (; curr->next; curr = curr->next) { + ++n; + } + curr->next = head; + + auto tail = curr; + k = n - k % n; + curr = head; + for (int i = 0; i < k; curr = curr->next, ++i) { + tail = curr; + } + + tail->next = nullptr; + return curr; + } +}; diff --git a/C++/rotate.cpp b/C++/rotate.cpp deleted file mode 100644 index 04d9b392c..000000000 --- a/C++/rotate.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(1) - -class Solution { - public: - void rotate(vector > &matrix) { - int n = matrix.size(); - for(int i = 0; i < n / 2; i++) { - for(int j = i; j < n - 1 - i; j++) { - int tmp = matrix[i][j]; - matrix[i][j] = matrix[n-1-j][i]; - matrix[n-1-j][i] = matrix[n-1-i][n-1-j]; - matrix[n-1-i][n-1-j]= matrix[j][n-1-i]; - matrix[j][n-1-i] = tmp; - } - } - } -}; diff --git a/C++/rotateRight.cpp b/C++/rotateRight.cpp deleted file mode 100644 index 9e5ffbd42..000000000 --- a/C++/rotateRight.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *rotateRight(ListNode *head, int k) { - ListNode dummy(INT_MIN); - dummy.next = head; - ListNode *p = &dummy; - for(int i = 0; p && i < k; ++i) { - p = p->next; - if(!p) - p = dummy.next; - } - - if(!p || !p->next) - return dummy.next; - - ListNode *cur = &dummy; - for(; p->next; cur = cur->next, p = p->next); // find new head - p->next = dummy.next; // connect tail to the head - dummy.next = cur->next; // update new head - cur->next = NULL; // update new tail - - return dummy.next; - } -}; diff --git a/C++/russian-doll-envelopes.cpp b/C++/russian-doll-envelopes.cpp new file mode 100644 index 000000000..f1c3aa3f9 --- /dev/null +++ b/C++/russian-doll-envelopes.cpp @@ -0,0 +1,28 @@ +// Time: O(nlogn + nlogk) = O(nlogn), k is the length of the result. +// Space: O(1) + +class Solution { +public: + int maxEnvelopes(vector>& envelopes) { + vector result; + + sort(envelopes.begin(), envelopes.end(), // O(nlogn) + [](const pair& a, const pair& b) { + if (a.first == b.first) { + return a.second > b.second; + } + return a.first < b.first; + }); + for (const auto& envelope : envelopes) { + const auto target = envelope.second; + auto it = lower_bound(result.begin(), result.end(), target); // O(logk) + if (it == result.end()) { + result.emplace_back(target); + } else { + *it = target; + } + } + + return result.size(); + } +}; diff --git a/C++/same-tree.cpp b/C++/same-tree.cpp new file mode 100644 index 000000000..6fa9f9dad --- /dev/null +++ b/C++/same-tree.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(h), h is height of binary tree + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool isSameTree(TreeNode* p, TreeNode* q) { + if (!p && !q) { + return true; + } + return p && q && p->val == q->val && + isSameTree(p->left, q->left) && + isSameTree(p->right, q->right); + } +}; diff --git a/C++/search-a-2d-matrix-ii.cpp b/C++/search-a-2d-matrix-ii.cpp new file mode 100644 index 000000000..e2af261ce --- /dev/null +++ b/C++/search-a-2d-matrix-ii.cpp @@ -0,0 +1,30 @@ +// Time: O(m + n) +// Space: O(1) + +class Solution { +public: + bool searchMatrix(vector>& matrix, int target) { + const int m = matrix.size(); + if (m == 0) { + return false; + } + const int n = matrix[0].size(); + if (n == 0) { + return false; + } + int count = 0; + + int i = 0, j = n - 1; + while (i < m && j >= 0) { + if (matrix[i][j] == target) { + return true; + } else if (matrix[i][j] > target) { + --j; + } else { + ++i; + } + } + + return false; + } +}; diff --git a/C++/search-a-2d-matrix.cpp b/C++/search-a-2d-matrix.cpp new file mode 100644 index 000000000..a6fcfa723 --- /dev/null +++ b/C++/search-a-2d-matrix.cpp @@ -0,0 +1,34 @@ +// Time: O(logm + logn) +// Space: O(1) + +class Solution { +public: + bool searchMatrix(vector>& matrix, int target) { + if (matrix.empty()) { + return false; + } + + // Treat matrix as 1D array. + const int m = matrix.size(); + const int n = matrix[0].size(); + int left = 0; + int right = m * n - 1; + + // Find min of left s.t. matrix[left / n][left % n] >= target + while (left <= right) { + int mid = left + (right - left) / 2; + if (matrix[mid / n][mid % n] >= target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + // Check if matrix[left / n][left % n] equals to target. + if (left != m * n && matrix[left / n][left % n] == target) { + return true; + } + + return false; + } +}; diff --git a/C++/search-for-a-range.cpp b/C++/search-for-a-range.cpp new file mode 100644 index 000000000..cd775bc3f --- /dev/null +++ b/C++/search-for-a-range.cpp @@ -0,0 +1,59 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + vector searchRange(vector& nums, int target) { + const auto start = lower_bound(nums.cbegin(), nums.cend(), target); + const auto end = upper_bound(nums.cbegin(), nums.cend(), target); + if (start != nums.cend() && *start == target) { + return {start - nums.cbegin(), end - nums.cbegin() - 1}; + } + return {-1, -1}; + } +}; + +class Solution2 { +public: + vector searchRange(vector &nums, int target) { + const int begin = lower_bound(nums, target); + const int end = upper_bound(nums, target); + + if (begin < nums.size() && nums[begin] == target) { + return {begin, end - 1}; + } + + return {-1, -1}; + } + +private: + int lower_bound(vector &nums, int target) { + int left = 0; + int right = nums.size(); + // Find min left s.t. A[left] >= target. + while (left < right) { + const auto mid = left + (right - left) / 2; + if (nums[mid] >= target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } + + int upper_bound(vector &nums, int target) { + int left = 0; + int right = nums.size(); + // Find min left s.t. A[left] > target. + while (left < right) { + const auto mid = left + (right - left) / 2; + if (nums[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } +}; diff --git a/C++/search-in-rotated-sorted-array-ii.cpp b/C++/search-in-rotated-sorted-array-ii.cpp new file mode 100644 index 000000000..8b03c92b5 --- /dev/null +++ b/C++/search-in-rotated-sorted-array-ii.cpp @@ -0,0 +1,48 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + bool search(vector &nums, int target) { + int left = 0, right = nums.size() - 1; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return true; + } else if (nums[mid] == nums[left]) { + ++left; + } else if ((nums[mid] > nums[left] && nums[left] <= target && target < nums[mid]) || + (nums[mid] < nums[left] && !(nums[mid] < target && target <= nums[right]))) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + return false; + } +}; + +class Solution2 { +public: + bool search(vector &nums, int target) { + int left = 0, right = nums.size(); + + while (left < right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return true; + } else if (nums[mid] == nums[left]) { + ++left; + } else if ((nums[left] <= nums[mid] && nums[left] <= target && target < nums[mid]) || + (nums[left] > nums[mid] && !(nums[mid] < target && target <= nums[right - 1]))) { + right = mid; + } else { + left = mid + 1; + } + } + + return false; + } +}; diff --git a/C++/search-in-rotated-sorted-array.cpp b/C++/search-in-rotated-sorted-array.cpp new file mode 100644 index 000000000..25578bc87 --- /dev/null +++ b/C++/search-in-rotated-sorted-array.cpp @@ -0,0 +1,44 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int search(vector& nums, int target) { + int left = 0, right = nums.size() - 1; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if ((nums[mid] >= nums[left] && nums[left] <= target && target < nums[mid]) || + (nums[mid] < nums[left] && !(nums[mid] < target && target <= nums[right]))) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + return -1; + } +}; + +class Solution2 { +public: + int search(vector& nums, int target) { + int left = 0, right = nums.size(); + + while (left < right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if ((nums[left] <= nums[mid] && nums[left] <= target && target < nums[mid]) || + (nums[left] > nums[mid] && !(nums[mid] < target && target <= nums[right - 1]))) { + right = mid; + } else { + left = mid + 1; + } + } + + return -1; + } +}; diff --git a/C++/search-insert-position.cpp b/C++/search-insert-position.cpp new file mode 100644 index 000000000..b348cd62e --- /dev/null +++ b/C++/search-insert-position.cpp @@ -0,0 +1,21 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int searchInsert(vector& nums, int target) { + int left = 0; + int right = nums.size() - 1; + + while (left <= right) { + const auto mid = left + (right -left) / 2; + if (nums[mid] >= target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + return left; + } +}; diff --git a/C++/search.cpp b/C++/search.cpp deleted file mode 100644 index 60f5babe4..000000000 --- a/C++/search.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Time Complexity: O(logn) -// O(n) if duplicates are allowed -// Space Complexity: O(1) - -class Solution { - public: - bool search(int A[], int n, int target) { - for(int start = 0, end = n; start < end; ) { - const int mid = (start + end) / 2; - if(A[mid] == target) - return true; - if(A[start] < A[mid]) { - if(A[start] <= target && target < A[mid]) - end = mid; - else - start = mid + 1; - } - else if(A[start] > A[mid]) { - if(A[mid] < target && target <= A[end - 1]) - start = mid + 1; - else - end = mid; - } - else - ++start; - } - return false; - } -}; diff --git a/C++/searchMatrix.cpp b/C++/searchMatrix.cpp deleted file mode 100644 index 6bc9a9a07..000000000 --- a/C++/searchMatrix.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Time Complexity: O(m+n) (Akra-Bazzi theorem) -// Space Complexity: O(log(mn)) - -class Solution { - public: - bool partitionAndSearch(vector > &matrix, int target, int i, int j, int m, int n) { - if(m < 1 || n < 1) - return false; - int start, end; - for(start = 0, end = min(m, n); start < end;) { - int tmp = (start+end)/2; - if(target < matrix[i+tmp][j+tmp]) - end = tmp; - else if (target > matrix[i+tmp][j+tmp]) - start = tmp+1; - else - return true; - } - if(start < 1) - return false; - return partitionAndSearch(matrix, target, i, j+start, m, n - start) - || partitionAndSearch(matrix, target, i+start, j, m - start, n); - } - bool searchMatrix(vector > &matrix, int target) { - return partitionAndSearch(matrix, target, 0, 0, matrix.size(), matrix[0].size()); - } -}; diff --git a/C++/searchRange.cpp b/C++/searchRange.cpp deleted file mode 100644 index abcf490e0..000000000 --- a/C++/searchRange.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Time Complexity: O(logn) -// Space Complexity: O(1) - -class Solution { - public: - vector searchRange(int A[], int n, int target) { - int begin = lower_bound(A, n, target); - int end = upper_bound(A, n, target); - - if(begin < n && A[begin] == target) - return {begin, end - 1}; - - return {-1, -1}; - } - - private: - int lower_bound(int A[], int n, int target) { - int begin = 0; - int end = n; - while(begin < end) { - int mid = (begin + end) / 2; - if(A[mid] < target) - begin = mid + 1; - else - end = mid; - } - return begin; - } - - int upper_bound(int A[], int n, int target) { - int begin = 0; - int end = n; - while(begin < end) { - int mid = (begin + end) / 2; - if(A[mid] <= target) - begin = mid + 1; - else - end = mid; - } - return begin; - } -}; diff --git a/C++/second-minimum-node-in-a-binary-tree.cpp b/C++/second-minimum-node-in-a-binary-tree.cpp new file mode 100644 index 000000000..19134d7dd --- /dev/null +++ b/C++/second-minimum-node-in-a-binary-tree.cpp @@ -0,0 +1,36 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int findSecondMinimumValue(TreeNode* root) { + set bst; + findSecondMinimumValueHelper(root, &bst); + if (bst.size() < 2) { + return -1; + } + return *bst.rbegin(); + } + +private: + void findSecondMinimumValueHelper(TreeNode* root, set *bst) { + if (!root) { + return; + } + bst->emplace(root->val); + if (bst->size() > 2) { + bst->erase(prev(bst->end())); + } + findSecondMinimumValueHelper(root->left, bst); + findSecondMinimumValueHelper(root->right, bst); + } +}; diff --git a/C++/self-crossing.cpp b/C++/self-crossing.cpp new file mode 100644 index 000000000..2db45b704 --- /dev/null +++ b/C++/self-crossing.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isSelfCrossing(vector& x) { + if (x.size() >= 5 && x[3] == x[1] && x[4] + x[0] >= x[2]) { + // Crossing in a loop: + // 2 + // 3 ┌────┐ + // └─══>┘1 + // 4 0 (overlapped) + return true; + } + + for (int i = 3; i < x.size(); ++i) { + if (x[i] >= x[i - 2] && x[i - 3] >= x[i - 1]) { + // Case 1: + // i-2 + // i-1┌─┐ + // └─┼─>i + // i-3 + return true; + } else if (i >= 5 && x[i - 4] <= x[i - 2] && x[i] + x[i - 4] >= x[i - 2] && + x[i - 1] <= x[i - 3] && x[i - 1] + x[i - 5] >= x[i - 3]) { + // Case 2: + // i-4 + // ┌──┐ + // │i<┼─┐ + // i-3│ i-5│i-1 + // └────┘ + // i-2 + return true; + } + } + return false; + } +}; diff --git a/C++/self-dividing-numbers.cpp b/C++/self-dividing-numbers.cpp new file mode 100644 index 000000000..d4a1565c5 --- /dev/null +++ b/C++/self-dividing-numbers.cpp @@ -0,0 +1,25 @@ +// Time: O(nlogr) = O(n) +// Space: O(logr) = O(1) + +class Solution { +public: + vector selfDividingNumbers(int left, int right) { + vector result; + for (int i = left; i <= right; ++i) { + if (isDividingNumber(i)) { + result.emplace_back(i); + } + } + return result; + } + +private: + bool isDividingNumber(int num) { + for (int n = num; n > 0; n /= 10) { + if (!(n % 10) || num % (n % 10)) { + return false; + } + } + return true; + } +}; diff --git a/C++/sentence-screen-fitting.cpp b/C++/sentence-screen-fitting.cpp new file mode 100644 index 000000000..e63cf0072 --- /dev/null +++ b/C++/sentence-screen-fitting.cpp @@ -0,0 +1,35 @@ +// Time: O(r + n * c) +// Space: O(n) + +class Solution { +public: + int wordsTyping(vector& sentence, int rows, int cols) { + vector wc(sentence.size()); + for (int i = 0; i < sentence.size(); ++i) { + wc[i] = wordsFit(sentence, i, cols); + } + + int words = 0, start = 0; + for (int i = 0; i < rows; ++i) { + words += wc[start]; + start = (start + wc[start]) % sentence.size(); + } + return words / sentence.size(); + } + +private: + int wordsFit(const vector& sentence, int start, int cols) { + if (sentence[start].length() > cols) { + return 0; + } + + int sum = sentence[start].length(), count = 1; + for (int i = (start + 1) % sentence.size(); + sum + 1 + sentence[i].length() <= cols; + i = (i + 1) % sentence.size()) { + sum += 1 + sentence[i].length(); + ++count; + } + return count; + } +}; diff --git a/C++/sentence-similarity-ii.cpp b/C++/sentence-similarity-ii.cpp new file mode 100644 index 000000000..e556e2e69 --- /dev/null +++ b/C++/sentence-similarity-ii.cpp @@ -0,0 +1,58 @@ +// Time: O(n + p) +// Space: O(p) + +class Solution { +public: + bool areSentencesSimilarTwo(vector& words1, vector& words2, vector> pairs) { + if (words1.size() != words2.size()) { + return false; + } + unordered_map lookup; + UnionFind union_find(2 * pairs.size()); + for (const auto& pair : pairs) { + if (!lookup.count(pair.first)) { + lookup.emplace(pair.first, lookup.size()); + } + if (!lookup.count(pair.second)) { + lookup.emplace(pair.second, lookup.size()); + } + union_find.union_set(lookup[pair.first], lookup[pair.second]); + } + for (int i = 0; i < words1.size(); ++i) { + if (words1[i] != words2[i] && + (!lookup.count(words1[i]) || !lookup.count(words2[i]) || + union_find.find_set(lookup[words1[i]]) != + union_find.find_set(lookup[words2[i]]))) { + return false; + } + } + return true; + } + +private: + class UnionFind { + public: + UnionFind(const int n) : set_(n) { + iota(set_.begin(), set_.end(), 0); + } + + int find_set(const int x) { + if (set_[x] != x) { + set_[x] = find_set(set_[x]); // Path compression. + } + return set_[x]; + } + + bool union_set(const int x, const int y) { + int x_root = find_set(x), y_root = find_set(y); + if (x_root == y_root) { + return false; + } + set_[min(x_root, y_root)] = max(x_root, y_root); + return true; + } + + private: + vector set_; + }; +}; diff --git a/C++/sentence-similarity.cpp b/C++/sentence-similarity.cpp new file mode 100644 index 000000000..076568ee3 --- /dev/null +++ b/C++/sentence-similarity.cpp @@ -0,0 +1,34 @@ +// Time: O(n + p) +// Space: O(p) + +class Solution { +public: + bool areSentencesSimilar(vector& words1, vector& words2, vector> pairs) { + if (words1.size() != words2.size()) { + return false; + } + unordered_set, PairHash> lookup; + for (const auto& pair : pairs) { + lookup.emplace(pair.first, pair.second); + lookup.emplace(pair.second, pair.first); + } + for (int i = 0; i < words1.size(); ++i) { + if (words1[i] != words2[i] && + !lookup.count(make_pair(words1[i], words2[i]))) { + return false; + } + } + return true; + } + +private: + template + struct PairHash { + size_t operator()(const pair& p) const { + size_t seed = 0; + seed ^= std::hash{}(p.first) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= std::hash{}(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2); + return seed; + } + }; +}; diff --git a/C++/sequence-reconstruction.cpp b/C++/sequence-reconstruction.cpp new file mode 100644 index 000000000..2778589d1 --- /dev/null +++ b/C++/sequence-reconstruction.cpp @@ -0,0 +1,36 @@ +// Time: O(n * s), n is the size of org, s is the size of seqs +// Space: O(n) + +class Solution { +public: + bool sequenceReconstruction(vector& org, vector>& seqs) { + if (seqs.empty()) { + return false; + } + vector pos(org.size() + 1); + for (int i = 0; i < org.size(); ++i) { + pos[org[i]] = i; + } + + vector is_matched(org.size() + 1); + int cnt_to_match = org.size() - 1; + for (const auto& seq : seqs) { + for (int i = 0; i < seq.size(); ++i) { + if (seq[i] <= 0 || seq[i] > org.size()) { + return false; + } + if (i == 0) { + continue; + } + if (pos[seq[i - 1]] >= pos[seq[i]]) { + return false; + } + if (is_matched[seq[i - 1]] == false && pos[seq[i - 1]] + 1 == pos[seq[i]]) { + is_matched[seq[i - 1]] = true; + --cnt_to_match; + } + } + } + return cnt_to_match == 0; + } +}; diff --git a/C++/serialize-and-deserialize-binary-tree.cpp b/C++/serialize-and-deserialize-binary-tree.cpp new file mode 100644 index 000000000..baeb0076e --- /dev/null +++ b/C++/serialize-and-deserialize-binary-tree.cpp @@ -0,0 +1,119 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Codec { +public: + + // Encodes a tree to a single string. + string serialize(TreeNode* root) { + string output; + serializeHelper(root, &output); + return output; + } + + // Decodes your encoded data to tree. + TreeNode* deserialize(string data) { + TreeNode *root = nullptr; + int start = 0; + return deserializeHelper(data, &start); + } + +private: + bool getNumber(const string &data, int *start, int *num) { + int sign = 1; + if (data[*start] == '#') { + *start += 2; // Skip "# ". + return false; + } else if (data[*start] == '-') { + sign = -1; + ++(*start); + } + + for (*num = 0; isdigit(data[*start]); ++(*start)) { + *num = *num * 10 + data[*start] - '0'; + } + *num *= sign; + ++(*start); // Skip " ". + + return true; + } + + void serializeHelper(const TreeNode *root, string *prev) { + if (!root) { + prev->append("# "); + } else { + prev->append(to_string(root->val).append(" ")); + serializeHelper(root->left, prev); + serializeHelper(root->right, prev); + } + } + + TreeNode *deserializeHelper(const string& data, int *start) { + int num; + if (!getNumber(data, start, &num)) { + return nullptr; + } else { + TreeNode *root = new TreeNode(num); + root->left = deserializeHelper(data, start); + root->right = deserializeHelper(data, start); + return root; + } + } +}; + + +// Time: O(n) +// Space: O(n) +class Codec2 { +public: + + // Encodes a tree to a single string. + string serialize(TreeNode* root) { + ostringstream out; + serializeHelper(root, out); + return out.str(); + } + + // Decodes your encoded data to tree. + TreeNode* deserialize(string data) { + istringstream in(data); // Space: O(n) + return deserializeHelper(in); + } + +private: + void serializeHelper(const TreeNode *root, ostringstream& out) { + if (!root) { + out << "# "; + } else { + out << root->val << " "; + serializeHelper(root->left, out); + serializeHelper(root->right, out); + } + } + + TreeNode *deserializeHelper(istringstream& in) { + string val; + in >> val; + if (val == "#") { + return nullptr; + } else { + TreeNode* root = new TreeNode(stoi(val)); + root->left = deserializeHelper(in); + root->right = deserializeHelper(in); + return root; + } + } +}; + +// Your Codec object will be instantiated and called as such: +// Codec codec; +// codec.deserialize(codec.serialize(root)); diff --git a/C++/serialize-and-deserialize-bst.cpp b/C++/serialize-and-deserialize-bst.cpp new file mode 100644 index 000000000..8ac849122 --- /dev/null +++ b/C++/serialize-and-deserialize-bst.cpp @@ -0,0 +1,59 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Codec { +public: + + // Encodes a tree to a single string. + string serialize(TreeNode* root) { + string data; + serializeHelper(root, &data); + return data; + } + + // Decodes your encoded data to tree. + TreeNode* deserialize(string data) { + int i = 0; + return deserializeHelper(numeric_limits::min(), numeric_limits::max(), data, &i); + } + + +private: + void serializeHelper(TreeNode *node, string *data) { + if (node) { + *data += to_string(node->val) + " "; + serializeHelper(node->left, data); + serializeHelper(node->right, data); + } + } + + TreeNode* deserializeHelper(int minVal, int maxVal, const string& data, int *i) { + if (*i == data.length()) { + return nullptr; + } + int j = data.find(' ', *i); + auto val = stoi(data.substr(*i, j - *i)); + if (minVal < val && val < maxVal) { + auto node = new TreeNode(val); + *i = j + 1; + node->left = deserializeHelper(minVal, val, data, i); + node->right = deserializeHelper(val, maxVal, data, i); + return node; + } else { + return nullptr; + } + } +}; + +// Your Codec object will be instantiated and called as such: +// Codec codec; +// codec.deserialize(codec.serialize(root)); diff --git a/C++/set-matrix-zeroes.cpp b/C++/set-matrix-zeroes.cpp new file mode 100644 index 000000000..b251ce394 --- /dev/null +++ b/C++/set-matrix-zeroes.cpp @@ -0,0 +1,50 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + void setZeroes(vector>& matrix) { + if (matrix.empty()) { + return; + } + + bool has_zero = false; + int zero_i = -1, zero_j = -1; + + for (int i = 0; i < matrix.size(); ++i) { + for (int j = 0; j < matrix[0].size(); ++j) { + if (matrix[i][j] == 0) { + if (!has_zero) { + zero_i = i; + zero_j = j; + has_zero = true; + } + matrix[zero_i][j] = 0; + matrix[i][zero_j] = 0; + } + } + } + + if (has_zero) { + for (int i = 0; i < matrix.size(); ++i) { + if (i == zero_i) { + continue; + } + for (int j = 0; j < matrix[0].size(); ++j) { + if (j == zero_j) { + continue; + } + if (matrix[zero_i][j] == 0 || matrix[i][zero_j] == 0) { + matrix[i][j] = 0; + } + } + } + for (int i = 0; i < matrix.size(); ++i) { + matrix[i][zero_j] = 0; + } + for (int j = 0; j < matrix[0].size(); ++j) { + matrix[zero_i][j] = 0; + } + } + } +}; diff --git a/C++/set-mismatch.cpp b/C++/set-mismatch.cpp new file mode 100644 index 000000000..f5a28b1e6 --- /dev/null +++ b/C++/set-mismatch.cpp @@ -0,0 +1,47 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector findErrorNums(vector& nums) { + int x_xor_y = 0; + for (int i = 0; i < nums.size(); ++i) { + x_xor_y ^= nums[i] ^ (i + 1); + } + int bit = x_xor_y & ~(x_xor_y - 1); + vector result(2); + for (int i = 0; i < nums.size(); ++i) { + result[static_cast(nums[i] & bit)] ^= nums[i]; + result[static_cast((i + 1) & bit)] ^= i + 1; + } + if (find(nums.begin(), nums.end(), result[0]) == nums.end()) { + swap(result[0], result[1]); + } + return result; + } +}; + + +// Time: O(n) +// Space: O(1) +class Solution2 { +public: + vector findErrorNums(vector& nums) { + vector result(2); + for (const auto& i : nums) { + if (nums[abs(i) - 1] < 0) { // twice + result[0] = abs(i); + } else { + nums[abs(i) - 1] *= -1; + } + } + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] > 0) { // missing + result[1] = i + 1; + } else { + nums[i] *= -1; + } + } + return result; + } +}; diff --git a/C++/shopping-offers.cpp b/C++/shopping-offers.cpp new file mode 100644 index 000000000..09b8ec402 --- /dev/null +++ b/C++/shopping-offers.cpp @@ -0,0 +1,31 @@ +// Time: O(n * 2^n) +// Space: O(n) + +class Solution { +public: + int shoppingOffers(vector& price, vector>& special, vector& needs) { + return shoppingOffersHelper(price, special, needs, 0); + } + +private: + int shoppingOffersHelper(const vector& price, const vector>& special, vector& needs, int i) { + if (i == special.size()) { + return inner_product(price.begin(), price.end(), needs.begin(), 0); + } + + int result = shoppingOffersHelper(price, special, needs, i + 1); + + for (int j = 0; j < needs.size(); ++j) { + needs[j] -= special[i][j]; + } + if (all_of(needs.begin(), needs.end(), [](int i) { return i >= 0; })) { + result = min(result, special[i].back() + shoppingOffersHelper(price, special, needs, i)); + } + for (int j = 0; j < needs.size(); ++j) { + needs[j] += special[i][j]; + } + + return result; + } +}; + diff --git a/C++/shortest-completing-word.cpp b/C++/shortest-completing-word.cpp new file mode 100644 index 000000000..0ece33588 --- /dev/null +++ b/C++/shortest-completing-word.cpp @@ -0,0 +1,38 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string shortestCompletingWord(string licensePlate, vector& words) { + string result; + const auto& counter = counts(licensePlate); + for (const auto& word : words) { + if ((result.empty() || word.length() < result.length()) && + contains(counter, word)) { + result = word; + } + } + return result; + } + +private: + bool contains(const vector& counter1, const string& w2) const { + const auto& counter2 = counts(w2); + for (int i = 0; i < counter2.size(); ++i) { + if (counter1[i] > counter2[i]) { + return false; + } + } + return true; + } + + vector counts(const string& s) const { + vector count(26); + for (const auto& c : s) { + if (isalpha(c)) { + ++count[tolower(c) - 'a']; + } + } + return count; + } +}; diff --git a/C++/shortest-distance-from-all-buildings.cpp b/C++/shortest-distance-from-all-buildings.cpp new file mode 100644 index 000000000..218721bfa --- /dev/null +++ b/C++/shortest-distance-from-all-buildings.cpp @@ -0,0 +1,59 @@ +// Time: O(k * m * n), k is the number of the buildings +// Space: O(m * n) + +class Solution { +public: + int shortestDistance(vector>& grid) { + int m = grid.size(), n = grid[0].size(), cnt = 0; + vector> dists(m, vector(n)), cnts(m, vector(n)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == 1) { + ++cnt; + BFS(grid, i, j, &dists, &cnts); + } + } + } + + int shortest = numeric_limits::max(); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (dists[i][j] < shortest && cnts[i][j] == cnt) { + shortest = dists[i][j]; + } + } + } + + return shortest != numeric_limits::max() ? shortest : -1; + } + + void BFS(const vector>& grid, int x, int y, + vector> *dists, vector> *cnts) { + int dist = 0, m = grid.size(), n = grid[0].size(); + vector> visited(m, vector(n)); + + vector> pre_level{{x, y}}, cur_level; + visited[x][y] = true; + while (!pre_level.empty()) { + ++dist; + cur_level.clear(); + for (const auto& p : pre_level) { + int i, j; + tie(i, j) = p; + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + for (const auto& d : directions) { + const int I = i + d.first, J = j + d.second; + if (0 <= I && I < m && 0 <= J && J < n && + grid[I][J] == 0 && !visited[I][J]) { + (*dists)[I][J] += dist; + ++(*cnts)[I][J]; + cur_level.push_back({I, J}); + visited[I][J] = true; + } + } + } + swap(pre_level, cur_level); + } + } +}; diff --git a/C++/shortest-palindrome.cpp b/C++/shortest-palindrome.cpp new file mode 100644 index 000000000..094d6df5e --- /dev/null +++ b/C++/shortest-palindrome.cpp @@ -0,0 +1,104 @@ +// Time: O(n) +// Space: O(n) + +// KMP Algorithm +class Solution { +public: + string shortestPalindrome(string s) { + if (s.empty()) { + return s; + } + string rev_s(s.crbegin(), s.crend()); + // Assume s is (Palindrome)abc, + // A would be (Palindrome)abccba(Palindrome). + string A = s + rev_s; + auto prefix = getPrefix(A); + // The index prefix.back() of A would be: + // (Palindrome)abccba(Palindrome) + // ^ + // The index prefix.back() + 1 of s would be: + // (Palindrome)abc + // ^ + // Get non palindrome part of s. + int i = prefix.back(); + while (i >= s.length()) { + i = prefix[i]; + } + string non_palindrome = s.substr(i + 1); + reverse(non_palindrome.begin(), non_palindrome.end()); + return non_palindrome + s; // cba(Palindrome)abc. + } + +private: + vector getPrefix(const string& pattern) { + vector prefix(pattern.length(), -1); + int j = -1; + for (int i = 1; i < pattern.length(); ++i) { + while (j > -1 && pattern[j + 1] != pattern[i]) { + j = prefix[j]; + } + if (pattern[j + 1] == pattern[i]) { + ++j; + } + prefix[i] = j; + } + return prefix; + } +}; + +// Time: O(n) +// Space: O(n) +// Manacher's Algorithm +class Solution2 { +public: + string shortestPalindrome(string s) { + string T = preProcess(s); + int n = T.length(); + vector P(n); + int C = 0, R = 0; + for (int i = 1; i < n - 1; ++i) { + int i_mirror = 2 * C - i; // equals to i' = C - (i-C) + + P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; + + // Attempt to expand palindrome centered at i + while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) { + ++P[i]; + } + + // If palindrome centered at i expand past R, + // adjust center based on expanded palindrome. + if (i + P[i] > R) { + C = i; + R = i + P[i]; + } + } + + // Find the max len of palindrome which starts with the first char of s. + int max_len = 0; + for (int i = 1; i < n - 1; ++i) { + if (i - P[i] == 1) { + max_len = P[i]; + } + } + + // Assume s is (Palindrome)abc. + string ans = s.substr(max_len); // abc. + reverse(ans.begin(), ans.end()); // cba. + ans.append(s); // cba(Palindrome)abc. + return ans; + } +private: + string preProcess(string s) { + int n = s.length(); + if (n == 0) { + return "^$"; + } + string ret = "^"; + for (int i = 0; i < n; ++i) { + ret += "#" + s.substr(i, 1); + } + ret += "#$"; + return ret; + } +}; diff --git a/C++/shortest-unsorted-continuous-subarray.cpp b/C++/shortest-unsorted-continuous-subarray.cpp new file mode 100644 index 000000000..fe45e1ac8 --- /dev/null +++ b/C++/shortest-unsorted-continuous-subarray.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findUnsortedSubarray(vector& nums) { + const auto n = nums.size(); + auto left = -1, right = -2; + auto max_from_left = nums[0], min_from_right = nums.back(); + for (int i = 1; i < n; ++i) { + max_from_left = max(max_from_left, nums[i]); + min_from_right = min(min_from_right, nums[n - 1 - i]); + if (nums[i] < max_from_left) { + right = i; + } + if (nums[n - 1 - i] > min_from_right) { + left = n - 1 - i; + } + } + return right - left + 1; + } +}; diff --git a/C++/shortest-word-distance-ii.cpp b/C++/shortest-word-distance-ii.cpp new file mode 100644 index 000000000..a402d7b15 --- /dev/null +++ b/C++/shortest-word-distance-ii.cpp @@ -0,0 +1,26 @@ +// Time: ctor: O(n), shortest: O(a + b), a, b is occurences of word1, word2 +// Space: O(n) + +class WordDistance { +public: + WordDistance(vector words) { + for (int i = 0; i < words.size(); ++i) { + wordIndex[words[i]].emplace_back(i); + } + } + + int shortest(string word1, string word2) { + const vector& indexes1 = wordIndex[word1]; + const vector& indexes2 = wordIndex[word2]; + + int i = 0, j = 0, dist = INT_MAX; + while (i < indexes1.size() && j < indexes2.size()) { + dist = min(dist, abs(indexes1[i] - indexes2[j])); + indexes1[i] < indexes2[j] ? ++i : ++j; + } + return dist; + } + +private: + unordered_map> wordIndex; +}; diff --git a/C++/shortest-word-distance-iii.cpp b/C++/shortest-word-distance-iii.cpp new file mode 100644 index 000000000..6043f572f --- /dev/null +++ b/C++/shortest-word-distance-iii.cpp @@ -0,0 +1,24 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int shortestWordDistance(vector& words, string word1, string word2) { + int dist = INT_MAX; + bool is_same = (word1 == word2); + for (int i = 0, index1 = -1, index2 = -1; i < words.size(); ++i) { + if (words[i] == word1) { + if (is_same && index1 != -1) { + dist = min(dist, abs(index1 - i)); + } + index1 = i; + } else if (words[i] == word2) { + index2 = i; + } + if (index1 != -1 && index2 != -1) { + dist = min(dist, abs(index1 - index2)); + } + } + return dist; + } +}; diff --git a/C++/shortest-word-distance.cpp b/C++/shortest-word-distance.cpp new file mode 100644 index 000000000..cd7957e2d --- /dev/null +++ b/C++/shortest-word-distance.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int shortestDistance(vector& words, string word1, string word2) { + int dist = INT_MAX; + for (int i = 0, index1 = -1, index2 = -1; i < words.size(); ++i) { + if (words[i] == word1) { + index1 = i; + } else if (words[i] == word2) { + index2 = i; + } + if (index1 != -1 && index2 != -1) { + dist = min(dist, abs(index1 - index2)); + } + } + return dist; + } +}; diff --git a/C++/shuffle-an-array.cpp b/C++/shuffle-an-array.cpp new file mode 100644 index 000000000..2d60b923f --- /dev/null +++ b/C++/shuffle-an-array.cpp @@ -0,0 +1,36 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + Solution(vector nums) : nums_(nums) { + + } + + /** Resets the array to its original configuration and return it. */ + vector reset() { + return nums_; + } + + /** Returns a random shuffling of the array. */ + vector shuffle() { + vector nums{nums_}; + default_random_engine seed((random_device())()); + for (int i = 0; i < nums.size(); ++i) { + swap(nums[i], nums[uniform_int_distribution{ + i, static_cast(nums.size()) - 1}(seed)]); + } + return nums; + } + +private: + const vector nums_; +}; + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(nums); + * vector param_1 = obj.reset(); + * vector param_2 = obj.shuffle(); + */ + diff --git a/C++/simplify-path.cpp b/C++/simplify-path.cpp new file mode 100644 index 000000000..3528b86f0 --- /dev/null +++ b/C++/simplify-path.cpp @@ -0,0 +1,42 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string simplifyPath(string path) { + vector names; + vector tokens(move(split(path, '/'))); + for (const auto& token : tokens) { + if (token == ".." && !names.empty()) { + names.pop_back(); + } else if (token != ".." && token != "." && !token.empty()) { + names.emplace_back(token); + } + } + return string("/").append(join(names, '/')); + } + +private: + // Split string by delimitor. + vector split(const string& s, const char delim) { + vector tokens; + stringstream ss(s); + string token; + while (getline(ss, token, delim)) { + tokens.emplace_back(token); + } + return tokens; + } + + // Join strings with delimitor. + string join(const vector& names, const char delim) { + ostringstream ss; + if (!names.empty()) { + const string delim_str(1, delim); + copy(names.cbegin(), prev(names.cend()), + ostream_iterator(ss, delim_str.c_str())); + ss << names.back(); + } + return ss.str(); + } +}; diff --git a/C++/simplifyPath.cpp b/C++/simplifyPath.cpp deleted file mode 100644 index 992aafdac..000000000 --- a/C++/simplifyPath.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(n) - -class Solution { - public: - string simplifyPath(string path) { - vector dirs; - - for(auto i = path.cbegin(); i != path.cend();) { - ++i; // write here is to make sure i is not end - - auto j = find(i, path.cend(), '/'); - string dir = string(i, j); - - if(!dir.empty() && dir != ".") { - if(dir == "..") { - if(!dirs.empty()) dirs.pop_back(); - } - else - dirs.push_back(dir); - } - i = j; // i may be end - } - - if(dirs.empty()) return "/"; - - string ans; - for(auto dir : dirs) { - ans.append("/" + dir); - } - - return ans; - } -}; diff --git a/C++/single-element-in-a-sorted-array.cpp b/C++/single-element-in-a-sorted-array.cpp new file mode 100644 index 000000000..3f800b08e --- /dev/null +++ b/C++/single-element-in-a-sorted-array.cpp @@ -0,0 +1,21 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int left = 0, right = nums.size() - 1; + while (left <= right) { + auto mid = left + (right - left) / 2; + if (!(mid % 2 == 0 && mid + 1 < nums.size() && + nums[mid] == nums[mid + 1]) && + !(mid % 2 == 1 && nums[mid] == nums[mid - 1])) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return nums[left]; + } +}; + diff --git a/C++/single-number-ii.cpp b/C++/single-number-ii.cpp new file mode 100644 index 000000000..be693c446 --- /dev/null +++ b/C++/single-number-ii.cpp @@ -0,0 +1,17 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int singleNumber(vector& nums) { + int one = 0, two = 0; + + for (const auto& i : nums) { + int new_one = (~i & one) | (i & ~one & ~two); + int new_two = (~i & two) | (i & one); + one = new_one, two = new_two; + } + + return one; + } +}; diff --git a/C++/single-number-iii.cpp b/C++/single-number-iii.cpp new file mode 100644 index 000000000..02893acac --- /dev/null +++ b/C++/single-number-iii.cpp @@ -0,0 +1,50 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector singleNumber(vector& nums) { + // Xor all the elements to get x ^ y. + const auto x_xor_y = accumulate(nums.cbegin(), nums.cend(), 0, bit_xor()); + + // Get the last bit where 1 occurs by "x & ~(x - 1)" + // Because -(x - 1) = ~(x - 1) + 1 <=> -x = ~(x - 1) + // So we can also get the last bit where 1 occurs by "x & -x" + const auto bit = x_xor_y & -x_xor_y; + + // Get the subset of A where the number has the bit. + // The subset only contains one of the two integers, call it x. + // Xor all the elements in the subset to get x. + vector result(2, 0); + for (const auto& i : nums) { + result[static_cast(i & bit)] ^= i; + } + return result; + } +}; + +class Solution2 { +public: + vector singleNumber(vector& nums) { + // Xor all the elements to get x ^ y. + int x_xor_y = 0; + for (const auto& i : nums) { + x_xor_y ^= i; + } + + // Get the last bit where 1 occurs. + const auto bit = x_xor_y & ~(x_xor_y - 1); + + // Get the subset of A where the number has the bit. + // The subset only contains one of the two integers, call it x. + // Xor all the elements in the subset to get x. + int x = 0; + for (const auto& i : nums) { + if (i & bit) { + x ^= i; + } + } + + return {x, x_xor_y ^ x}; + } +}; diff --git a/C++/single-number.cpp b/C++/single-number.cpp new file mode 100644 index 000000000..d42eed2cd --- /dev/null +++ b/C++/single-number.cpp @@ -0,0 +1,10 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int singleNumber(vector& nums) { + return accumulate(nums.cbegin(), nums.cend(), + 0, std::bit_xor()); + } +}; diff --git a/C++/sliding-window-maximum.cpp b/C++/sliding-window-maximum.cpp new file mode 100644 index 000000000..5960d102d --- /dev/null +++ b/C++/sliding-window-maximum.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(k) + +class Solution { +public: + vector maxSlidingWindow(vector& nums, int k) { + deque dq; + vector max_numbers; + + for (int i = 0; i < nums.size(); ++i) { + while (!dq.empty() && nums[i] >= nums[dq.back()]) { + dq.pop_back(); + } + dq.emplace_back(i); + if (i >= k && !dq.empty() && dq.front() == i - k) { + dq.pop_front(); + } + if (i >= k - 1) { + max_numbers.emplace_back(nums[dq.front()]); + } + } + + return max_numbers; + } +}; diff --git a/C++/sliding-window-median.cpp b/C++/sliding-window-median.cpp new file mode 100644 index 000000000..984721150 --- /dev/null +++ b/C++/sliding-window-median.cpp @@ -0,0 +1,42 @@ +// Time: O(nlogk) +// Space: O(k) + +class Solution { +public: +vector medianSlidingWindow(vector& nums, int k) { + multiset> min_bst; + multiset> max_bst; + + vector result; + for (int i = 0; i < nums.size(); ++i) { + if (i >= k) { + if (max_bst.find(nums[i - k]) != max_bst.cend()) { + max_bst.erase(max_bst.find(nums[i - k])); + } else { + min_bst.erase(min_bst.find(nums[i - k])); + } + } + + if (max_bst.empty() || nums[i] > *max_bst.cbegin()) { + min_bst.emplace(nums[i]); + if (min_bst.size() > max_bst.size() + 1) { + max_bst.emplace(*min_bst.cbegin()); + min_bst.erase(min_bst.cbegin()); + } + } else { + max_bst.emplace(nums[i]); + if (max_bst.size() > min_bst.size()) { + min_bst.emplace(*max_bst.cbegin()); + max_bst.erase(max_bst.cbegin()); + } + } + + if (i >= k - 1) { + result.emplace_back(min_bst.size() == max_bst.size() ? + *max_bst.cbegin() / 2.0 + *min_bst.cbegin() / 2.0 : *min_bst.cbegin()); + } + } + + return result; + } +}; diff --git a/C++/smallest-good-base.cpp b/C++/smallest-good-base.cpp new file mode 100644 index 000000000..e3a435ab1 --- /dev/null +++ b/C++/smallest-good-base.cpp @@ -0,0 +1,19 @@ +// Time: O((logn)^2) +// Space: O(1) + +class Solution { +public: + string smallestGoodBase(string n) { + unsigned long long num = stoll(n); + for (int l = log(num) / log(2); l >= 2; --l) { + unsigned long long b = pow(num, 1.0 / l), sum = 0, curr = 1; + for (int i = 0; i <= l; ++i, curr *= b) { + sum += curr; + } + if (sum == num) { + return to_string(b); + } + } + return to_string(num - 1); + } +}; diff --git a/C++/smallest-range.cpp b/C++/smallest-range.cpp new file mode 100644 index 000000000..f0a3bfdb2 --- /dev/null +++ b/C++/smallest-range.cpp @@ -0,0 +1,40 @@ +// Time: O(nlogk) +// Space: O(k) + +class Solution { +public: + vector smallestRange(vector>& nums) { + using VIT = vector::iterator; + + const auto comp = [](const pair& p1, const pair& p2) { + return *p1.first > *p2.first; + }; + + int left = numeric_limits::max(), right = numeric_limits::min(); + priority_queue, vector>, decltype(comp)> min_heap(comp); + for (auto &row : nums) { + left = min(left, row[0]); + right = max(right, row[0]); + min_heap.emplace(row.begin(), row.end()); + } + + vector result = {left, right}; + while (!min_heap.empty()) { + auto p = min_heap.top(); + min_heap.pop(); + ++p.first; + if (p.first == p.second) { + break; + } + min_heap.emplace(p); + + left = *min_heap.top().first; + right = max(right, *p.first); + if (right - left < result[1] - result[0]) { + result = {left, right}; + } + } + return result; + } +}; + diff --git a/C++/smallest-rectangle-enclosing-black-pixels.cpp b/C++/smallest-rectangle-enclosing-black-pixels.cpp new file mode 100644 index 000000000..9f96b1eee --- /dev/null +++ b/C++/smallest-rectangle-enclosing-black-pixels.cpp @@ -0,0 +1,128 @@ +// Time: O(nlogn) +// Space: O(1) + +// Using template. +class Solution { +public: + int minArea(vector>& image, int x, int y) { + using namespace std::placeholders; // for _1, _2, _3... + + const auto searchColumns = + [](const vector>& image, bool has_one, const int mid) { + return has_one == any_of(image.cbegin(), image.cend(), + [=](const vector& row) { return row[mid] == '1'; }); + }; + const auto searchRows = + [](const vector>& image, bool has_one, const int mid) { + return has_one == any_of(image[mid].cbegin(), image[mid].cend(), + [](const char& col) { return col == '1'; }); + }; + + const int left = binarySearch(0, y - 1, bind(searchColumns, image, true, _1)); + const int right = binarySearch(y + 1, image[0].size() - 1, bind(searchColumns, image, false, _1)); + const int top = binarySearch(0, x - 1, bind(searchRows, image, true, _1)); + const int bottom = binarySearch(x + 1, image.size() - 1, bind(searchRows, image, false, _1)); + + return (right - left) * (bottom - top); + } + +private: + template + int binarySearch(int left, int right, const T& find) { + while (left <= right) { + const int mid = left + (right - left) / 2; + if (find(mid)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; + +// Using std::bind(). +class Solution2 { +public: + int minArea(vector>& image, int x, int y) { + using namespace std::placeholders; // for _1, _2, _3... + + const auto searchColumns = + [](const vector>& image, bool has_one, const int mid) { + return has_one == any_of(image.cbegin(), image.cend(), + [=](const vector& row) { return row[mid] == '1'; }); + }; + const auto searchRows = + [](const vector>& image, bool has_one, const int mid) { + return has_one == any_of(image[mid].cbegin(), image[mid].cend(), + [](const char& col) { return col == '1'; }); + }; + + function findLeft = bind(searchColumns, image, true, _1); + const int left = binarySearch(0, y - 1, findLeft); + + function findRight = bind(searchColumns, image, false, _1); + const int right = binarySearch(y + 1, image[0].size() - 1, findRight); + + function findTop = bind(searchRows, image, true, _1); + const int top = binarySearch(0, x - 1, findTop); + + function findBottom = bind(searchRows, image, false, _1); + const int bottom = binarySearch(x + 1, image.size() - 1, findBottom); + + return (right - left) * (bottom - top); + } + +private: + int binarySearch(int left, int right, function& find) { + while (left <= right) { + const int mid = left + (right - left) / 2; + if (find(mid)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; + +// Using lambda. +class Solution3 { +public: + int minArea(vector>& image, int x, int y) { + const auto searchColumns = + [](const vector>& image, bool has_one, const int mid) { + return has_one == any_of(image.cbegin(), image.cend(), + [=](const vector& row) { return row[mid] == '1'; }); + }; + const auto searchRows = + [](const vector>& image, bool has_one, const int mid) { + return has_one == any_of(image[mid].cbegin(), image[mid].cend(), + [](const char& col) { return col == '1'; }); + }; + + const int left = binarySearch(0, y - 1, searchColumns, image, true); + const int right = binarySearch(y + 1, image[0].size() - 1, searchColumns, image, false); + const int top = binarySearch(0, x - 1, searchRows, image, true); + const int bottom = binarySearch(x + 1, image.size() - 1, searchRows, image, false); + + return (right - left) * (bottom - top); + } + +private: + int binarySearch(int left, int right, + const function>&, bool, const int)>& find, + const vector>& image, + bool has_one) { + while (left <= right) { + const int mid = left + (right - left) / 2; + if (find(image, has_one, mid)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; diff --git a/C++/solve-the-equation.cpp b/C++/solve-the-equation.cpp new file mode 100644 index 000000000..cacf34c27 --- /dev/null +++ b/C++/solve-the-equation.cpp @@ -0,0 +1,56 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string solveEquation(string equation) { + auto a = 0, b = 0; + auto side = 1; + int submatches[] = { 1, 2, 3, 4 }; + auto e = regex("(=)|([-+]?)(\\d*)(x?)"); + for (regex_token_iterator it(equation.begin(), equation.end(), e, submatches), end; + it != end;) { + auto eq = (it++)->str(); + auto sign = (it++)->str(); + auto num = (it++)->str(); + auto isx = (it++)->str(); + if (!eq.empty()) { + side = -1; + } else if (!isx.empty()) { + a += side * stoi(sign + "1") * stoi(num.empty() ? "1" : num); + } else if (!num.empty()) { + b -= side * stoi(sign + num); + } + } + return a != 0 ? "x=" + to_string(b / a) : b != 0 ? "No solution" : "Infinite solutions"; + } +}; + +// Time: O(n) +// Space: O(n) +class Solution2 { +public: + string solveEquation(string equation) { + equation = regex_replace(equation, regex("(^|[+=-])x"), "$011x"); + + auto pos = equation.find('='); + auto l = coef(equation.substr(0, pos)); + auto r = coef(equation.substr(pos + 1)); + + auto a = l.first - r.first; + auto b = r.second - l.second; + + return a != 0 ? "x=" + to_string(b / a) : b != 0 ? "No solution" : "Infinite solutions"; + } + +private: + pair coef(string s) { + auto a = 0, b = 0; + auto e = regex("(^|[+-])\\d+x?"); + for (regex_token_iterator it(s.begin(), s.end(), e), end; + it != end; ++it) { + (it->str().back() == 'x' ? a : b) += stoi(*it); + } + return {a, b}; + } +}; diff --git a/C++/sort-characters-by-frequency.cpp b/C++/sort-characters-by-frequency.cpp new file mode 100644 index 000000000..c37dd4fe2 --- /dev/null +++ b/C++/sort-characters-by-frequency.cpp @@ -0,0 +1,26 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + string frequencySort(string s) { + unordered_map freq; + for (const auto& c : s) { + ++freq[c]; + } + + vector counts(s.size() + 1); + for (const auto& kvp : freq) { + counts[kvp.second].push_back(kvp.first); + } + + string result; + for (int count = counts.size() - 1; count >= 0; --count) { + for (const auto& c : counts[count]) { + result += string(count, c); + } + } + + return result; + } +}; diff --git a/C++/sort-colors.cpp b/C++/sort-colors.cpp new file mode 100644 index 000000000..9eb088944 --- /dev/null +++ b/C++/sort-colors.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +// Tri-Partition solution. +class Solution { +public: + void sortColors(vector& nums) { + const int target = 1; + for (int i = 0, j = 0, n = nums.size() - 1; j <= n;) { + if (nums[j] < target) { + swap(nums[i++], nums[j++]); + } else if (nums[j] > target) { + swap(nums[j], nums[n--]); + } else { + ++j; + } + } + } +}; diff --git a/C++/sort-list.cpp b/C++/sort-list.cpp new file mode 100644 index 000000000..11320d427 --- /dev/null +++ b/C++/sort-list.cpp @@ -0,0 +1,52 @@ +// Time: O(nlogn) +// Space: O(logn) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head || !head->next) { + return head; + } + + auto slow = head, fast = head; + while (fast->next && fast->next->next) { + slow = slow->next; + fast = fast->next->next; + } + + // Split linked list. + fast = slow; + slow = slow->next; + fast->next = nullptr; + + return mergeTwoLists(sortList(head), sortList(slow)); + } + +private: + ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode dummy{0}; + auto curr = &dummy; + + while (l1 && l2) { + if (l1->val <= l2->val) { + curr->next = l1; + l1 = l1->next; + } else { + curr->next = l2; + l2 = l2->next; + } + curr = curr->next; + } + curr->next = l1 ? l1 : l2; + + return dummy.next; + } +}; diff --git a/C++/sort-transformed-array.cpp b/C++/sort-transformed-array.cpp new file mode 100644 index 000000000..71f6e5541 --- /dev/null +++ b/C++/sort-transformed-array.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector sortTransformedArray(vector& nums, int a, int b, int c) { + const auto f = [](int x, int a, int b, int c) { + return a * x * x + b * x + c; + }; + + vector result; + if (nums.empty()) { + return result; + } + + int left = 0, right = nums.size() - 1; + int d = a > 0 ? -1 : 1; + while (left <= right) { + if (d * f(nums[left], a, b, c) < d * f(nums[right], a, b, c)) { + result.emplace_back(f(nums[left++], a, b, c)); + } else { + result.emplace_back(f(nums[right--], a, b, c)); + } + } + if (d == -1) { + reverse(result.begin(), result.end()); + } + + return result; + } +}; diff --git a/C++/sortList.cpp b/C++/sortList.cpp deleted file mode 100644 index da85f13f2..000000000 --- a/C++/sortList.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Time Complexity: O(nlogn) -// Space Complexity: O(1) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { - public: - ListNode *sortList(ListNode *head) { - if(!head || !head->next) return head; - - ListNode *slow = head; - ListNode *fast = head; - - while(fast->next && fast->next->next) { - slow = slow->next; - fast = fast->next->next; - } - - // split linked list - fast = slow; - slow = slow->next; - fast->next = nullptr; - - return mergeList(sortList(head), sortList(slow)); // merge sorted list - } - - private: - ListNode *mergeList(ListNode *list1, ListNode *list2) { - ListNode dummy(INT_MIN); - dummy.next = nullptr; - ListNode *head = &dummy; - - for(;list1 && list2; head = head->next) { - if(list1->val <= list2->val) { - head->next = list1; - list1 = list1->next; - } - else { - head->next = list2; - list2 = list2->next; - } - } - - if(list1) { - head->next = list1; - } - else if(list2) { - head->next = list2; - } - - return dummy.next; - } -}; diff --git a/C++/sortedListToBST.cpp b/C++/sortedListToBST.cpp deleted file mode 100644 index 6ea2911a0..000000000 --- a/C++/sortedListToBST.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(logn) - -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -/** - * Definition for binary tree - * struct TreeNode { - * int val; - * TreeNode *left; - * TreeNode *right; - * TreeNode(int x) : val(x), left(NULL), right(NULL) {} - * }; - */ -class Solution { - public: - TreeNode *sortedListToBST(ListNode *head) { - int len = 0; - - ListNode *p = head; - while(p) { - p = p->next; - ++len; - } - - return sortedListToBST(head, len); - } - - private: - TreeNode *sortedListToBST(ListNode *&head, int len) { - if(!len || !head) - return NULL; - TreeNode *left = sortedListToBST(head, len / 2); - TreeNode *parent = new TreeNode(head->val); - parent->left = left; - head = head->next; - parent->right = sortedListToBST(head, (len % 2 != 0)? len / 2: len / 2 - 1); - return parent; - } -}; diff --git a/C++/sparse-matrix-multiplication.cpp b/C++/sparse-matrix-multiplication.cpp new file mode 100644 index 000000000..3910db4fe --- /dev/null +++ b/C++/sparse-matrix-multiplication.cpp @@ -0,0 +1,20 @@ +// Time: O(m * n * l), A is m x n matrix, B is n x l matrix +// Space: O(m * l) + +class Solution { +public: + vector> multiply(vector>& A, vector>& B) { + const int m = A.size(), n = A[0].size(), l = B[0].size(); + vector> res(m, vector(l)); + for (int i = 0; i < m; ++i) { + for (int k = 0; k < n; ++k) { + if (A[i][k]) { + for (int j = 0; j < l; ++j) { + res[i][j] += A[i][k] * B[k][j]; + } + } + } + } + return res; + } +}; diff --git a/C++/spiral-matrix-ii.cpp b/C++/spiral-matrix-ii.cpp new file mode 100644 index 000000000..52d40d6ca --- /dev/null +++ b/C++/spiral-matrix-ii.cpp @@ -0,0 +1,81 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + /** + * @param n an integer + * @return a square matrix + */ + vector> generateMatrix(int n) { + vector> matrix(n, vector(n)); + + for (int num = 0, left = 0, right = n - 1, top = 0, bottom = n - 1; + left <= right && top <= bottom; + ++left, --right, ++top, --bottom) { + + for (int j = left; j <= right; ++j) { + matrix[top][j] = ++num; + } + for (int i = top + 1; i < bottom; ++i) { + matrix[i][right] = ++num; + } + for (int j = right; top < bottom && j >= left; --j) { + matrix[bottom][j] = ++num; + } + for (int i = bottom - 1; left < right && i >= top + 1; --i) { + matrix[i][left] = ++num; + } + } + + return matrix; + } +}; + +// Time: O(n^2) +// Space: O(1) +class Solution2 { +public: + vector > generateMatrix(int n) { + vector > matrix(n, vector(n)); + enum Action {RIGHT, DOWN, LEFT, UP}; + Action action = RIGHT; + for (int i = 0, j = 0, cnt = 0, total = n * n; cnt < total;) { + matrix[i][j] = ++cnt; + + switch (action) { + case RIGHT: + if (j + 1 < n && matrix[i][j + 1] == 0) { + ++j; + } else { + action = DOWN, ++i; + } + break; + case DOWN: + if (i + 1 < n && matrix[i + 1][j] == 0) { + ++i; + } else { + action = LEFT, --j; + } + break; + case LEFT: + if (j - 1 >= 0 && matrix[i][j - 1] == 0) { + --j; + } else { + action = UP, --i; + } + break; + case UP: + if (i - 1 >= 0 && matrix[i - 1][j] == 0) { + --i; + } else { + action = RIGHT, ++j; + } + break; + default: + break; + } + } + return matrix; + } +}; diff --git a/C++/spiral-matrix.cpp b/C++/spiral-matrix.cpp new file mode 100644 index 000000000..61d6fc9ba --- /dev/null +++ b/C++/spiral-matrix.cpp @@ -0,0 +1,89 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + vector spiralOrder(vector>& matrix) { + vector res; + if (matrix.empty()) { + return res; + } + + for (int left = 0, right = matrix[0].size() - 1, + top = 0, bottom = matrix.size() - 1; + left <= right && top <= bottom; + ++left, --right, ++top, --bottom) { + + for (int j = left; j <= right; ++j) { + res.emplace_back(matrix[top][j]); + } + for (int i = top + 1; i < bottom; ++i) { + res.emplace_back(matrix[i][right]); + } + for (int j = right; top < bottom && j >= left; --j) { + res.emplace_back(matrix[bottom][j]); + } + for (int i = bottom - 1; left < right && i > top; --i) { + res.emplace_back(matrix[i][left]); + } + } + + return res; + } +}; + +// Time: O(m * n) +// Space: O(1) +class Solution2 { +public: + vector spiralOrder(vector>& matrix) { + const int m = matrix.size(); + vector res; + if (m == 0) { + return res; + } + + const int n = matrix.front().size(); + enum Action {RIGHT, DOWN, LEFT, UP}; + Action action = RIGHT; + for (int i = 0, j = 0, begini = 0, beginj = 0, endi = m, + endj = n, cnt = 0, total = m * n; cnt < total; ++cnt) { + + res.emplace_back(matrix[i][j]); + + switch (action) { + case RIGHT: + if (j + 1 < endj) { + ++j; + } else { + action = DOWN, ++begini, ++i; + } + break; + case DOWN: + if (i + 1 < endi) { + ++i; + } else { + action = LEFT, --endj, --j; + } + break; + case LEFT: + if (j - 1 >= beginj) { + --j; + } else { + action = UP, --endi, --i; + } + break; + case UP: + if (i - 1 >= begini) { + --i; + } else { + action = RIGHT, ++beginj, ++j; + } + break; + default: + break; + } + } + return res; + } +}; diff --git a/C++/spiralOrder.cpp b/C++/spiralOrder.cpp deleted file mode 100644 index 21e2b96cd..000000000 --- a/C++/spiralOrder.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - vector spiralOrder(vector > &matrix) { - const int m = matrix.size(); - vector ans; - if(m == 0) return ans; - - const int n = matrix.front().size(); - enum Action {RIGHT, DOWN, LEFT, UP}; - Action action = RIGHT; - for(int i = 0, j = 0, begini = 0, beginj = 0, endi = m, endj = n, cnt = 0, total = m * n; cnt < total; ++cnt) { - ans.push_back(matrix[i][j]); - - switch(action) { - case RIGHT: - if(j + 1 < endj) ++j; - else action = DOWN, ++begini, ++i; - break; - case DOWN: - if(i + 1 < endi) ++i; - else action = LEFT, --endj, --j; - break; - case LEFT: - if(j - 1 >= beginj) --j; - else action = UP, --endi, --i; - break; - case UP: - if(i - 1 >= begini) --i; - else action = RIGHT, ++beginj, ++j; - break; - default: - break; - } - } - return ans; - } -}; diff --git a/C++/split-array-into-consecutive-subsequences.cpp b/C++/split-array-into-consecutive-subsequences.cpp new file mode 100644 index 000000000..67bfe6c79 --- /dev/null +++ b/C++/split-array-into-consecutive-subsequences.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isPossible(vector& nums) { + auto pre = numeric_limits::min(), cur = 0; + auto cnt1 = 0, cnt2 = 0, cnt3 = 0; // count of each length ending at cur + for (int i = 0; i < nums.size(); pre = cur) { + auto cnt = 0; + for (cur = nums[i]; i < nums.size() && cur == nums[i]; ++cnt, ++i); + + if (cur != pre + 1) { + if (cnt1 != 0 || cnt2 != 0) { + return false; + } + tie(cnt1, cnt2, cnt3) = make_tuple(cnt, 0, 0); + } else { + if (cnt < cnt1 + cnt2) { + return false; + } + tie(cnt1, cnt2, cnt3) = make_tuple(max(0, cnt - (cnt1 + cnt2 + cnt3)), + cnt1, + cnt2 + min(cnt3, cnt - (cnt1 + cnt2))); + } + } + return cnt1 == 0 && cnt2 == 0; + } +}; diff --git a/C++/split-array-largest-sum.cpp b/C++/split-array-largest-sum.cpp new file mode 100644 index 000000000..b39e527a5 --- /dev/null +++ b/C++/split-array-largest-sum.cpp @@ -0,0 +1,36 @@ +// Time: O(nlogs), s is the sum of nums +// Space: O(1) + +class Solution { +public: + int splitArray(vector& nums, int m) { + int left = 0, right = 0; + for (const auto& num : nums) { + left = max(left, num); + right += num; + } + + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (canSplit(nums, m, mid)) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } + +private: + bool canSplit(vector& nums, int m, int sum) { + int cnt = 1, curr_sum = 0; + for (const auto& num : nums) { + curr_sum += num; + if (curr_sum > sum) { + curr_sum = num; + ++cnt; + } + } + return cnt <= m; + } +}; diff --git a/C++/split-array-with-equal-sum.cpp b/C++/split-array-with-equal-sum.cpp new file mode 100644 index 000000000..5f4c336de --- /dev/null +++ b/C++/split-array-with-equal-sum.cpp @@ -0,0 +1,32 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + bool splitArray(vector& nums) { + if (nums.size() < 7) { + return false; + } + + vector sum(nums.size()); + sum[0] = nums[0]; + for (int i = 1; i < nums.size(); ++i) { + sum[i] = sum[i - 1] + nums[i]; + } + for (int j = 3; j < nums.size() - 3; ++j) { + unordered_set lookup; + for (int i = 1; i < j - 1; ++i) { + if (sum[i - 1] == sum[j - 1] - sum[i]) { + lookup.emplace(sum[i - 1]); + } + } + for (int k = j + 2; k < nums.size() - 1; ++k) { + if (sum[nums.size() - 1] - sum[k] == sum[k - 1] - sum[j] && + lookup.count(sum[k - 1] - sum[j])) { + return true; + } + } + } + return false; + } +}; diff --git a/C++/split-concatenated-strings.cpp b/C++/split-concatenated-strings.cpp new file mode 100644 index 000000000..0c2578f43 --- /dev/null +++ b/C++/split-concatenated-strings.cpp @@ -0,0 +1,31 @@ +// Time: O(n^2) +// Space: O(n) + +class Solution { +public: + string splitLoopedString(vector& strs) { + string s; + for (const auto& str : strs) { + auto rev{str}; + reverse(rev.begin(), rev.end()); + s += max(str, rev); + } + string result{"a"}; + for (auto i = 0, st = 0; i < strs.size(); st += strs[i++].size()) { + auto rev{strs[i]}, body{s.substr(st + strs[i].length())}; + body += s.substr(0, st); + reverse(rev.begin(), rev.end()); + for (const auto& p : {strs[i], rev}) { + for (auto j = 0; j < strs[i].size(); ++j) { + if (p[j] >= result[0]) { + string tmp{p.substr(j)}; + tmp += body; + tmp += p.substr(0, j); + result = max(result, tmp); + } + } + } + } + return result; + } +}; diff --git a/C++/split-linked-list-in-parts.cpp b/C++/split-linked-list-in-parts.cpp new file mode 100644 index 000000000..2792a408a --- /dev/null +++ b/C++/split-linked-list-in-parts.cpp @@ -0,0 +1,41 @@ +// Time: O(n + k) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + vector splitListToParts(ListNode* root, int k) { + auto n = 0; + auto curr = root; + while (curr) { + curr = curr->next; + n += 1; + } + auto width = n / k; + auto remainder = n % k; + + vector result; + curr = root; + for (int i = 0; i < k; ++i) { + auto head = curr; + for (int j = 0; curr && + j < width - 1 + static_cast(i < remainder); ++j) { + curr = curr->next; + } + if (curr) { + auto tail = curr; + curr = curr->next; + tail->next = nullptr; + } + result.emplace_back(head); + } + return result; + } +}; diff --git a/C++/sqrt.cpp b/C++/sqrt.cpp deleted file mode 100644 index df80bc622..000000000 --- a/C++/sqrt.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int sqrt(int x) { - int left = 1; - int right = x; - int last_mid = 0; - - while(left <= right) { - int mid = left + (right - left) / 2; - - if(x / mid > mid) { - left = mid + 1; - last_mid = mid; - } - else if (x / mid < mid) { - right = mid - 1; - } - else - return mid; - } - - return last_mid; - } -}; diff --git a/C++/sqrtx.cpp b/C++/sqrtx.cpp new file mode 100644 index 000000000..2d4092aca --- /dev/null +++ b/C++/sqrtx.cpp @@ -0,0 +1,23 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + int mySqrt(int x) { + if (x < 2) { + return x; + } + + int left = 1, right = x / 2; + while (left <= right) { + const auto mid = left + (right - left) / 2; + if (mid > x / mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + return left - 1; + } +}; diff --git a/C++/squirrel-simulation.cpp b/C++/squirrel-simulation.cpp new file mode 100644 index 000000000..adf3aa525 --- /dev/null +++ b/C++/squirrel-simulation.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int minDistance(int height, int width, vector& tree, vector& squirrel, vector>& nuts) { + int result = 0; + int d = numeric_limits::max(); + for (const auto& nut : nuts) { + result += (distance(nut, tree) * 2); + d = min(d, distance(nut, squirrel) - distance(nut, tree)); + } + return result + d; + } + +private: + int distance(const vector& a, const vector& b) { + return abs(a[0] - b[0]) + abs(a[1] - b[1]); + } +}; diff --git a/C++/stickers-to-spell-word.cpp b/C++/stickers-to-spell-word.cpp new file mode 100644 index 000000000..90a42e399 --- /dev/null +++ b/C++/stickers-to-spell-word.cpp @@ -0,0 +1,49 @@ +// Time: O(T * S^T) +// Space: O(T * S^T) + +class Solution { +public: + int minStickers(vector& stickers, string target) { + vector> sticker_counts(stickers.size(), vector(26)); + unordered_map dp; + for (int i = 0; i < stickers.size(); ++i) { + for (const auto& c : stickers[i]) { + ++sticker_counts[i][c - 'a']; + } + } + dp[""] = 0; + return minStickersHelper(sticker_counts, target, &dp); + } + +private: + int minStickersHelper(const vector>& sticker_counts, const string& target, + unordered_map *dp) { + if (dp->count(target)) { + return (*dp)[target]; + } + int result = numeric_limits::max(); + vector target_count(26); + for (const auto& c : target) { + ++target_count[c - 'a']; + } + for (const auto& sticker_count : sticker_counts) { + if (sticker_count[target[0] - 'a'] == 0) { + continue; + } + string new_target; + for (int i = 0; i < target_count.size(); ++i) { + if (target_count[i] - sticker_count[i] > 0) { + new_target += string(target_count[i] - sticker_count[i], 'a' + i); + } + } + if (new_target.length() != target.length()) { + int num = minStickersHelper(sticker_counts, new_target, dp); + if (num != -1) { + result = min(result, 1 + num); + } + } + } + (*dp)[target] = (result == numeric_limits::max()) ? -1 : result; + return (*dp)[target]; + } +}; \ No newline at end of file diff --git a/C++/strStr.cpp b/C++/strStr.cpp deleted file mode 100644 index 6320e9f73..000000000 --- a/C++/strStr.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Time Complexity: O(m + n) -// Space Complexity: O(n) - -class Solution { - public: - char *strStr(char *haystack, char *needle) { - string target(haystack); - string pattern(needle); - - if(target.size() < pattern.size()) - return nullptr; - - if(pattern.size() == 0) - return haystack; - - int i = kmp(target, pattern); - - return (i != -1)? haystack + i : nullptr; - } - private: - int kmp(const string &target, const string &pattern) { - const auto m = target.size(); - const auto n = pattern.size(); - - vector failure(n, -1); - for(int i = 1, j = -1; i < n; ++i) { - while(j >= 0 && pattern[j + 1] != pattern[i]) - j = failure[j]; - if(pattern[j + 1] == pattern[i]) - ++j; - failure[i] = j; - } - - for(int i = 0, j = -1; i < m; ++i) { - while(j >= 0 && pattern[j + 1] != target[i]) - j = failure[j]; - if(pattern[j + 1] == target[i]) - ++j; - if(j == n - 1) { - return i - j; - } - } - - return -1; - } -}; diff --git a/C++/strange-printer.cpp b/C++/strange-printer.cpp new file mode 100644 index 000000000..89997ba20 --- /dev/null +++ b/C++/strange-printer.cpp @@ -0,0 +1,27 @@ +// Time: O(n^3) +// Space: O(n^2) + +class Solution { +public: + int strangePrinter(string s) { + vector> lookup(s.length(), vector(s.length())); + return dp(s, 0, s.length() - 1, &lookup); + } + +private: + int dp(const string& s, int i, int j, vector> *lookup) { + if (i > j) { + return 0; + } + if (!(*lookup)[i][j]) { + (*lookup)[i][j] = dp(s, i, j - 1, lookup) + 1; + for (int k = i; k < j; ++k) { + if (s[k] == s[j]) { + (*lookup)[i][j] = min((*lookup)[i][j], + dp(s, i, k, lookup) + dp(s, k + 1, j - 1, lookup)); + } + } + } + return (*lookup)[i][j]; + } +}; diff --git a/C++/string-compression.cpp b/C++/string-compression.cpp new file mode 100644 index 000000000..8021ebce8 --- /dev/null +++ b/C++/string-compression.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int compress(vector& chars) { + int write = 0, anchor = 0; + for (int read = 0; read < chars.size(); ++read) { + if (read + 1 == chars.size() || chars[read + 1] != chars[read]) { + chars[write++] = chars[read]; + if (read - anchor > 0) { + auto n = read - anchor + 1, cnt = 0; + while (n > 0) { + chars[write++] = n % 10 + '0'; + n /= 10; + ++cnt; + } + reverse(chars.begin() + write - cnt, chars.begin() + write); + } + anchor = read + 1; + } + } + return write; + } +}; diff --git a/C++/string-to-integer-atoi.cpp b/C++/string-to-integer-atoi.cpp new file mode 100644 index 000000000..c8de958d5 --- /dev/null +++ b/C++/string-to-integer-atoi.cpp @@ -0,0 +1,40 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int myAtoi(string str) { + if (str.empty()) { + return 0; + } + + int ans = 0; + int sign = 1; + int i = 0; + + // Skip whitespace. + while (str[i] == ' ' || str[i] == '\t') { + ++i; + } + + // Parse sign. + if (str[i] == '+') { + ++i; + } else if (str[i] == '-') { + sign = -1; + ++i; + } + + // Compute integer. + for (; i < str.length() && isdigit(str[i]); ++i) { + if (ans > (numeric_limits::max() - (str[i] - '0')) / 10) { + return sign > 0 ? numeric_limits::max() : numeric_limits::min(); + } + ans *= 10; + ans += str[i] - '0'; + } + + ans *= sign; + return ans; + } +}; diff --git a/C++/strobogrammatic-number-ii.cpp b/C++/strobogrammatic-number-ii.cpp new file mode 100644 index 000000000..4c5b610e0 --- /dev/null +++ b/C++/strobogrammatic-number-ii.cpp @@ -0,0 +1,32 @@ +// Time: O(n^2 * 5^(n/2)) +// Space: O(n) + +class Solution { +public: + vector findStrobogrammatic(int n) { + return findStrobogrammaticRecu(n, n); + } + + vector findStrobogrammaticRecu(const int n, int k) { + if (k == 0) { + return {""}; + } else if (k == 1) { + return {"0", "1", "8"}; + } + + vector result; + for (const auto& num : findStrobogrammaticRecu(n, k - 2)) { + for (const auto& kvp : lookup) { + if (n != k || kvp.first != "0") { + result.emplace_back(kvp.first + num + kvp.second); + } + } + } + return result; + } + +private: + const unordered_map lookup{{"0", "0"}, {"1", "1"}, + {"6", "9"}, {"8", "8"}, + {"9", "6"}}; +}; diff --git a/C++/strobogrammatic-number-iii.cpp b/C++/strobogrammatic-number-iii.cpp new file mode 100644 index 000000000..0510a5c00 --- /dev/null +++ b/C++/strobogrammatic-number-iii.cpp @@ -0,0 +1,96 @@ +// Time: O(5^(n/2)) +// Space: O(n) + +class Solution { +public: + int strobogrammaticInRange(string low, string high) { + int count = countStrobogrammaticUntil(high, false) - + countStrobogrammaticUntil(low, false) + + isStrobogrammatic(low); + return count >= 0 ? count : 0; + } + + int countStrobogrammaticUntil(string num, bool can_start_with_0) { + if (can_start_with_0 && cache.find(num) != cache.end()) { + return cache[num]; + } + + int count = 0; + if (num.length() == 1) { + for (const auto& c : {'0', '1', '8'}) { + if (num.front() >= c) { + ++count; + } + } + cache[num] = count; + return count; + } + + for (const auto& kvp : lookup) { + if (can_start_with_0 || kvp.first != '0') { + if (num.front() > kvp.first) { + if (num.length() == 2) { // num is like "21" + ++count; + } else { // num is like "201" + count += countStrobogrammaticUntil(string(num.length() - 2, '9'), true); + } + } else if (num.front() == kvp.first) { + if (num.length() == 2) { // num is like 12". + count += num.back() >= kvp.second; + } else { + if (num.back() >= kvp.second) { // num is like "102". + count += countStrobogrammaticUntil(getMid(num), true); + } else if (getMid(num) != string(num.length() - 2, '0')) { // num is like "110". + count += countStrobogrammaticUntil(getMid(num), true) - + isStrobogrammatic(getMid(num)); + } + } + } + } + } + + if (!can_start_with_0) { // Sum up each length. + for (int i = num.length() - 1; i > 0; --i) { + count += countStrobogrammaticByLength(i); + } + } else { + cache[num] = count; + } + + return count; + } + + string getMid(const string& num) { + return num.substr(1, num.length() - 2); + } + + int countStrobogrammaticByLength(int n) { + switch (n) { + case 1: + return 3; // "0", "1", "8" + case 2: + return 4; // "11", "69", "88", "96" + case 3: + return 4 * 3; // "101", "111", "181", ... + default: + return 5 * countStrobogrammaticByLength(n - 2); + } + } + + bool isStrobogrammatic(const string& num) { + const int n = num.size(); + for (int i = 0; i <= n - 1 - i; ++i) { + const auto it = lookup.find(num[n - 1 - i]); + if (it == lookup.end() || num[i] != it->second) { + return false; + } + } + return true; + } + +private: + const unordered_map lookup{{'0', '0'}, {'1', '1'}, + {'6', '9'}, {'8', '8'}, + {'9', '6'}}; + unordered_map cache; +}; diff --git a/C++/strobogrammatic-number.cpp b/C++/strobogrammatic-number.cpp new file mode 100644 index 000000000..6d62376b8 --- /dev/null +++ b/C++/strobogrammatic-number.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isStrobogrammatic(string num) { + const int n = num.size(); + for (int i = 0; i <= n - 1 - i; ++i) { + const auto it = lookup.find(num[n - 1 - i]); + if (it == lookup.end() || num[i] != it->second) { + return false; + } + } + return true; + } + +private: + const unordered_map lookup{{'0', '0'}, {'1', '1'}, + {'6', '9'}, {'8', '8'}, + {'9', '6'}}; +}; diff --git a/C++/strong-password-checker.cpp b/C++/strong-password-checker.cpp new file mode 100644 index 000000000..fa8cf5854 --- /dev/null +++ b/C++/strong-password-checker.cpp @@ -0,0 +1,48 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int strongPasswordChecker(string s) { + int missing_type_cnt = 3; + missing_type_cnt -= static_cast(any_of(s.begin(), s.end(), [](char c){ return isdigit(c); })); + missing_type_cnt -= static_cast(any_of(s.begin(), s.end(), [](char c){ return isupper(c); })); + missing_type_cnt -= static_cast(any_of(s.begin(), s.end(), [](char c){ return islower(c); })); + + int total_change_cnt = 0; + int one_change_cnt = 0, two_change_cnt = 0, three_change_cnt = 0; + for (int i = 2; i < s.length();) { + if (s[i] == s[i - 1] && s[i - 1] == s[i - 2]) { + int length = 2; + while (i < s.length() && s[i] == s[i - 1]) { + ++length; + ++i; + } + total_change_cnt += length / 3; + if (length % 3 == 0) { + ++one_change_cnt; + } else if (length % 3 == 1) { + ++two_change_cnt; + } else { + ++three_change_cnt; + } + } else { + ++i; + } + } + + if (s.length() < 6) { + return max(missing_type_cnt, 6 - static_cast(s.length())); + } else if (s.length() <= 20) { + return max(missing_type_cnt, total_change_cnt); + } + + int delete_cnt = s.length() - 20; + + total_change_cnt -= min(delete_cnt, one_change_cnt) / 1; + total_change_cnt -= min(max(delete_cnt - one_change_cnt, 0), two_change_cnt * 2) / 2; + total_change_cnt -= min(max(delete_cnt - one_change_cnt - 2 * two_change_cnt, 0), three_change_cnt * 3) / 3; + + return delete_cnt + max(missing_type_cnt, total_change_cnt); + } +}; diff --git a/C++/student-attendance-record-i.cpp b/C++/student-attendance-record-i.cpp new file mode 100644 index 000000000..bf7eb9aa2 --- /dev/null +++ b/C++/student-attendance-record-i.cpp @@ -0,0 +1,20 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool checkRecord(string s) { + int count_A = 0; + for (int i = 0; i < s.length(); ++i) { + if (s[i] == 'A') { + if (++count_A == 2) { + return false; + } + } + if (i + 2 < s.length() && s[i] == 'L' && s[i + 1] == 'L' && s[i + 2] == 'L') { + return false; + } + } + return true; + } +}; diff --git a/C++/student-attendance-record-ii.cpp b/C++/student-attendance-record-ii.cpp new file mode 100644 index 000000000..819c954da --- /dev/null +++ b/C++/student-attendance-record-ii.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int checkRecord(int n) { + static const long long M = 1000000007; + long long a0l0 = 1, a0l1 = 0, a0l2 = 0, a1l0 = 0, a1l1 = 0, a1l2 = 0; + for (int i = 0; i <= n; ++i) { + auto new_a0l0 = (a0l0 + a0l1 + a0l2) % M; + a0l2 = a0l1; + a0l1 = a0l0; + a0l0 = new_a0l0; + auto new_a1l0 = (a0l0 + a1l0 + a1l1 + a1l2) % M; + a1l2 = a1l1; + a1l1 = a1l0; + a1l0 = new_a1l0; + } + return static_cast(a1l0); + } +}; diff --git a/C++/subarray-product-less-than-k.cpp b/C++/subarray-product-less-than-k.cpp new file mode 100644 index 000000000..6312bc526 --- /dev/null +++ b/C++/subarray-product-less-than-k.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +// Sliding window solution. +class Solution { +public: + int numSubarrayProductLessThanK(vector& nums, int k) { + if (k <= 1) { + return 0; + } + int result = 0, start = 0, prod = 1; + for (int i = 0; i < nums.size(); ++i) { + prod *= nums[i]; + while (prod >= k) { + prod /= nums[start]; + ++start; + } + result += i - start + 1; + } + return result; + } +}; diff --git a/C++/subarray-sum-equals-k.cpp b/C++/subarray-sum-equals-k.cpp new file mode 100644 index 000000000..3b0e19401 --- /dev/null +++ b/C++/subarray-sum-equals-k.cpp @@ -0,0 +1,18 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + int subarraySum(vector& nums, int k) { + auto result{0}; + auto accumulated_sum{0}; + unordered_map lookup; + ++lookup[0]; + for (const auto& num : nums) { + accumulated_sum += num; + result += lookup[accumulated_sum - k]; + ++lookup[accumulated_sum]; + } + return result; + } +}; diff --git a/C++/subsets-ii.cpp b/C++/subsets-ii.cpp new file mode 100644 index 000000000..2a6b1cd3b --- /dev/null +++ b/C++/subsets-ii.cpp @@ -0,0 +1,23 @@ +// Time: O(n * 2^n) +// Space: O(1) + +class Solution { +public: + vector> subsetsWithDup(vector &nums) { + vector> result(1); + sort(nums.begin(), nums.end()); + size_t previous_size = 0; + for (size_t i = 0; i < nums.size(); ++i) { + const size_t size = result.size(); + for (size_t j = 0; j < size; ++j) { + // Only union non-duplicate element or new union set. + if (i == 0 || nums[i] != nums[i - 1] || j >= previous_size) { + result.emplace_back(result[j]); + result.back().emplace_back(nums[i]); + } + } + previous_size = size; + } + return result; + } +}; diff --git a/C++/subsets.cpp b/C++/subsets.cpp index 9b99a3809..9c0d9d0c3 100644 --- a/C++/subsets.cpp +++ b/C++/subsets.cpp @@ -1,25 +1,36 @@ -// Time Complexity: O(2^n) -// Space Complexity: O(1) +// Time: O(n * 2^n) +// Space: O(1) class Solution { - public: - vector > subsets(vector &S) { - const int size = S.size(); - const int setSize = 1 << size; - vector > ans; - vector v; - - sort(S.begin(), S.end()); - - for(int i = 0; i < setSize; ++i) { - for(int j = 0; j < size; j++) { - if(i & (1 << j)) - v.push_back(S[j]); - } - ans.push_back(v); - v.clear(); +public: + vector > subsets(vector &nums) { + vector> result(1); + sort(nums.begin(), nums.end()); + for (size_t i = 0; i < nums.size(); ++i) { + const size_t size = result.size(); + for (size_t j = 0; j < size; ++j) { + result.emplace_back(result[j]); + result.back().emplace_back(nums[i]); } + } + return result; + } +}; - return ans; +// Time: O(n * 2^n) +// Space: O(1) +class Solution2 { +public: + vector > subsets(vector &nums) { + vector> result(1); + sort(nums.begin(), nums.end()); + for (size_t i = 0; i < nums.size(); ++i) { + const size_t size = result.size(); + for (size_t j = 0; j < size; ++j) { + result.emplace_back(result[j]); + result.back().emplace_back(nums[i]); + } } + return result; + } }; diff --git a/C++/subsetsWithDup.cpp b/C++/subsetsWithDup.cpp deleted file mode 100644 index 36907d1a3..000000000 --- a/C++/subsetsWithDup.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Time Complexity: O(2^n) -// Space Complexity: O(1) - -class Solution { - public: - vector > subsetsWithDup(vector &S) { - sort(S.begin(), S.end()); - vector > result(1); - size_t previous_size = 0; - for (size_t i = 0; i < S.size(); ++i) { - const size_t size = result.size(); - for (size_t j = 0; j < size; ++j) { - // only union non-duplicate element or new union set - if (i == 0 || S[i] != S[i-1] || j >= previous_size) { - result.push_back(result[j]); - result.back().push_back(S[i]); - } - } - previous_size = size; - } - return result; - } -}; diff --git a/C++/substring-with-concatenation-of-all-words.cpp b/C++/substring-with-concatenation-of-all-words.cpp new file mode 100644 index 000000000..eff6743b7 --- /dev/null +++ b/C++/substring-with-concatenation-of-all-words.cpp @@ -0,0 +1,96 @@ +// Time: O((m + n) * k), m is the length of the string, +// n is the size of the dictionary, +// k is the length of each word +// Space: O(n * k) + +// Sliding window solution. +class Solution { +public: + vector findSubstring(string s, vector& words) { + vector result; + const int m = s.length(); + const int n = words.size(); + const int k = words.front().length(); + if (m < n * k) { + return result; + } + + unordered_map lookup; + for (const auto& word : words) { + ++lookup[word]; // Space: O(n * k) + } + for (int i = 0; i < k; ++i) { // Time: O(k) + int left = i, count = 0; + unordered_map tmp; + for (int j = i; j <= m - k; j += k) { // Time: O(m / k) + const auto& str = s.substr(j, k); // Time: O(k) + if (lookup.count(str)) { + ++tmp[str]; + if (tmp[str] <= lookup[str]) { + ++count; + } else { + while (tmp[str] > lookup[str]) { + const auto& str1 = s.substr(left, k); + --tmp[str1]; + if (tmp[str1] < lookup[str1]) { + --count; + } + left += k; + } + } + if (count == n) { + result.emplace_back(left); + --tmp[s.substr(left, k)]; + --count; + left += k; + } + } else { + tmp.clear(); + count = 0; + left = j + k; + } + } + } + return result; + } +}; + + +// Time: O((m - n * k) * n * k) ~ O(m * n * k), m is the length of the string, +// n is the size of the dictionary, +// k is the length of each word +// Space: O(n * k) +class Solution2 { +public: + vector findSubstring(string s, vector& words) { + const auto word_length = words.front().length(); + const auto cat_length = word_length * words.size(); + vector result; + + if (s.length() < cat_length) { + return result; + } + + unordered_map wordCount; + for (const auto & word : words) { + ++wordCount[word]; + } + + for (auto it = s.begin(); it != prev(s.end(), cat_length - 1); ++it) { + unordered_map unused(wordCount); + for (auto jt = it; jt != next(it, cat_length); jt += word_length) { + auto pos = unused.find(string(jt, next(jt, word_length))); + if (pos == unused.end()) { + break; + } + if (--pos->second == 0) { + unused.erase(pos); + } + } + if (unused.empty()) { + result.emplace_back(distance(s.begin(), it)); + } + } + return result; + } +}; diff --git a/C++/subtree-of-another-tree.cpp b/C++/subtree-of-another-tree.cpp new file mode 100644 index 000000000..c018489fd --- /dev/null +++ b/C++/subtree-of-another-tree.cpp @@ -0,0 +1,37 @@ +// Time: O(m * n), m is the number of nodes of s, n is the number of nodes of t +// Space: O(h), h is the height of s + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool isSubtree(TreeNode* s, TreeNode* t) { + return preOrderTraverse(s, t); + } + +private: + bool preOrderTraverse(TreeNode *s, TreeNode *t) { + return s && (isSame(s, t) || + preOrderTraverse(s->left, t) || + preOrderTraverse(s->right, t)); + } + + bool isSame(TreeNode *x,TreeNode *y) { + if (!x && !y) { + return true; + } + if (!x || !y) { + return false; + } + return x->val == y->val && + isSame(x->left, y->left) && + isSame(x->right, y->right); + } +}; diff --git a/C++/sum-of-left-leaves.cpp b/C++/sum-of-left-leaves.cpp new file mode 100644 index 000000000..21f4ac16a --- /dev/null +++ b/C++/sum-of-left-leaves.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int sumOfLeftLeaves(TreeNode* root) { + return sumOfLeftLeavesHelper(root, false); + } + +private: + int sumOfLeftLeavesHelper(TreeNode* root, bool is_left) { + if (!root) { + return 0; + } + if (!root->left && !root->right) { + return is_left ? root->val : 0; + } + return sumOfLeftLeavesHelper(root->left, true) + + sumOfLeftLeavesHelper(root->right, false); + } +}; diff --git a/C++/sum-of-square-numbers.cpp b/C++/sum-of-square-numbers.cpp new file mode 100644 index 000000000..bf24612ce --- /dev/null +++ b/C++/sum-of-square-numbers.cpp @@ -0,0 +1,16 @@ +// Time: O(sqrt(c) * logc) +// Space: O(1) + +class Solution { +public: + bool judgeSquareSum(int c) { + for (long long a = 0; a * a <= c; ++a) { + auto b = static_cast(sqrt(c - a * a)); + if (a * a + b * b == c) { + return true; + } + } + return false; + } +}; + diff --git a/C++/sum-of-two-integers.cpp b/C++/sum-of-two-integers.cpp new file mode 100644 index 000000000..50c66d19f --- /dev/null +++ b/C++/sum-of-two-integers.cpp @@ -0,0 +1,14 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + int getSum(int a, int b) { + while (b) { + int carry = a & b; + a ^= b; + b = carry << 1; + } + return a; + } +}; diff --git a/C++/summary-ranges.cpp b/C++/summary-ranges.cpp new file mode 100644 index 000000000..b1a012967 --- /dev/null +++ b/C++/summary-ranges.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector summaryRanges(vector& nums) { + vector ranges; + if (nums.empty()) { + return ranges; + } + + int start = nums[0], end = nums[0]; + for (int i = 1; i <= nums.size(); ++i) { + if (i < nums.size() && nums[i] == end + 1) { + end = nums[i]; + } else { + auto&& range = to_string(start); + if (start != end) { + range.append("->" + to_string(end)); + } + ranges.emplace_back(range); + if (i < nums.size()) { + start = end = nums[i]; + } + } + } + + return ranges; + } +}; diff --git a/C++/super-pow.cpp b/C++/super-pow.cpp new file mode 100644 index 000000000..fe3393d87 --- /dev/null +++ b/C++/super-pow.cpp @@ -0,0 +1,27 @@ +// Time: O(n), n is the size of b. +// Space: O(1) + +class Solution { +public: + int superPow(int a, vector& b) { + int result = 1; + for (const auto& digit : b) { + result = myPow(result, 10, 1337) * myPow(a, digit, 1337) % 1337; + } + return result; + } + +private: + int myPow(int a, int n, int b) { + int result = 1; + int x = a % b; + while (n) { + if (n & 1) { + result = result * x % b; + } + n >>= 1; + x = x * x % b; + } + return result % b; + } +}; diff --git a/C++/super-ugly-number.cpp b/C++/super-ugly-number.cpp new file mode 100644 index 000000000..3e786e2b0 --- /dev/null +++ b/C++/super-ugly-number.cpp @@ -0,0 +1,141 @@ +// Time: O(n * logk) ~ O(n * k) +// Space: O(n + k) + +// Heap solution. (308ms) +class Solution { +public: + int nthSuperUglyNumber(int n, vector& primes) { + priority_queue, vector>, greater>> heap; + vector uglies(n), idx(primes.size()), ugly_by_last_prime(n); + uglies[0] = 1; + + for (int i = 0; i < primes.size(); ++i) { + heap.emplace(primes[i], i); + } + for (int i = 1; i < n; ++i) { + int k; + tie(uglies[i], k) = heap.top(); + heap.pop(); + ugly_by_last_prime[i] = k; + while (ugly_by_last_prime[++idx[k]] > k); // worst time: O(k) + heap.emplace(uglies[idx[k]] * primes[k], k); + } + return uglies[n - 1]; + } +}; + +// Time: O(n * k) +// Space: O(n + k) +// DP solution. (596ms) +class Solution2 { +public: + int nthSuperUglyNumber(int n, vector& primes) { + vector uglies(n), ugly_by_prime(primes), idx(primes.size()); + uglies[0] = 1; + + for (int i = 1; i < n; ++i) { + int min_val = *min_element(ugly_by_prime.begin(), ugly_by_prime.end()); + uglies[i] = min_val; + for (int k = 0; k < primes.size(); ++k) { + if (min_val == ugly_by_prime[k]) { + ugly_by_prime[k] = primes[k] * uglies[++idx[k]]; + } + } + } + + return uglies[n - 1]; + } +}; + +// Time: O(n * logk) ~ O(n * klogk) +// Space: O(k^2) +// Heap solution. (612ms) +class Solution3 { +public: + int nthSuperUglyNumber(int n, vector& primes) { + long long ugly_number = 0; + priority_queue, greater> heap; + + heap.emplace(1); + for (const auto& p: primes) { + heap.emplace(p); + } + for (int i = 0; i < n; ++i) { + ugly_number = heap.top(); + heap.pop(); + int j = 0; + for (; j < primes.size(); ++j) { + if (ugly_number % primes[j] == 0) { + for (int k = 0; k <= j; ++k) { + // worst time: O(klogk) + // worst space: O(k^2) + heap.emplace(ugly_number * primes[k]); + } + break; + } + } + } + + return ugly_number; + } +}; + +// Time: O(n * k) +// Space: O(n + k) +// Hash solution. (804ms) +class Solution4 { +public: + int nthSuperUglyNumber(int n, vector& primes) { + priority_queue, vector>, greater>> heap; + unordered_set ugly_set{1}; + vector uglies(n), idx(primes.size()); + uglies[0] = 1; + + for (int k = 0; k < primes.size(); ++k) { + heap.emplace(primes[k], k); + ugly_set.emplace(primes[k]); + } + + for (int i = 1; i < n; ++i) { + int k; + tie(uglies[i], k) = heap.top(); + heap.pop(); + while (ugly_set.count(primes[k] * uglies[idx[k]])) { + ++idx[k]; + } + heap.emplace(primes[k] * uglies[idx[k]], k); + ugly_set.emplace(primes[k] * uglies[idx[k]]); + } + + return uglies[n - 1]; + } +}; + +// Time: O(n * logk) ~ O(n * klogk) +// Space: O(n + k) +// Heap solution. (1184ms) +class Solution5 { +public: + int nthSuperUglyNumber(int n, vector& primes) { + priority_queue, vector>, greater>> heap; + vector uglies(n), idx(primes.size()); + uglies[0] = 1; + + for (int k = 0; k < primes.size(); ++k) { + heap.emplace(primes[k], k); + } + + for (int i = 1; i < n; ++i) { + int k; + tie(uglies[i], k) = heap.top(); + + while (heap.top().first == uglies[i]) { // worst time: O(klogk) + tie(uglies[i], k) = heap.top(); + heap.pop(); + heap.emplace(primes[k] * uglies[++idx[k]], k); + } + } + + return uglies[n - 1]; + } +}; diff --git a/C++/super-washing-machines.cpp b/C++/super-washing-machines.cpp new file mode 100644 index 000000000..e2f0ff82e --- /dev/null +++ b/C++/super-washing-machines.cpp @@ -0,0 +1,19 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findMinMoves(vector& machines) { + int sum = accumulate(machines.begin(), machines.end(), 0); + if (sum % machines.size() != 0) { + return -1; + } + + int result = 0, target = sum / machines.size(), curr = 0; + for (const auto& n : machines) { + curr += n - target; + result = max(result, max(n - target, abs(curr))); + } + return result; + } +}; diff --git a/C++/surrounded-regions.cpp b/C++/surrounded-regions.cpp new file mode 100644 index 000000000..6ac13171c --- /dev/null +++ b/C++/surrounded-regions.cpp @@ -0,0 +1,51 @@ +// Time: O(m * n) +// Space: O(m + n) + +class Solution { +public: + void solve(vector>& board) { + if (board.empty()) { + return; + } + + queue> q; + for (int i = 0; i < board.size(); ++i) { + q.emplace(i, 0); + q.emplace(i, board[0].size() - 1); + } + for (int j = 0; j < board[0].size(); ++j) { + q.emplace(0, j); + q.emplace(board.size() - 1, j); + } + + while (!q.empty()) { + int i, j; + tie(i, j) = q.front(); + q.pop(); + if (board[i][j] == 'O' || board[i][j] == 'V') { + board[i][j] = 'V'; + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + for (const auto& d : directions) { + const int x = i + d.first, y = j + d.second; + if (0 <= x && x < board.size() && + 0 <= y && y < board[0].size() && + board[x][y] == 'O') { + board[x][y] = 'V'; + q.emplace(x, y); + } + } + } + } + + for (int i = 0; i < board.size(); ++i) { + for (int j = 0; j < board[0].size(); ++j) { + if (board[i][j] != 'V') { + board[i][j] = 'X'; + } else { + board[i][j] = 'O'; + } + } + } + } +}; diff --git a/C++/swap-nodes-in-pairs.cpp b/C++/swap-nodes-in-pairs.cpp new file mode 100644 index 000000000..d9ae7ae75 --- /dev/null +++ b/C++/swap-nodes-in-pairs.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + ListNode dummy{0}; + dummy.next = head; + auto curr = &dummy; + while (curr->next && curr->next->next) { + auto next_one = curr->next; + auto next_two = next_one->next; + auto next_three = next_two->next; + curr->next = next_two; + next_two->next = next_one; + next_one->next = next_three; + curr = next_one; + } + return dummy.next; + } +}; diff --git a/C++/symmetric-tree.cpp b/C++/symmetric-tree.cpp new file mode 100644 index 000000000..e3808f89d --- /dev/null +++ b/C++/symmetric-tree.cpp @@ -0,0 +1,70 @@ +// Time: O(n) +// Space: O(h), h is the height of the binary tree. + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +// Iterative solution. +class Solution { +public: + bool isSymmetric(TreeNode* root) { + if (!root) { + return true; + } + // isSymmetricHelper(root->left, root->right) + stack nodes; + nodes.emplace(root->left); + nodes.emplace(root->right); + + while (!nodes.empty()) { + auto right = nodes.top(); + nodes.pop(); + auto left = nodes.top(); + nodes.pop(); + if (!left && !right) { + continue; + } + if (!left || !right || left->val != right->val) { + return false; + } + // isSymmetricHelper(left->right, right->left) + nodes.emplace(left->right); + nodes.emplace(right->left); + + // isSymmetricHelper(left->left, right->right) + nodes.emplace(left->left); + nodes.emplace(right->right); + } + return true; + } +}; + + +// Recursive solution. +class Solution2 { +public: + bool isSymmetric(TreeNode* root) { + if (!root) { + return true; + } + return isSymmetricHelper(root->left, root->right); + } + + bool isSymmetricHelper(TreeNode *left, TreeNode *right) { + if (!left && !right) { + return true; + } + if (!left || !right || left->val != right->val) { + return false; + } + return isSymmetricHelper(left->left, right->right) && + isSymmetricHelper(left->right, right->left); + } +}; diff --git a/C++/tag-validator.cpp b/C++/tag-validator.cpp new file mode 100644 index 000000000..25556dd6e --- /dev/null +++ b/C++/tag-validator.cpp @@ -0,0 +1,70 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + bool isValid(string code) { + auto i = 0; + return validTag(code, &i) && i == code.length(); + } + +private: + bool validTag(const string& s, int *i) { + auto j = *i; + auto tag = parseTagName(s, &j); + if (tag.empty()) { + return false; + } + parseContent(s, &j); + auto k = j + tag.size() + 2; + if (k >= s.size() || s.substr(j, k + 1 - j) != "") { + return false; + } + *i = k + 1; + return true; + } + + string parseTagName(const string& s, int *i) { + if (s[*i] != '<') { + return ""; + } + auto j = s.find('>', *i); + if (j == string::npos || j - 1 - *i < 1 || 9 < j - 1 - *i) { + return ""; + } + auto tag = s.substr(*i + 1, j - 1 - *i); + for (const auto& c : tag) { + if (c < 'A' || 'Z' < c) { + return ""; + } + } + *i = j + 1; + return tag; + } + + void parseContent(const string& s, int *i) { + while (*i < s.size()) { + if (!validText(s, i) && !validCData(s, i) && !validTag(s, i)) { + break; + } + } + } + + bool validText(const string& s, int *i) { + auto j = *i; + *i = s.find("<", *i); + return *i != j; + } + + bool validCData(const string& s, int *i) { + if (s.find("", *i); + if (j == string::npos) { + return false; + } + *i = j + 3; + return true; + } +}; diff --git a/C++/target-sum.cpp b/C++/target-sum.cpp new file mode 100644 index 000000000..a3a7f01d7 --- /dev/null +++ b/C++/target-sum.cpp @@ -0,0 +1,28 @@ +// Time: O(n * S) +// Space: O(S) + +class Solution { +public: + int findTargetSumWays(vector& nums, int S) { + // sum(P) - sum(N) = S + // <=> + // 2 * sum(P) = S + sum(nums) + int sum = accumulate(nums.begin(), nums.end(), 0); + if (sum < S || (S + sum) % 2) { + return 0; + } + return subsetSum(nums, (S + sum) / 2); + } + +private: + int subsetSum(vector& nums, int S) { + vector dp(S + 1); + dp[0] = 1; + for (const auto& n : nums) { + for (int i = S; i >= n; --i) { + dp[i] += dp[i - n]; + } + } + return dp.back(); + } +}; diff --git a/C++/task-scheduler.cpp b/C++/task-scheduler.cpp new file mode 100644 index 000000000..c37929643 --- /dev/null +++ b/C++/task-scheduler.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(26) = O(1) + +class Solution { +public: + int leastInterval(vector& tasks, int n) { + unordered_map count; + int max_count = 0; + for (const auto& task : tasks) { + ++count[task]; + max_count = max(max_count, count[task]); + } + + auto result = (max_count - 1) * (n + 1); + for (const auto& kvp : count) { + if (kvp.second == max_count) { + ++result; + } + } + return max(result, static_cast(tasks.size())); + } +}; diff --git a/C++/teemo-attacking.cpp b/C++/teemo-attacking.cpp new file mode 100644 index 000000000..294abfb79 --- /dev/null +++ b/C++/teemo-attacking.cpp @@ -0,0 +1,13 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findPoisonedDuration(vector& timeSeries, int duration) { + int result = duration * timeSeries.size(); + for (int i = 1; i < timeSeries.size(); ++i){ + result -= max(0, duration - (timeSeries[i] - timeSeries[i - 1])); + } + return result; + } +}; diff --git a/C++/ternary-expression-parser.cpp b/C++/ternary-expression-parser.cpp new file mode 100644 index 000000000..d71e836dc --- /dev/null +++ b/C++/ternary-expression-parser.cpp @@ -0,0 +1,32 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string parseTernary(string expression) { + if (expression.empty()) { + return ""; + } + + string stack; + for (int i = expression.length() - 1; i >= 0; --i) { + auto c = expression[i]; + if (!stack.empty() && stack.back() == '?') { + stack.pop_back(); // pop '?' + auto first = stack.back(); stack.pop_back(); + stack.pop_back(); // pop ':' + auto second = stack.back(); stack.pop_back(); + + if (c == 'T') { + stack.push_back(first); + } else { + stack.push_back(second); + } + } else { + stack.push_back(c); + } + } + + return string(1, stack.back()); + } +}; diff --git a/C++/text-justification.cpp b/C++/text-justification.cpp new file mode 100644 index 000000000..601be856e --- /dev/null +++ b/C++/text-justification.cpp @@ -0,0 +1,48 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector fullJustify(vector& words, int maxWidth) { + vector res; + const int n = words.size(); + int begin = 0, len = 0; + for (int i = 0; i < n; ++i) { + if (len + words[i].size() + (i - begin) > maxWidth) { + res.emplace_back(connect(words, maxWidth, begin, i, len, false)); + begin = i; + len = 0; + } + len += words[i].size(); + } + // Last line. + res.emplace_back(connect(words, maxWidth, begin, n, len, true)); + return res; + } + +private: + string connect(const vector& words, int maxWidth, + int begin, int end, int len, + bool is_last) { + string s; + int n = end - begin; + for (int i = 0; i < n; ++i) { + s += words[begin + i]; + addSpaces(i, n - 1, maxWidth - len, is_last, &s); + } + // For only one word in a line. + if (s.size() < maxWidth) { + s.append(maxWidth - s.size(), ' '); + } + return s; + } + + void addSpaces(int i, int spaceCnt, int maxWidth, bool is_last, string *s) { + if (i < spaceCnt) { + // For the last line of text, it should be left justified, + // and no extra space is inserted between words. + int spaces = is_last ? 1 : maxWidth / spaceCnt + (i < maxWidth % spaceCnt); + s->append(spaces, ' '); + } + } +}; diff --git a/C++/textJustification.cpp b/C++/textJustification.cpp deleted file mode 100644 index 8187d104f..000000000 --- a/C++/textJustification.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// LeetCode, Text Justification -// Complexity: -// O(n) time -// O(1) space - -class Solution { -public: - vector fullJustify(vector &words, int L) { - vector result; - const int n = words.size(); - int begin = 0, len = 0; - for (int i = 0; i < n; ++i) { - if (len + words[i].size() + (i - begin) > L) { - result.push_back(connect(words, begin, i - 1, len, L, false)); - begin = i; - len = 0; - } - - len += words[i].size(); - } - // last line - result.push_back(connect(words, begin, n - 1, len, L, true)); - return result; - } - - string connect(vector &words, int begin, int end, - int len, int L, bool is_last) { - string s; - int n = end - begin + 1; - for (int i = 0; i < n; ++i) { - s += words[begin + i]; - addSpaces(s, i, n - 1, L - len, is_last); - } - // for only one word in a line - if (s.size() < L) s.append(L - s.size(), ' '); - return s; - } - - void addSpaces(string &s, int i, int n, int L, bool is_last) { - if (n < 1 || i > n - 1) return; - // for the last line of text, it should be left justified, - // and no extra space is inserted between words. - int spaces = is_last ? 1 : (L / n + (i < (L % n) ? 1 : 0)); - s.append(spaces, ' '); - } -}; \ No newline at end of file diff --git a/C++/the-maze-ii.cpp b/C++/the-maze-ii.cpp new file mode 100644 index 000000000..1256ced9b --- /dev/null +++ b/C++/the-maze-ii.cpp @@ -0,0 +1,58 @@ +// Time: O(max(r, c) * wlogw) +// Space: O(w) + +class Solution { +public: + int shortestDistance(vector>& maze, vector& start, vector& destination) { + static const vector> dirs = {{-1, 0}, {0, 1}, {0, -1}, {1, 0}}; + priority_queue, greater> heap; + unordered_set visited; + heap.emplace(0, start); + + while (!heap.empty()) { + int dist = 0; + vector node; + tie(dist, node) = heap.top(); + heap.pop(); + if (visited.count(hash(maze, node))) { + continue; + } + if (node[0] == destination[0] && + node[1] == destination[1]) { + return dist; + } + + visited.emplace(hash(maze, node)); + for (const auto& dir : dirs) { + int neighbor_dist = 0; + vector neighbor; + tie(neighbor_dist, neighbor) = findNeighbor(maze, node, dir); + heap.emplace(dist + neighbor_dist, neighbor); + } + } + + return -1; + } + +private: + using node = pair>; + + node findNeighbor(const vector>& maze, + const vector& node, const vector& dir) { + vector cur_node = node; + int dist = 0; + + while (0 <= cur_node[0] + dir[0] && cur_node[0] + dir[0] < maze.size() && + 0 <= cur_node[1] + dir[1] && cur_node[1] + dir[1] < maze[0].size() && + !maze[cur_node[0] + dir[0]][cur_node[1] + dir[1]]) { + cur_node[0] += dir[0]; + cur_node[1] += dir[1]; + ++dist; + } + return {dist, cur_node}; + } + + int hash(const vector>& maze, const vector& node) { + return node[0] * maze[0].size() + node[1]; + } +}; diff --git a/C++/the-maze-iii.cpp b/C++/the-maze-iii.cpp new file mode 100644 index 000000000..cf2739527 --- /dev/null +++ b/C++/the-maze-iii.cpp @@ -0,0 +1,75 @@ +// Time: O(max(r, c) * wlogw) +// Space: O(w^2) + +class Solution { +public: + string findShortestWay(vector>& maze, vector& ball, vector& hole) { + static const unordered_map> dirs = {{"u", {-1, 0}}, {"r", {0, 1}}, + {"l", {0, -1}}, {"d", {1, 0}}}; + priority_queue, greater> heap; + unordered_set visited; + heap.emplace(0, make_pair("", ball)); + + while (!heap.empty()) { + int dist = 0; + string path; + vector node; + tie(dist, lvalue(tie(path, node))) = heap.top(); + heap.pop(); + if (visited.count(hash(maze, node))) { + continue; + } + + if (node[0] == hole[0] && + node[1] == hole[1]) { + return path; + } + + visited.emplace(hash(maze, node)); + for (const auto& kvp : dirs) { + int neighbor_dist = 0; + string dir; + vector neighbor; + tie(neighbor_dist, lvalue(tie(dir, neighbor))) = findNeighbor(maze, hole, node, kvp); + heap.emplace(dist + neighbor_dist, make_pair(path + dir, neighbor)); + } + } + + return "impossible"; + } + +private: + using node = pair>>; + + node findNeighbor(const vector>& maze, const vector& hole, + const vector& node, const pair>& kvp) { + string dir; + vector vec; + tie(dir, vec) = kvp; + vector cur_node = node; + int dist = 0; + + while (0 <= cur_node[0] + vec[0] && cur_node[0] + vec[0] < maze.size() && + 0 <= cur_node[1] + vec[1] && cur_node[1] + vec[1] < maze[0].size() && + !maze[cur_node[0] + vec[0]][cur_node[1] + vec[1]]) { + + cur_node[0] += vec[0]; + cur_node[1] += vec[1]; + ++dist; + if (cur_node[0] == hole[0] && + cur_node[1] == hole[1]) { + break; + } + } + return {dist, {dir, cur_node}}; + } + + int hash(const vector>& maze, const vector& node) { + return node[0] * maze[0].size() + node[1]; + } + + template + constexpr T &lvalue(T &&v) { + return v; + } +}; diff --git a/C++/the-maze.cpp b/C++/the-maze.cpp new file mode 100644 index 000000000..6a80e40e6 --- /dev/null +++ b/C++/the-maze.cpp @@ -0,0 +1,58 @@ +// Time: O(max(r, c) * w) +// Space: O(w) + +class Solution { +public: + bool hasPath(vector>& maze, vector& start, vector& destination) { + static const vector> dirs = {{-1, 0}, {0, 1}, {0, -1}, {1, 0}}; + queue q; + unordered_set visited; + q.emplace(0, start); + + while (!q.empty()) { + int dist = 0; + vector node; + tie(dist, node) = q.front(); + q.pop(); + if (visited.count(hash(maze, node))) { + continue; + } + if (node[0] == destination[0] && + node[1] == destination[1]) { + return true; + } + + visited.emplace(hash(maze, node)); + for (const auto& dir : dirs) { + int neighbor_dist = 0; + vector neighbor; + tie(neighbor_dist, neighbor) = findNeighbor(maze, node, dir); + q.emplace(dist + neighbor_dist, neighbor); + } + } + + return false; + } + +private: + using node = pair>; + + node findNeighbor(const vector>& maze, + const vector& node, const vector& dir) { + vector cur_node = node; + int dist = 0; + + while (0 <= cur_node[0] + dir[0] && cur_node[0] + dir[0] < maze.size() && + 0 <= cur_node[1] + dir[1] && cur_node[1] + dir[1] < maze[0].size() && + !maze[cur_node[0] + dir[0]][cur_node[1] + dir[1]]) { + cur_node[0] += dir[0]; + cur_node[1] += dir[1]; + ++dist; + } + return {dist, cur_node}; + } + + int hash(const vector>& maze, const vector& node) { + return node[0] * maze[0].size() + node[1]; + } +}; diff --git a/C++/the-skyline-problem.cpp b/C++/the-skyline-problem.cpp new file mode 100644 index 000000000..626963c95 --- /dev/null +++ b/C++/the-skyline-problem.cpp @@ -0,0 +1,147 @@ +// Time: O(nlogn) +// Space: O(n) + +// BST solution. +class Solution { +public: + enum {start, end, height}; + + struct Endpoint { + int height; + bool isStart; + }; + + vector > getSkyline(vector >& buildings) { + map> point_to_height; // Ordered, no duplicates. + for (const auto& building : buildings) { + point_to_height[building[start]].emplace_back(Endpoint{building[height], true}); + point_to_height[building[end]].emplace_back(Endpoint{building[height], false}); + } + + vector> res; + map height_to_count; // BST. + int curr_max = 0; + // Enumerate each point in increasing order. + for (const auto& kvp : point_to_height) { + const auto& point = kvp.first; + const auto& heights = kvp.second; + + for (const auto& h : heights) { + if (h.isStart) { + ++height_to_count[h.height]; + } else { + --height_to_count[h.height]; + if (height_to_count[h.height] == 0) { + height_to_count.erase(h.height); + } + } + } + + if (height_to_count.empty() || + curr_max != height_to_count.crbegin()->first) { + curr_max = height_to_count.empty() ? + 0 : height_to_count.crbegin()->first; + res.emplace_back(point, curr_max); + } + } + return res; + } +}; + +// Time: O(nlogn) +// Space: O(n) +// Divide and conquer solution. +class Solution2 { +public: + enum {start, end, height}; + + vector> getSkyline(vector>& buildings) { + const auto intervals = ComputeSkylineInInterval(buildings, 0, buildings.size()); + + vector> res; + int last_end = -1; + for (const auto& interval : intervals) { + if (last_end != -1 && last_end < interval[start]) { + res.emplace_back(last_end, 0); + } + res.emplace_back(interval[start], interval[height]); + last_end = interval[end]; + } + if (last_end != -1) { + res.emplace_back(last_end, 0); + } + return res; + } + + // Divide and Conquer. + vector> ComputeSkylineInInterval(const vector>& buildings, + int left_endpoint, int right_endpoint) { + if (right_endpoint - left_endpoint <= 1) { // 0 or 1 skyline, just copy it. + return {buildings.cbegin() + left_endpoint, + buildings.cbegin() + right_endpoint}; + } + int mid = left_endpoint + ((right_endpoint - left_endpoint) / 2); + auto left_skyline = ComputeSkylineInInterval(buildings, left_endpoint, mid); + auto right_skyline = ComputeSkylineInInterval(buildings, mid, right_endpoint); + return MergeSkylines(left_skyline, right_skyline); + } + + // Merge Sort + vector> MergeSkylines(vector>& left_skyline, vector>& right_skyline) { + int i = 0, j = 0; + vector> merged; + + while (i < left_skyline.size() && j < right_skyline.size()) { + if (left_skyline[i][end] < right_skyline[j][start]) { + merged.emplace_back(move(left_skyline[i++])); + } else if (right_skyline[j][end] < left_skyline[i][start]) { + merged.emplace_back(move(right_skyline[j++])); + } else if (left_skyline[i][start] <= right_skyline[j][start]) { + MergeIntersectSkylines(merged, left_skyline[i], i, + right_skyline[j], j); + } else { // left_skyline[i][start] > right_skyline[j][start]. + MergeIntersectSkylines(merged, right_skyline[j], j, + left_skyline[i], i); + } + } + + // Insert the remaining skylines. + merged.insert(merged.end(), left_skyline.begin() + i, left_skyline.end()); + merged.insert(merged.end(), right_skyline.begin() + j, right_skyline.end()); + return merged; + } + + // a[start] <= b[start] + void MergeIntersectSkylines(vector>& merged, vector& a, int& a_idx, + vector& b, int& b_idx) { + if (a[end] <= b[end]) { + if (a[height] > b[height]) { // |aaa| + if (b[end] != a[end]) { // |abb|b + b[start] = a[end]; + merged.emplace_back(move(a)), ++a_idx; + } else { // aaa + ++b_idx; // abb + } + } else if (a[height] == b[height]) { // abb + b[start] = a[start], ++a_idx; // abb + } else { // a[height] < b[height]. + if (a[start] != b[start]) { // bb + merged.emplace_back(move(vector{a[start], b[start], a[height]})); // |a|bb + } + ++a_idx; + } + } else { // a[end] > b[end]. + if (a[height] >= b[height]) { // aaaa + ++b_idx; // abba + } else { + // |bb| + // |a||bb|a + if (a[start] != b[start]) { + merged.emplace_back(move(vector{a[start], b[start], a[height]})); + } + a[start] = b[end]; + merged.emplace_back(move(b)), ++b_idx; + } + } + } +}; diff --git a/C++/third-maximum-number.cpp b/C++/third-maximum-number.cpp new file mode 100644 index 000000000..c07234f4f --- /dev/null +++ b/C++/third-maximum-number.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int thirdMax(vector& nums) { + int count = 0; + vector top(3, numeric_limits::min()); + + for (const auto& num : nums) { + if (num > top[0]) { + top[2] = top[1]; + top[1] = top[0]; + top[0] = num; + ++count; + } else if (num != top[0] && num > top[1]) { + top[2] = top[1]; + top[1] = num; + ++count; + } else if (num != top[0] && num != top[1] && num >= top[2]) { + top[2] = num; + ++count; + } + } + + if (count < 3) { + return top[0]; + } + return top[2]; + } +}; diff --git a/C++/threeSum.cpp b/C++/threeSum.cpp deleted file mode 100644 index 8cbea6c72..000000000 --- a/C++/threeSum.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(1) - -class Solution { - public: - vector > threeSum(vector &num) { - vector > ans; - const int target = 0; - - if(num.size() < 3) - return ans; - - sort(num.begin(), num.end()); - auto last = num.end(); - for(auto a = num.begin(); a < prev(last, 2); ++a) { - if(a > num.begin() && *a == *(a - 1)) - continue; - auto b = next(a); - auto c = prev(last); - - while(b < c) { - if(b > next(a) && *b == *(b - 1)) { - ++b; - } - else if(c < prev(last) && *c == *(c + 1)) { - --c; - } - else { - const int sum = *a + *b + *c; - - if(sum < target) - ++b; - else if(sum > target) - --c; - else { - ans.push_back({ *a, *b, *c}); - ++b; - --c; - } - } - } - } - - return ans; - } -}; - diff --git a/C++/threeSumCloset.cpp b/C++/threeSumCloset.cpp deleted file mode 100644 index 67034d769..000000000 --- a/C++/threeSumCloset.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(1) - -class Solution { - public: - int threeSumClosest(vector &num, int target) { - int ans = 0; - int gap = INT_MAX; - - sort(num.begin(), num.end()); - auto last = num.end(); - for(auto a = num.begin(); a != prev(last, 2); a++) { - auto b = next(a); - auto c = prev(last); - - while(b != c) { - const int sum = *a + *b + *c; - - if(gap > abs(target - sum)) { - gap = abs(target - sum); - ans = sum; - } - if(sum < target) - ++b; - else - --c; - } - } - - return ans; - } -}; diff --git a/C++/top-k-frequent-elements.cpp b/C++/top-k-frequent-elements.cpp new file mode 100644 index 000000000..216a27f24 --- /dev/null +++ b/C++/top-k-frequent-elements.cpp @@ -0,0 +1,78 @@ +// Time: O(n) +// Space: O(n) + +// Bucket Sort Solution +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (const auto& i : nums) { + ++counts[i]; + } + vector> buckets(nums.size() + 1); + for (const auto& kvp : counts) { + buckets[kvp.second].emplace_back(kvp.first); + } + + vector result; + for (int i = buckets.size() - 1; i >= 0; --i) { + for (int j = 0; j < buckets[i].size(); ++j){ + result.emplace_back(buckets[i][j]); + if (result.size() == k) { + return result; + } + } + } + return result; + } +}; + +// Time: O(n) ~ O(n^2), O(n) on average. +// Space: O(n) +// Quick Select Solution +class Solution2 { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (const auto& i : nums) { + ++counts[i]; + } + vector> p; + for (const auto& kvp : counts) { + p.emplace_back(-kvp.second, kvp.first); + } + nth_element(p.begin(), p.begin() + k - 1, p.end()); + vector result; + for (int i = 0; i < k; ++i) { + result.emplace_back(p[i].second); + } + return result; + } +}; + +// Time: O(nlogk) +// Space: O(n) +// Heap solution. +class Solution3 { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (const auto& i : nums) { + ++counts[i]; + } + priority_queue> heap; + for (const auto& kvp : counts) { + heap.emplace(-kvp.second, kvp.first); + if (heap.size() == k + 1) { + heap.pop(); + } + } + vector result; + while (!heap.empty()) { + result.emplace_back(heap.top().second); + heap.pop(); + } + reverse(result.begin(), result.end()); + return result; + } +}; diff --git a/C++/top-k-frequent-words.cpp b/C++/top-k-frequent-words.cpp new file mode 100644 index 000000000..fe77afcb7 --- /dev/null +++ b/C++/top-k-frequent-words.cpp @@ -0,0 +1,86 @@ +// Time: O(n + klogk) on average +// Space: O(n) + +// Quick Select Solution +class Solution { +public: + vector topKFrequent(vector& words, int k) { + unordered_map counts; + for (const auto& word : words) { + ++counts[word]; + } + vector> p; + for (const auto& kvp : counts) { + p.emplace_back(-kvp.second, kvp.first); + } + nth_element(p.begin(), p.begin() + k - 1, p.end()); // O(n) time on average. + sort(p.begin(), p.begin() + k); // O(klogk) time. + vector result; + for (int i = 0; i < k; ++i) { + result.emplace_back(p[i].second); + } + return result; + } +}; + + +// Time: O(nlogk) +// Space: O(n) +// Heap Solution +class Solution2 { +public: + vector topKFrequent(vector& words, int k) { + unordered_map counts; + for (const auto& word : words) { + ++counts[word]; + } + priority_queue> heap; + for (const auto& kvp : counts) { + heap.emplace(-kvp.second, kvp.first); + if (heap.size() == k + 1) { + heap.pop(); + } + } + vector result; + while (!heap.empty()) { + result.emplace_back(heap.top().second); + heap.pop(); + } + reverse(result.begin(), result.end()); + return result; + } +}; + + +// Time: O(n + klogk) ~ O(n + nlogn) +// Space: O(n) +// Bucket Sort Solution +class Solution3 { +public: + vector topKFrequent(vector& words, int k) { + unordered_map counts; + for (const auto& word : words) { + ++counts[word]; + } + vector> buckets(words.size() + 1); + for (const auto& kvp : counts) { + buckets[kvp.second].emplace_back(kvp.first); + } + + vector> p; + for (int i = buckets.size() - 1; i >= 0; --i) { + for (const auto& word : buckets[i]) { + p.emplace_back(-i, word); + } + if (p.size() >= k) { + break; + } + } + sort(p.begin(), p.end()); + vector result; + for (int i = 0; i < k; ++i) { + result.emplace_back(p[i].second); + } + return result; + } +}; diff --git a/C++/total-hamming-distance.cpp b/C++/total-hamming-distance.cpp new file mode 100644 index 000000000..b9098e48e --- /dev/null +++ b/C++/total-hamming-distance.cpp @@ -0,0 +1,17 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int totalHammingDistance(vector& nums) { + int result = 0; + for (int i = 0; i < 8 * sizeof(int); ++i) { + vector counts(2); + for (const auto& num : nums) { + ++counts[(num >> i) & 1]; + } + result += counts[0] * counts[1]; + } + return result; + } +}; diff --git a/C++/trap.cpp b/C++/trap.cpp deleted file mode 100644 index cb25e875e..000000000 --- a/C++/trap.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Time Complexity: O(n) -// Space Complexity: O(1) - -class Solution { - public: - int trap(int A[], int n) { - int max = 0; - for(int i = 0; i < n; ++i) { - if(A[i] > A[max]) - max = i; - } - - int water = 0; - for(int i = 0, top = 0; i < max; ++i) { - if(A[i] > top) - top = A[i]; - else - water += top - A[i]; - } - - for(int i = n - 1, top = 0; i > max; --i) { - if(A[i] > top) - top = A[i]; - else - water += top - A[i]; - } - - return water; - } -}; diff --git a/C++/trapping-rain-water-ii.cpp b/C++/trapping-rain-water-ii.cpp new file mode 100644 index 000000000..97c231218 --- /dev/null +++ b/C++/trapping-rain-water-ii.cpp @@ -0,0 +1,81 @@ +// Time: O(m * n * log(m + n)) ~ O(m * n * log(m * n)) +// Space: O(m * n) + +class Solution { +public: + int trapRainWater(vector>& heightMap) { + // Init m_, n_, is_visited_. + m_ = heightMap.size(); + if (!m_) { + return 0; + } + n_ = heightMap[0].size(); + if (!n_) { + return 0; + } + + is_visited_ = vector>(m_, vector(n_, false)); + + int trap = 0; + + // Put the cells on the border into min heap. + for (int i = 0; i < m_; ++i) { + heap_.emplace(Cell{i, 0, heightMap[i][0]}); + is_visited_[i][0] = true; + heap_.emplace(Cell{i, n_ - 1, heightMap[i][n_ - 1]}); + is_visited_[i][n_ - 1] = true; + } + for (int j = 0; j < n_; ++j) { + heap_.emplace(Cell{0, j, heightMap[0][j]}); + is_visited_[0][j] = true; + heap_.emplace(Cell{m_ - 1, j, heightMap[m_ - 1][j]}); + is_visited_[m_ - 1][j] = true; + } + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + // BFS with priority queue (min heap) + while (!heap_.empty()) { + Cell c = heap_.top(); + heap_.pop(); + for (const auto& d : directions) { + trap += fill(heightMap, c.i + d.first, c.j + d.second, c.height); + } + } + + return trap; + } + +private: + int fill(const vector>& heightMap, int i, int j, int height) { + // Out of border. + if ( i < 0 || i >= m_ || j < 0 || j >= n_) { + return 0; + } + + // Fill unvisited cell. + if (!is_visited_[i][j]) { + heap_.emplace(Cell{i, j, max(height, heightMap[i][j])}); + is_visited_[i][j] = true; // Marked as visited. + return max(0, height - heightMap[i][j]); // Fill in the gap. + } + + return 0; + } + + struct Cell { + int i; + int j; + int height; + }; + + struct Compare { + bool operator()(const Cell& a, const Cell& b) { + return a.height > b.height; + } + }; + + int m_; + int n_; + vector> is_visited_; + priority_queue, Compare> heap_; // Use min heap to get the lowerest cell. +}; diff --git a/C++/trapping-rain-water.cpp b/C++/trapping-rain-water.cpp new file mode 100644 index 000000000..082772360 --- /dev/null +++ b/C++/trapping-rain-water.cpp @@ -0,0 +1,35 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int trap(vector& height) { + if (height.empty()) { + return 0; + } + + int i = 0, j = height.size() - 1; + int left_height = height[0]; + int right_height = height[height.size() - 1]; + int trap = 0; + + while (i < j) { + if (left_height < right_height) { + ++i; + // Fill in the gap. + trap += max(0, left_height - height[i]); + // Update current max height from left. + left_height = max(left_height, height[i]); + } + else { + --j; + // Fill in the gap. + trap += max(0, right_height - height[j]); + // Update current max height from right. + right_height = max(right_height, height[j]); + } + } + + return trap; + } +}; diff --git a/C++/trim-a-binary-search-tree.cpp b/C++/trim-a-binary-search-tree.cpp new file mode 100644 index 000000000..d7ebff2bc --- /dev/null +++ b/C++/trim-a-binary-search-tree.cpp @@ -0,0 +1,29 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* trimBST(TreeNode* root, int L, int R) { + if (!root) { + return nullptr; + } + if (root->val < L) { + return trimBST(root->right, L, R); + } + if (root->val > R) { + return trimBST(root->left, L, R); + } + root->left = trimBST(root->left, L, R); + root->right = trimBST(root->right, L, R); + return root; + } +}; diff --git a/C++/two-sum-ii-input-array-is-sorted.cpp b/C++/two-sum-ii-input-array-is-sorted.cpp new file mode 100644 index 000000000..d7baf13f8 --- /dev/null +++ b/C++/two-sum-ii-input-array-is-sorted.cpp @@ -0,0 +1,22 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + vector twoSum(vector& numbers, int target) { + int left = 0, right = numbers.size() - 1; + + while (left != right) { + const auto sum = numbers[left] + numbers[right]; + if (sum > target) { + --right; + } else if (sum < target) { + ++left; + } else { + return {left + 1, right + 1}; + } + } + + return {0, 0}; + } +}; diff --git a/C++/two-sum-iii-data-structure-design.cpp b/C++/two-sum-iii-data-structure-design.cpp new file mode 100644 index 000000000..d664aea3c --- /dev/null +++ b/C++/two-sum-iii-data-structure-design.cpp @@ -0,0 +1,31 @@ +// Time: O(n) +// Space: O(n) + +class TwoSum { +public: + + // Add the number to an internal data structure. + void add(int number) { + ++lookup_[number]; + } + + // Find if there exists any pair of numbers which sum is equal to the value. + bool find(int value) { + for (const auto& kvp : lookup_) { + const auto num = value - kvp.first; + if (lookup_.count(num) && (num != kvp.first || kvp.second > 1)) { + return true; + } + } + return false; + } + +private: + unordered_map lookup_; +}; + + +// Your TwoSum object will be instantiated and called as such: +// TwoSum twoSum; +// twoSum.add(number); +// twoSum.find(value); diff --git a/C++/two-sum-iv-input-is-a-bst.cpp b/C++/two-sum-iv-input-is-a-bst.cpp new file mode 100644 index 000000000..3cbeeb4f4 --- /dev/null +++ b/C++/two-sum-iv-input-is-a-bst.cpp @@ -0,0 +1,67 @@ +// Time: O(n) +// Space: O(h) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +class Solution { +public: + bool findTarget(TreeNode* root, int k) { + if (!root) { + return false; + } + BSTIterator left(root, true), right(root, false); + while (*left < *right) { + if (*left + *right == k) { + return true; + } else if (*left + *right < k) { + ++left; + } else { + ++right; + } + } + return false; + } + +private: + class BSTIterator { + public: + BSTIterator(TreeNode *root, bool forward) : + node_(root), + forward_(forward) { + ++(*this); + }; + + int operator*() { + return cur_; + } + + void operator++() { + while (node_ || !s_.empty()) { + if (node_) { + s_.emplace(node_); + node_ = forward_ ? node_->left : node_->right; + } else { + node_ = s_.top(); + s_.pop(); + cur_ = node_->val; + node_ = forward_ ? node_->right : node_->left; + break; + } + } + } + + private: + TreeNode* node_; + bool forward_; + stack s_; + int cur_; + }; +}; diff --git a/C++/two-sum.cpp b/C++/two-sum.cpp new file mode 100644 index 000000000..841d2e1a5 --- /dev/null +++ b/C++/two-sum.cpp @@ -0,0 +1,16 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map lookup; + for (int i = 0; i < nums.size(); ++i) { + if (lookup.count(target - nums[i])) { + return {lookup[target - nums[i]], i}; + } + lookup[nums[i]] = i; + } + return {}; + } +}; diff --git a/C++/ugly-number-ii.cpp b/C++/ugly-number-ii.cpp new file mode 100644 index 000000000..00c79a9f5 --- /dev/null +++ b/C++/ugly-number-ii.cpp @@ -0,0 +1,85 @@ +// Time: O(n) +// Space: O(n) + +// DP solution. (12ms) +class Solution { +public: + int nthUglyNumber(int n) { + vector uglies(n); + uglies[0] = 1; + + int f2 = 2, f3 = 3, f5 = 5; + int idx2 = 0, idx3 = 0, idx5 = 0; + + for (int i = 1; i < n; ++i) { + int min_val = min(min(f2, f3), f5); + uglies[i] = min_val; + + if (min_val == f2) { + f2 = 2 * uglies[++idx2]; + } + if (min_val == f3) { + f3 = 3 * uglies[++idx3]; + } + if (min_val == f5) { + f5 = 5 * uglies[++idx5]; + } + } + + return uglies[n - 1]; + } +}; + +// Time: O(n) +// Space: O(1) +// Heap solution. (148ms) +class Solution2 { +public: + int nthUglyNumber(int n) { + long long ugly_number = 0; + priority_queue, greater> heap; + + heap.emplace(1); + for (int i = 0; i < n; ++i) { + ugly_number = heap.top(); + heap.pop(); + if (ugly_number % 2 == 0) { + heap.emplace(ugly_number * 2); + } else if (ugly_number % 3 == 0) { + heap.emplace(ugly_number * 2); + heap.emplace(ugly_number * 3); + } else { + heap.emplace(ugly_number * 2); + heap.emplace(ugly_number * 3); + heap.emplace(ugly_number * 5); + } + } + return ugly_number; + } +}; + +// BST solution. +class Solution3 { +public: + int nthUglyNumber(int n) { + long long ugly_number = 0; + set bst; + + bst.emplace(1); + for (int i = 0; i < n; ++i) { + ugly_number = *bst.cbegin(); + bst.erase(bst.cbegin()); + if (ugly_number % 2 == 0) { + bst.emplace(ugly_number * 2); + } else if (ugly_number % 3 == 0) { + bst.emplace(ugly_number * 2); + bst.emplace(ugly_number * 3); + } else { + bst.emplace(ugly_number * 2); + bst.emplace(ugly_number * 3); + bst.emplace(ugly_number * 5); + } + } + return ugly_number; + } +}; diff --git a/C++/ugly-number.cpp b/C++/ugly-number.cpp new file mode 100644 index 000000000..3f357bc5c --- /dev/null +++ b/C++/ugly-number.cpp @@ -0,0 +1,17 @@ +// Time: O(logn) = O(1) +// Space: O(1) + +class Solution { +public: + bool isUgly(int num) { + if (num == 0) { + return false; + } + for (const auto& i : {2, 3, 5}) { + while (num % i == 0) { + num /= i; + } + } + return num == 1; + } +}; diff --git a/C++/unique-binary-search-trees-ii.cpp b/C++/unique-binary-search-trees-ii.cpp new file mode 100644 index 000000000..a26e83c9f --- /dev/null +++ b/C++/unique-binary-search-trees-ii.cpp @@ -0,0 +1,57 @@ +// Time: O(n * 4^n / n^(3/2)) ~= Catalan numbers +// Space: O(n) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector generateTrees(int n) { + if (n == 0) { + return {}; + } + return generateTreesHelper(1, n); + } + +private: + vector generateTreesHelper(int start, int end) { + vector result; + if (start > end) { + result.emplace_back(nullptr); + return result; + } + + for (int i = start; i <= end; ++i) { + vector leftSubTrees = generateTreesHelper(start, i - 1); + vector rightSubTrees = generateTreesHelper(i + 1, end); + for (const auto& left : leftSubTrees) { + for (const auto& right : rightSubTrees) { + TreeNode *root = new TreeNode(i); + root->left = clone(left); + root->right = clone(right); + result.emplace_back(root); + } + } + + } + return result; + } + + TreeNode *clone(TreeNode *root) { + TreeNode *newRoot = nullptr; + + if (root) { + newRoot = new TreeNode(root->val); + newRoot->left = clone(root->left); + newRoot->right = clone(root->right); + } + + return newRoot; + } +}; diff --git a/C++/unique-substrings-in-wraparound-string.cpp b/C++/unique-substrings-in-wraparound-string.cpp new file mode 100644 index 000000000..dd4f847b7 --- /dev/null +++ b/C++/unique-substrings-in-wraparound-string.cpp @@ -0,0 +1,21 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int findSubstringInWraproundString(string p) { + vector letters(26, 0); + int result = 0, len = 0; + for (int i = 0; i < p.length(); ++i) { + int curr = p[i] - 'a'; + if (i > 0 && p[i - 1] != (curr + 26 - 1) % 26 + 'a') { + len = 0; + } + if (++len > letters[curr]) { + result += len - letters[curr]; + letters[curr] = len; + } + } + return result; + } +}; diff --git a/C++/unique-word-abbreviation.cpp b/C++/unique-word-abbreviation.cpp new file mode 100644 index 000000000..e07743b9f --- /dev/null +++ b/C++/unique-word-abbreviation.cpp @@ -0,0 +1,35 @@ +// Time: ctor: O(n), n is number of words in the dictionary. +// lookup: O(1) +// Space: O(k), k is number of unique words. + +class ValidWordAbbr { +public: + ValidWordAbbr(vector &dictionary) { + for (string& word : dictionary) { + const string abbr = abbreviation(word); + lookup_[abbr].emplace(word); + } + } + + bool isUnique(string word) { + const string abbr = abbreviation(word); + return lookup_[abbr].empty() || + (lookup_[abbr].count(word) == lookup_[abbr].size()); + } + +private: + unordered_map> lookup_; + + string abbreviation(const string& word) { + if (word.length() <= 2) { + return word; + } + return word.front() + to_string(word.length()) + word.back(); + } +}; + + +// Your ValidWordAbbr object will be instantiated and called as such: +// ValidWordAbbr vwa(dictionary); +// vwa.isUnique("hello"); +// vwa.isUnique("anotherWord"); diff --git a/C++/utf-8-validation.cpp b/C++/utf-8-validation.cpp new file mode 100644 index 000000000..319f94569 --- /dev/null +++ b/C++/utf-8-validation.cpp @@ -0,0 +1,28 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool validUtf8(vector& data) { + int count = 0; + for (const auto& c : data) { + if (count == 0) { + if ((c >> 5) == 0b110) { + count = 1; + } else if ((c >> 4) == 0b1110) { + count = 2; + } else if ((c >> 3) == 0b11110) { + count = 3; + } else if ((c >> 7)) { + return false; + } + } else { + if ((c >> 6) != 0b10) { + return false; + } + --count; + } + } + return count == 0; + } +}; diff --git a/C++/valid-anagram.cpp b/C++/valid-anagram.cpp new file mode 100644 index 000000000..290375884 --- /dev/null +++ b/C++/valid-anagram.cpp @@ -0,0 +1,42 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isAnagram(string s, string t) { + if (s.length() != t.length()) { + return false; + } + + unordered_map count; + + for (const auto& c: s) { + ++count[tolower(c)]; + } + + for (const auto& c: t) { + --count[tolower(c)]; + if (count[tolower(c)] < 0) { + return false; + } + } + + return true; + } +}; + +// Time: O(nlogn) +// Space: O(n) +class Solution2 { +public: + bool isAnagram(string s, string t) { + if (s.length() != t.length()) { + return false; + } + + sort(s.begin(), s.end()); + sort(t.begin(), t.end()); + + return s == t; + } +}; diff --git a/C++/valid-number.cpp b/C++/valid-number.cpp new file mode 100644 index 000000000..7e18513ac --- /dev/null +++ b/C++/valid-number.cpp @@ -0,0 +1,64 @@ +// Time: O(n) +// Space: O(1) + +// automata: http://images.cnitblog.com/i/627993/201405/012016243309923.png +class Solution { +public: + bool isNumber(string s) { + enum InputType { + INVALID, // 0 + SPACE, // 1 + SIGN, // 2 + DIGIT, // 3 + DOT, // 4 + EXPONENT, // 5 + NUM_INPUTS // 6 + }; + int transitionTable[][NUM_INPUTS] = { + -1, 0, 3, 1, 2, -1, // next states for state 0 + -1, 8, -1, 1, 4, 5, // next states for state 1 + -1, -1, -1, 4, -1, -1, // next states for state 2 + -1, -1, -1, 1, 2, -1, // next states for state 3 + -1, 8, -1, 4, -1, 5, // next states for state 4 + -1, -1, 6, 7, -1, -1, // next states for state 5 + -1, -1, -1, 7, -1, -1, // next states for state 6 + -1, 8, -1, 7, -1, -1, // next states for state 7 + -1, 8, -1, -1, -1, -1, // next states for state 8 + }; + + int state = 0; + for (const auto& c: s) { + InputType inputType = INVALID; + if (isspace(c)) { + inputType = SPACE; + } else if (c == '+' || c == '-') { + inputType = SIGN; + } else if (isdigit(c)) { + inputType = DIGIT; + } else if (c == '.') { + inputType = DOT; + } else if (c == 'e' || c == 'E') { + inputType = EXPONENT; + } + // Get next state from current state and input symbol + state = transitionTable[state][inputType]; + + // Invalid input + if (state == -1) { + return false; + } + } + // If the current state belongs to one of the accepting (final) states, + // then the number is valid + return state == 1 || state == 4 || state == 7 || state == 8; + } +}; + +#include +class Solution_TLE { +public: + bool isNumber(string s) { + regex e("^\\s*[\\+-]?((\\d+(\\.\\d*)?)|\\.\\d+)([eE][\\+-]?\\d+)?\\s*$"); + return regex_match(s, e); + } +}; diff --git a/C++/valid-palindrome-ii.cpp b/C++/valid-palindrome-ii.cpp new file mode 100644 index 000000000..1cd239064 --- /dev/null +++ b/C++/valid-palindrome-ii.cpp @@ -0,0 +1,27 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool validPalindrome(string s) { + int left = 0, right = s.length() - 1; + while (left < right) { + if (s[left] != s[right]) { + return validPalindrome(s, left, right - 1) || validPalindrome(s, left + 1, right); + } + ++left, --right; + } + return true; + } + +private: + bool validPalindrome(const string& s, int left, int right) { + while (left < right) { + if (s[left] != s[right]) { + return false; + } + ++left, --right; + } + return true; + } +}; diff --git a/C++/valid-palindrome.cpp b/C++/valid-palindrome.cpp new file mode 100644 index 000000000..3e81b0275 --- /dev/null +++ b/C++/valid-palindrome.cpp @@ -0,0 +1,44 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isPalindrome(string s) { + int i = 0, j = s.length() - 1; + while (i < j) { + if (!isalnum(s[i])) { + ++i; + } else if (!isalnum(s[j])) { + --j; + } else if (tolower(s[i]) != tolower(s[j])) { + return false; + } else { + ++i, --j; + } + } + return true; + } +}; + +// Time: O(n) +// Space: O(1) +// Iterator solution. +class Solution2 { +public: + bool isPalindrome(string s) { + auto left = s.begin(); + auto right = prev(s.end()); + while (left < right) { + if (!isalnum(*left)) { + ++left; + } else if (!isalnum(*right)) { + --right; + } else if (tolower(*left) != tolower(*right)) { + return false; + } else { + ++left, --right; + } + } + return true; + } +}; diff --git a/C++/valid-parentheses.cpp b/C++/valid-parentheses.cpp new file mode 100644 index 000000000..aeb15cac0 --- /dev/null +++ b/C++/valid-parentheses.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(n) + +class Solution { +public: + bool isValid(string s) { + const unordered_map symbol_pair = {{')', '('}, + {']', '['}, + {'}', '{'}}; + stack parentheses; + for (const auto& c: s) { + const auto& it = symbol_pair.find(c); + if (it != symbol_pair.cend()) { + if (parentheses.empty() || + parentheses.top() != it->second) { + return false; + } + parentheses.pop(); + } else { + parentheses.emplace(c); + } + } + return parentheses.empty(); + } +}; diff --git a/C++/valid-parenthesis-string.cpp b/C++/valid-parenthesis-string.cpp new file mode 100644 index 000000000..af21619c9 --- /dev/null +++ b/C++/valid-parenthesis-string.cpp @@ -0,0 +1,16 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool checkValidString(string s) { + int lower = 0, upper = 0; // keep lower bound and upper bound of '(' counts + for (const auto& c : s) { + lower += (c == '(') ? 1 : -1; + upper -= (c == ')') ? 1 : -1; + if (upper < 0) break; + lower = max(lower, 0); + } + return lower == 0; // range of '(' count is valid + } +}; diff --git a/C++/valid-perfect-square.cpp b/C++/valid-perfect-square.cpp new file mode 100644 index 000000000..91c301ee5 --- /dev/null +++ b/C++/valid-perfect-square.cpp @@ -0,0 +1,18 @@ +// Time: O(logn) +// Space: O(1) + +class Solution { +public: + bool isPerfectSquare(int num) { + int left = 1, right = num; + while (left <= right) { + const int mid = left + (right - left) / 2; + if (mid >= num / mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left == num / left && num % left == 0; + } +}; diff --git a/C++/valid-square.cpp b/C++/valid-square.cpp new file mode 100644 index 000000000..54d7d3d83 --- /dev/null +++ b/C++/valid-square.cpp @@ -0,0 +1,18 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + bool validSquare(vector& p1, vector& p2, vector& p3, vector& p4) { + unordered_set lookup({ dist(p1, p2), dist(p1, p3), + dist(p1, p4), dist(p2, p3), + dist(p2, p4), dist(p3, p4) }); + return !lookup.count(0) && lookup.size() == 2; + } + +private: + int dist(vector& p1, vector& p2) { + return (p1[0] - p2[0]) * (p1[0] - p2[0]) + + (p1[1] - p2[1]) * (p1[1] - p2[1]); + } +}; diff --git a/C++/valid-sudoku.cpp b/C++/valid-sudoku.cpp new file mode 100644 index 000000000..07a4c043e --- /dev/null +++ b/C++/valid-sudoku.cpp @@ -0,0 +1,107 @@ +// Time: O(9^2) +// Space: O(9) + +// Better performance solution. +class Solution { +public: + bool isValidSudoku(const vector>& board) { + // Check row constraints. + for (int i = 0; i < 9; ++i) { + if (anyDuplicate(board, i, i + 1, 0, 9)) { + return false; + } + } + + // Check column constraints. + for (int j = 0; j < board.size(); ++j) { + if (anyDuplicate(board, 0, 9, j, j + 1)) { + return false; + } + } + + // Check region constraints. + for (int i = 0; i < 9; i += 3) { + for (int j = 0; j < 9; j += 3) { + if (anyDuplicate(board, i, i + 3, j, j + 3)) { + return false; + } + } + } + return true; + } + +private: + // Return true if subarray board[start_row : end_row - 1][start_col : end_col - 1] + // contains any duplicates in [1 : num_elements]; otherwise return false. + bool anyDuplicate(const vector>& board, int start_row, int end_row, + int start_col, int end_col) { + bitset<9> is_present; + for (int i = start_row; i < end_row; ++i) { + for (int j = start_col; j < end_col; ++j) { + if (board[i][j] != '.') { + if (is_present[board[i][j] - '1']) { + return true; + } + is_present.flip(board[i][j] - '1'); + } + } + } + return false; + } +}; + + +// Time: O(9^2) +// Space: O(9) +// More generic solution. +class Solution2 { +public: + bool isValidSudoku(const vector>& board) { + // Check row constraints. + for (int i = 0; i < board.size(); ++i) { + if (anyDuplicate(board, i, i + 1, 0, board.size(), board.size())) { + return false; + } + } + + // Check column constraints. + for (int j = 0; j < board.size(); ++j) { + if (anyDuplicate(board, 0, board.size(), j, j + 1, board.size())) { + return false; + } + } + + // Check region constraints. + int region_size = sqrt(board.size()); + for (int i = 0; i < board.size(); i += region_size) { + for (int j = 0; j < board.size(); j += region_size) { + if (anyDuplicate(board, + i, i + region_size, + j, j + region_size, + board.size())) { + return false; + } + } + } + return true; + } + +private: + // Return true if subarray board[start_row : end_row - 1][start_col : end_col - 1] + // contains any duplicates in [1 : num_elements]; otherwise return false. + bool anyDuplicate(const vector>& board, int start_row, int end_row, + int start_col, int end_col, int num_elements) { + vector is_present(num_elements + 1, false); + for (int i = start_row; i < end_row; ++i) { + for (int j = start_col; j < end_col; ++j) { + if (board[i][j] != '.') { + if (is_present[board[i][j] - '0']) { + return true; + } + is_present[board[i][j] - '0'] = true; + } + } + } + return false; + } +}; diff --git a/C++/valid-triangle-number.cpp b/C++/valid-triangle-number.cpp new file mode 100644 index 000000000..fd270550f --- /dev/null +++ b/C++/valid-triangle-number.cpp @@ -0,0 +1,24 @@ +// Time: O(n^2) +// Space: O(1) + +class Solution { +public: + int triangleNumber(vector& nums) { + int result = 0; + sort(nums.begin(), nums.end()); + for (int i = 0; i + 2 < nums.size(); ++i) { + if (nums[i] == 0) { + continue; + } + auto k = i + 2; + for (int j = i + 1; j + 1 < nums.size(); ++j) { + while (k < nums.size() && nums[i] + nums[j] > nums[k]) { + ++k; + } + result += k - j - 1; + } + } + return result; + } +}; + diff --git a/C++/valid-word-abbreviation.cpp b/C++/valid-word-abbreviation.cpp new file mode 100644 index 000000000..a60bcf47d --- /dev/null +++ b/C++/valid-word-abbreviation.cpp @@ -0,0 +1,30 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool validWordAbbreviation(string word, string abbr) { + int i = 0, digit = 0; + for (const auto& c : abbr) { + if (isdigit(c)) { + if (digit == 0 && c == '0') { + return false; + } + digit *= 10; + digit += c - '0'; + } else { + if (digit) { + i += digit; + digit = 0; + } + if (i >= word.length() || word[i++] != c) { + return false; + } + } + } + if (digit) { + i += digit; + } + return i == word.length(); + } +}; diff --git a/C++/valid-word-square.cpp b/C++/valid-word-square.cpp new file mode 100644 index 000000000..300d53318 --- /dev/null +++ b/C++/valid-word-square.cpp @@ -0,0 +1,17 @@ +// Time: O(m * n) +// Space: O(1) + +class Solution { +public: + bool validWordSquare(vector& words) { + for (int i = 0; i < words.size(); ++i) { + for (int j = 0; j < words[i].size(); ++j) { + if (j >= words.size() || i >= words[j].size() || + words[j][i] != words[i][j]) { + return false; + } + } + } + return true; + } +}; diff --git a/C++/validate-binary-search-tree.cpp b/C++/validate-binary-search-tree.cpp new file mode 100644 index 000000000..4ac6bab20 --- /dev/null +++ b/C++/validate-binary-search-tree.cpp @@ -0,0 +1,78 @@ +// Time: O(n) +// Space: O(1) + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +// Morris Traversal +class Solution { +public: + bool isValidBST(TreeNode* root) { + TreeNode *prev = nullptr; + TreeNode *curr = root; + while (curr) { + if (!curr->left) { + if (prev && prev->val >= curr->val) { + return false; + } + prev = curr; + curr = curr->right; + } else { + TreeNode *node = curr->left; + while (node->right && node->right != curr) { + node = node->right; + } + if (!node->right) { + node->right = curr; + curr = curr->left; + } else { + if (prev && prev->val >= curr->val) { + return false; + } + prev = curr; + node->right = nullptr; + curr = curr->right; + } + } + } + + return true; + } +}; + +// Time: O(n) +// Space: O(h) +class Solution2 { +public: + bool isValidBST(TreeNode* root) { + if (!root) { + return true; + } + + if (!isValidBST(root->left)) { + return false; + } + + if (last && last != root && last->val >= root->val) { + return false; + } + + last = root; + + if (!isValidBST(root->right)) { + return false; + } + + return true; + } + +private: + TreeNode *last = nullptr; +}; diff --git a/C++/validate-ip-address.cpp b/C++/validate-ip-address.cpp new file mode 100644 index 000000000..936451682 --- /dev/null +++ b/C++/validate-ip-address.cpp @@ -0,0 +1,62 @@ +// Time: O(1) +// Space: O(1) + +class Solution { +public: + string validIPAddress(string IP) { + stringstream ss(IP); + string block; + if (IP.substr(0, 4).find('.') != string::npos) { + for (int i = 0; i < 4; ++i) { + if (!getline(ss, block, '.') || !isValidIPv4Block(block)) { + return "Neither"; + } + } + if (ss.eof()) { + return "IPv4"; + } + } else if (IP.substr(0, 5).find(':') != string::npos) { + for (int i = 0; i < 8; ++i) { + if (!getline(ss, block, ':') || !isValidIPv6Block(block)) { + return "Neither"; + } + } + if (ss.eof()) { + return "IPv6"; + } + } + + return "Neither"; + } + +private: + bool isValidIPv4Block(const string& block) { + int num = 0; + if (block.size() > 0 && block.size() <= 3) { + for (int i = 0; i < block.size(); ++i) { + char c = block[i]; + if (!isalnum(c) || (i == 0 && c == '0' && block.size() > 1)) { + return false; + } else { + num *= 10; + num += c - '0'; + } + } + return num <= 255; + } + return false; + } + + bool isValidIPv6Block(const string& block) { + if (block.size() > 0 && block.size() <= 4) { + for (int i = 0; i < block.size(); ++i) { + char c = block[i]; + if (!isxdigit(c)) { + return false; + } + } + return true; + } + return false; + } +}; diff --git a/C++/verify-preorder-sequence-in-binary-search-tree.cpp b/C++/verify-preorder-sequence-in-binary-search-tree.cpp new file mode 100644 index 000000000..9e66bee98 --- /dev/null +++ b/C++/verify-preorder-sequence-in-binary-search-tree.cpp @@ -0,0 +1,43 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool verifyPreorder(vector& preorder) { + int low = INT_MIN, i = -1; + for (auto& p : preorder) { + if (p < low) { + return false; + } + while (i >= 0 && p > preorder[i]) { + low = preorder[i--]; + } + preorder[++i] = p; + } + return true; + } +}; + +// Time: O(n) +// Space: O(h) +class Solution2 { +public: + bool verifyPreorder(vector& preorder) { + int low = INT_MIN; + stack path; + for (auto& p : preorder) { + if (p < low) { + return false; + } + while (!path.empty() && p > path.top()) { + // Traverse to its right subtree now. + // Use the popped values as a lower bound because + // we shouldn't come across a smaller number anymore. + low = path.top(); + path.pop(); + } + path.emplace(p); + } + return true; + } +}; diff --git a/C++/verify-preorder-serialization-of-a-binary-tree.cpp b/C++/verify-preorder-serialization-of-a-binary-tree.cpp new file mode 100644 index 000000000..42c34086a --- /dev/null +++ b/C++/verify-preorder-serialization-of-a-binary-tree.cpp @@ -0,0 +1,51 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + bool isValidSerialization(string preorder) { + if (preorder.empty()) { + return false; + } + Tokenizer tokens(preorder); + int depth = 0; + int i = 0; + for (; i < tokens.size() && depth >= 0; ++i) { + if (tokens.get_next() == "#") { + --depth; + } else { + ++depth; + } + } + return i == tokens.size() && depth < 0; + } + + class Tokenizer { + public: + Tokenizer(const string& str) : str_(str), i_(0), cnt_(0) { + size_ = count(str_.cbegin(), str_.cend(), ',') + 1; + } + + string get_next() { + string next; + if (cnt_ < size_) { + size_t j = str_.find(",", i_); + next = str_.substr(i_, j - i_); + i_ = j + 1; + ++cnt_; + } + return next; + } + + size_t size() { + return size_; + } + + private: + const string& str_; + size_t size_; + size_t cnt_; + size_t i_; + }; + +}; diff --git a/C++/walls-and-gates.cpp b/C++/walls-and-gates.cpp new file mode 100644 index 000000000..9e66eca21 --- /dev/null +++ b/C++/walls-and-gates.cpp @@ -0,0 +1,34 @@ +// Time: O(m * n) +// Space: O(g) + +class Solution { +public: + void wallsAndGates(vector>& rooms) { + const int INF = numeric_limits::max(); + queue> q; + for (int i = 0; i < rooms.size(); ++i) { + for (int j = 0; j < rooms[0].size(); ++j) { + if (rooms[i][j] == 0) { + q.emplace(i, j); + } + } + } + while (!q.empty()) { + int i, j; + tie(i, j) = q.front(); + q.pop(); + for (const pair& d : + vector>{{i + 1, j}, {i - 1, j}, + {i, j + 1}, {i, j - 1}}) { + int I, J; + tie(I, J) = d; + if (I >= 0 && I < rooms.size() && + J >= 0 && J < rooms[0].size() && + rooms[I][J] == INF) { + rooms[I][J] = rooms[i][j] + 1; + q.emplace(I, J); + } + } + } + } +}; diff --git a/C++/water-and-jug-problem.cpp b/C++/water-and-jug-problem.cpp new file mode 100644 index 000000000..29402f4be --- /dev/null +++ b/C++/water-and-jug-problem.cpp @@ -0,0 +1,20 @@ +// Time: O(logn), n is the max of (x, y) +// Space: O(1) + +// Bézout's identity (also called Bézout's lemma) +class Solution { +public: + bool canMeasureWater(int x, int y, int z) { + return z == 0 || (z <= x + y && z % gcd(x, y) == 0); + } + +private: + int gcd(int a, int b) { + while (b != 0) { + int tmp = b; + b = a % b; + a = tmp; + } + return a; + } +}; diff --git a/C++/wiggle-sort-ii.cpp b/C++/wiggle-sort-ii.cpp new file mode 100644 index 000000000..76d6835db --- /dev/null +++ b/C++/wiggle-sort-ii.cpp @@ -0,0 +1,104 @@ +// Time: O(n) ~ O(n^2), O(n) on average. +// Space: O(1) + +// Tri Partition (aka Dutch National Flag Problem) with virtual index solution. (44ms) +class Solution { +public: + void wiggleSort(vector& nums) { + int mid = (nums.size() - 1) / 2; + nth_element(nums.begin(), nums.begin() + mid, nums.end()); // O(n) ~ O(n^2) time + reversedTriPartitionWithVI(nums, nums[mid]); // O(n) time, O(1) space + } + + void reversedTriPartitionWithVI(vector& nums, int val) { + const int N = nums.size() / 2 * 2 + 1; + #define Nums(i) nums[(1 + 2 * (i)) % N] + for (int i = 0, j = 0, n = nums.size() - 1; j <= n;) { + if (Nums(j) > val) { + swap(Nums(i++), Nums(j++)); + } else if (Nums(j) < val) { + swap(Nums(j), Nums(n--)); + } else { + ++j; + } + } + } +}; + +// Time: O(n) ~ O(n^2) +// Space: O(n) +// Tri Partition (aka Dutch National Flag Problem) solution. (64ms) +class Solution2 { +public: + void wiggleSort(vector& nums) { + int mid = (nums.size() - 1) / 2; + nth_element(nums.begin(), nums.begin() + mid, nums.end()); // O(n) ~ O(n^2) time + triPartition(nums, nums[mid]); // O(n) time, O(1) space + + vector res(nums.size()); // O(n) space + for (int i = 0, smallEnd = mid; i < nums.size(); i += 2, --smallEnd) { + res[i] = nums[smallEnd]; + } + for (int i = 1, largeEnd = nums.size() - 1; i < nums.size(); i += 2, --largeEnd) { + res[i] = nums[largeEnd]; + } + nums = res; + } + + void triPartition(vector& nums, int val) { + for (int i = 0, j = 0, n = nums.size() - 1; j <= n;) { + if (nums[j] < val) { + swap(nums[i++], nums[j++]); + } else if (nums[j] > val) { + swap(nums[j], nums[n--]); + } else { + ++j; + } + } + } +}; + +// Time: O(nlogn) +// Space: O(1) +// Sorting and Tri Partition (aka Dutch National Flag Problem) with virtual index solution. (64ms) +class Solution3 { +public: + void wiggleSort(vector& nums) { + int mid = (nums.size() - 1) / 2; + sort(nums.begin(), nums.end()); // O(nlogn) time + reversedTriPartitionWithVI(nums, nums[mid]); // O(n) time, O(1) space + } + + void reversedTriPartitionWithVI(vector& nums, int val) { + const int N = nums.size() / 2 * 2 + 1; + #define Nums(i) nums[(1 + 2 * (i)) % N] + for (int i = 0, j = 0, n = nums.size() - 1; j <= n;) { + if (Nums(j) > val) { + swap(Nums(i++), Nums(j++)); + } else if (Nums(j) < val) { + swap(Nums(j), Nums(n--)); + } else { + ++j; + } + } + } +}; + +// Time: O(nlogn) +// Space: O(n) +// Sorting and reorder solution. (64ms) +class Solution4 { +public: + void wiggleSort(vector& nums) { + int mid = (nums.size() - 1) / 2; + sort(nums.begin(), nums.end()); // O(nlogn) time + vector res(nums.size()); // O(n) space + for (int i = 0, smallEnd = mid; i < nums.size(); i += 2, --smallEnd) { + res[i] = nums[smallEnd]; + } + for (int i = 1, largeEnd = nums.size() - 1; i < nums.size(); i += 2, --largeEnd) { + res[i] = nums[largeEnd]; + } + nums = res; + } +}; diff --git a/C++/wiggle-sort.cpp b/C++/wiggle-sort.cpp new file mode 100644 index 000000000..7f550a748 --- /dev/null +++ b/C++/wiggle-sort.cpp @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + void wiggleSort(vector& nums) { + for (int i = 1; i < nums.size(); ++i) { + if (((i % 2) && nums[i] < nums[i - 1]) || + (!(i % 2) && nums[i] > nums[i - 1])) { + // Swap unordered elements. + swap(nums[i], nums[i - 1]); + } + } + } +}; diff --git a/C++/wiggle-subsequence.cpp b/C++/wiggle-subsequence.cpp new file mode 100644 index 000000000..83830a720 --- /dev/null +++ b/C++/wiggle-subsequence.cpp @@ -0,0 +1,25 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int wiggleMaxLength(vector& nums) { + if (nums.size() < 2) { + return nums.size(); + } + + int length = 1, up = 0; + + for (int i = 1; i < nums.size(); ++i) { + if (nums[i - 1] < nums[i] && (up == 0 || up == 1)) { + ++length; + up = -1; + } else if (nums[i - 1] > nums[i] && (up == 0 || up == -1)) { + ++length; + up = 1; + } + } + + return length; + } +}; diff --git a/C++/word-abbreviation.cpp b/C++/word-abbreviation.cpp new file mode 100644 index 000000000..ef4e94bbf --- /dev/null +++ b/C++/word-abbreviation.cpp @@ -0,0 +1,52 @@ +// Time: O(n * l) ~ O(n^2 * l^2) +// Space: O(n * l) + +class Solution { +public: + vector wordsAbbreviation(vector& dict) { + unordered_map> abbr_to_word; + unordered_map word_to_abbr; + + for (const auto& word : dict) { + const auto prefix = word.substr(0, 1); + abbr_to_word[toAbbr(prefix, word)].emplace(word); + } + + for (const auto& kvp : abbr_to_word) { + if (kvp.second.size() > 1) { + for (const auto& word : kvp.second) { + for (int i = 2; i < word.length(); ++i) { + const auto prefix = word.substr(0, i); + if (isUnique(prefix, kvp.second)) { + word_to_abbr[word] = toAbbr(prefix, word); + break; + } + } + } + } else { + word_to_abbr[*kvp.second.begin()] = kvp.first; + } + } + + vector result; + for (const auto& word : dict) { + result.emplace_back(word_to_abbr[word]); + } + return result; + } + +private: + bool isUnique(const string& prefix, const unordered_set& words) { + return 1 == count_if(words.begin(), words.end(), + [&prefix](const string& word) { + return !word.compare(0, prefix.length(), prefix); + }); + } + + string toAbbr(const string& prefix, const string& word) { + string abbr = prefix; + abbr += to_string(word.length() - 1 - prefix.length()); + abbr += word.back(); + return abbr.length() < word.length() ? abbr : word; + } +}; diff --git a/C++/word-break-ii.cpp b/C++/word-break-ii.cpp new file mode 100644 index 000000000..3e2b92667 --- /dev/null +++ b/C++/word-break-ii.cpp @@ -0,0 +1,55 @@ +// Time: O(n * l^2 + n * r), l is the max length of the words, +// r is the number of the results. +// Space: O(n^2) + +class Solution { +public: + vector wordBreak(string s, unordered_set& wordDict) { + const int n = s.length(); + + size_t max_len = 0; + for (const auto& str: wordDict) { + max_len = max(max_len, str.length()); + } + + vector canBreak(n + 1, false); + vector> valid(n, vector(n, false)); + canBreak[0] = true; + for (int i = 1; i <= n; ++i) { + for (int l = 1; l <= max_len && i - l >= 0; ++l) { + if (canBreak[i - l] && wordDict.count(s.substr(i - l, l))) { + valid[i - l][i - 1] = true; + canBreak[i] = true; + } + } + } + + vector result, path; + if (canBreak[n]) { + wordBreakHelper(s, valid, 0, &path, &result); + } + return result; + } + + + void wordBreakHelper(const string& s, const vector>& valid, + int start, vector *path, vector *result) { + if (start == s.length()) { + string tmp; + for (const auto& str : *path) { + tmp += str; + tmp += " "; + } + tmp.pop_back(); + result->emplace_back(move(tmp)); + return; + } + for (int i = start; i < s.length(); ++i) { + if (valid[start][i]) { + path->emplace_back(s.substr(start, i + 1 - start)); + wordBreakHelper(s, valid, i + 1, path, result); + path->pop_back(); + } + } + } +}; diff --git a/C++/word-break.cpp b/C++/word-break.cpp new file mode 100644 index 000000000..c3305a139 --- /dev/null +++ b/C++/word-break.cpp @@ -0,0 +1,27 @@ +// Time: O(n * l^2), l is the max length of the words. +// Space: O(n) + +class Solution { +public: + bool wordBreak(string s, unordered_set& wordDict) { + const int n = s.length(); + + size_t max_len = 0; + for (const auto& str: wordDict) { + max_len = max(max_len, str.length()); + } + + vector canBreak(n + 1, false); + canBreak[0] = true; + for (int i = 1; i <= n; ++i) { + for (int l = 1; l <= max_len && i - l >= 0; ++l) { + if (canBreak[i - l] && wordDict.count(s.substr(i - l, l))) { + canBreak[i] = true; + break; + } + } + } + + return canBreak[n]; + } +}; diff --git a/C++/word-pattern-ii.cpp b/C++/word-pattern-ii.cpp new file mode 100644 index 000000000..bf679e586 --- /dev/null +++ b/C++/word-pattern-ii.cpp @@ -0,0 +1,43 @@ +// Time: O(n * C(n - 1, c - 1)), n is length of str, c is unique count of pattern, +// there are H(n - c, c - 1) = C(n - 1, c - 1) possible splits of string, +// and each one costs O(n) to check if it matches the word pattern. +// Space: O(n + c) + +class Solution { +public: + bool wordPatternMatch(string pattern, string str) { + unordered_map w2p; + unordered_map p2w; + return match(pattern, str, 0, 0, &w2p, &p2w); + } + + bool match(const string &pattern, const string &str, + const int i, const int j, + unordered_map* w2p, + unordered_map* p2w) { + + bool is_match = false; + if (i == pattern.length() && j == str.length()) { + is_match = true; + } else if (i < pattern.length() && j < str.length()) { + const char p = pattern[i]; + if (p2w->count(p)) { + const auto& w = (*p2w)[p]; + if (w == str.substr(j, w.length())) { // Match pattern. + is_match = match(pattern, str, i + 1, j + w.length(), w2p, p2w); + } // Else return false. + } else { + for (int k = j; k < str.length() && !is_match; ++k) { + const string w = str.substr(j, k - j + 1); + if (!w2p->count(w)) { + // Build mapping. Space: O(n + c) + (*w2p)[w] = p, (*p2w)[p] = w; + is_match = match(pattern, str, i + 1, k + 1, w2p, p2w); + w2p->erase(w), p2w->erase(p); + } // Else try longer word. + } + } + } + return is_match; + } +}; diff --git a/C++/word-pattern.cpp b/C++/word-pattern.cpp new file mode 100644 index 000000000..b4a88d415 --- /dev/null +++ b/C++/word-pattern.cpp @@ -0,0 +1,41 @@ +// Time: O(n) +// Space: O(c), c is unique count of pattern + +class Solution { +public: + bool wordPattern(string pattern, string str) { + // Count the words. + int cnt = str.empty() ? 0 : 1; + for (const auto& c : str) { + if (c == ' ') { + ++cnt; + } + } + if (pattern.size() != cnt) { + return false; + } + + unordered_map w2p; + unordered_map p2w; + int i = 0, j = 0; + for (const auto& p : pattern) { + // Get a word at a time without saving all the words. + j = str.find(" ", i); + if (j == string::npos) { + j = str.length(); + } + const string w = str.substr(i, j - i); + + if (!w2p.count(w) && !p2w.count(p)) { + // Build mapping. Space: O(c) + w2p[w] = p; + p2w[p] = w; + } else if (!w2p.count(w) || w2p[w] != p) { + // Contradict mapping. + return false; + } + i = j + 1; + } + return true; + } +}; diff --git a/C++/word-search-ii.cpp b/C++/word-search-ii.cpp new file mode 100644 index 000000000..731c4e73a --- /dev/null +++ b/C++/word-search-ii.cpp @@ -0,0 +1,102 @@ +// Time: O(m * n * h), h is height of trie +// Space: O(26^h) + +class Solution { +private: + struct TrieNode { + bool isString = false; + unordered_map leaves; + + bool Insert(const string& s) { + auto* p = this; + for (const auto& c : s) { + if (p->leaves.find(c) == p->leaves.cend()) { + p->leaves[c] = new TrieNode; + } + p = p->leaves[c]; + } + + // s already existed in this trie. + if (p->isString) { + return false; + } else { + p->isString = true; + return true; + } + } + + ~TrieNode() { + for (auto& kv : leaves) { + if (kv.second) { + delete kv.second; + } + } + } + }; + +public: + /** + * @param board: A list of lists of character + * @param words: A list of string + * @return: A list of string + */ + vector findWords(vector>& board, vector& words) { + unordered_set ret; + vector> visited(board.size(), vector(board[0].size(), false)); + string cur; + TrieNode trie; + for (const auto& word : words) { + trie.Insert(word); + } + + for (int i = 0; i < board.size(); ++i) { + for (int j = 0; j < board[0].size(); ++j) { + findWordsDFS(board, visited, &trie, i, j, cur, ret); + } + } + + return vector(ret.begin(), ret.end()); + } + + void findWordsDFS(vector> &grid, + vector> &visited, + TrieNode *trie, + int i, + int j, + string cur, + unordered_set &ret) { + // Invalid state. + if (!trie || i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) { + return; + } + + // Not in trie or visited. + if (!trie->leaves[grid[i][j] ] || visited[i][j]) { + return; + } + + // Get next trie nodes. + TrieNode *nextNode = trie->leaves[grid[i][j]]; + + // Update current string. + cur.push_back(grid[i][j]); + + // Find the string, add to the answers. + if (nextNode->isString) { + ret.insert(cur); + } + + // Marked as visited. + visited[i][j] = true; + + // Try each direction. + const vector> directions{{0, -1}, {0, 1}, + {-1, 0}, {1, 0}}; + for (const auto& d : directions) { + findWordsDFS(grid, visited, nextNode, + i + d.first, j + d.second, cur, ret); + } + + visited[i][j] = false; + } +}; diff --git a/C++/word-squares.cpp b/C++/word-squares.cpp new file mode 100644 index 000000000..11d66497c --- /dev/null +++ b/C++/word-squares.cpp @@ -0,0 +1,62 @@ +// Time: O(n^2 * n!) +// Space: O(n^2) + +class Solution { +private: + struct TrieNode { + vector indices; + vector children; + TrieNode() : children(26, nullptr) {} + }; + + TrieNode *buildTrie(const vector& words) { + TrieNode *root = new TrieNode(); + for (int j = 0; j < words.size(); ++j) { + TrieNode* t = root; + for (int i = 0; i < words[j].size(); ++i) { + if (!t->children[words[j][i] - 'a']) { + t->children[words[j][i] - 'a'] = new TrieNode(); + } + t = t->children[words[j][i] - 'a']; + t->indices.push_back(j); + } + } + return root; + } + +public: + vector> wordSquares(vector& words) { + vector> result; + + TrieNode *trie = buildTrie(words); + vector curr; + for (const auto& s : words) { + curr.emplace_back(s); + wordSquaresHelper(words, trie, &curr, &result); + curr.pop_back(); + } + + return result; + } + +private: + void wordSquaresHelper(const vector& words, TrieNode *trie, vector *curr, + vector> *result) { + if (curr->size() >= words[0].length()) { + return result->emplace_back(*curr); + } + + TrieNode *node = trie; + for (int i = 0; i < curr->size(); ++i) { + if (!(node = node->children[(*curr)[i][curr->size()] - 'a'])) { + return; + } + } + + for (const auto& i : node->indices) { + curr->emplace_back(words[i]); + wordSquaresHelper(words, trie, curr, result); + curr->pop_back(); + } + } +}; diff --git a/C++/wordBreak.cpp b/C++/wordBreak.cpp deleted file mode 100644 index 4b4d6d9be..000000000 --- a/C++/wordBreak.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Time Complexity: O(n^2) -// Space Complexity: O(n) - -class Solution { - public: - bool wordBreak(string s, unordered_set &dict) { - vector f(s.size() + 1, false); - f[0] = true; // null string - for(int i = 1; i <= s.size(); ++i) { - for(int j = i - 1; j >= 0; --j) { - if(f[j] && dict.find(s.substr(j, i - j)) != dict.end()) { - f[i] = true; - break; - } - } - } - return f[s.size()]; - } -}; diff --git a/C++/zigzag-conversion.cpp b/C++/zigzag-conversion.cpp new file mode 100644 index 000000000..3cb96df9b --- /dev/null +++ b/C++/zigzag-conversion.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + string convert(string s, int numRows) { + if (numRows == 1) { + return s; + } + const int step = 2 * numRows - 2; + string zigzag; + for (int i = 0; i < numRows; ++i) { + for (int j = i; j < s.length(); j += step) { + zigzag.push_back(s[j]); + if (0 < i && i < numRows - 1 && + j + step - 2 * i < s.length()) { + zigzag.push_back(s[j + step - 2 * i]); + } + } + } + return zigzag; + } +}; diff --git a/C++/zigzag-iterator.cpp b/C++/zigzag-iterator.cpp new file mode 100644 index 000000000..c2a470699 --- /dev/null +++ b/C++/zigzag-iterator.cpp @@ -0,0 +1,37 @@ +// Time: O(n) +// Space: O(k) + +class ZigzagIterator { +public: + ZigzagIterator(vector& v1, vector& v2) { + if (!v1.empty()) { + q.emplace(v1.size(), v1.cbegin()); + } + if (!v2.empty()) { + q.emplace(v2.size(), v2.cbegin()); + } + } + + int next() { + const auto len = q.front().first; + const auto it = q.front().second; + q.pop(); + if (len > 1) { + q.emplace(len - 1, it + 1); + } + return *it; + } + + bool hasNext() { + return !q.empty(); + } + +private: + queue::const_iterator>> q; +}; + +/** + * Your ZigzagIterator object will be instantiated and called as such: + * ZigzagIterator i(v1, v2); + * while (i.hasNext()) cout << i.next(); + */ diff --git a/C++/zuma-game.cpp b/C++/zuma-game.cpp new file mode 100644 index 000000000..c038098ba --- /dev/null +++ b/C++/zuma-game.cpp @@ -0,0 +1,74 @@ +// Time: O(b * b! * h!) +// Space: O(b * b! * h!) + +class Solution { +public: + int findMinStep(string board, string hand) { + unordered_map> lookup; + sort(hand.begin(), hand.end()); + int result = findMinStepHelper(board, hand, &lookup); + return result > hand.size() ? -1 : result; + } + +private: + int findMinStepHelper(const string& board, const string& hand, + unordered_map> *lookup) { + if (board.empty()) { + return 0; + } + if (hand.empty()) { + return MAX_STEP; + } + if ((*lookup)[board][hand]) { + return (*lookup)[board][hand]; + } + + int result = MAX_STEP; + for (int i = 0; i < hand.size(); ++i) { + int j = 0; + while (j < board.size()) { + int k = board.find(hand[i], j); + if (k == string::npos) { + break; + } + if (k < board.size() - 1 && board[k] == board[k + 1]) { + string next_board = shrink(board.substr(0, k) + board.substr(k + 2)); + string next_hand = hand.substr(0, i) + hand.substr(i + 1); + result = min(result, findMinStepHelper(next_board, next_hand, lookup) + 1); + ++k; + } else if (i > 0 && hand[i] == hand[i - 1]) { + string next_board = shrink(board.substr(0, k) + board.substr(k + 1)); + string next_hand = hand.substr(0, i - 1) + hand.substr(i + 1); + result = min(result, findMinStepHelper(next_board, next_hand, lookup) + 2); + } + j = k + 1; + } + } + + return (*lookup)[board][hand] = result; + } + + string shrink(const string& s) { // Time: O(n), Space: O(n) + vector> stack; + for (int i = 0, start = 0; i <= s.size(); ++i) { + if (i == s.size() || s[i] != s[start]) { + if (!stack.empty() && stack.back().first == s[start]) { + stack.back().second += i - start; + if (stack.back().second >= 3) { + stack.pop_back(); + } + } else if (!s.empty() && i - start < 3) { + stack.emplace_back(s[start], i - start); + } + start = i; + } + } + string result; + for (const auto& p : stack) { + result += string(p.second, p.first); + } + return result; + } + + static const int MAX_STEP = 6; +}; diff --git a/Golang/add-two-numbers.go b/Golang/add-two-numbers.go new file mode 100644 index 000000000..a344cc633 --- /dev/null +++ b/Golang/add-two-numbers.go @@ -0,0 +1,62 @@ +package leetcode + +// ListNode represents a non-negative number. +// You are given two linked lists representing two non-negative numbers. +// The digits are stored in reverse order and each of their nodes contain a single digit. +// Add the two numbers and return it as a linked list. +// +// Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) +// Output: 7 -> 0 -> 8 +type ListNode struct { + Val int + Next *ListNode +} + +func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { + results := &ListNode{} + node := results + node1 := l1 + node2 := l2 + + overten := false + + for node1 != nil || node2 != nil { + + tmp := 0 + + if node1 != nil { + tmp = tmp + node1.Val + node1 = node1.Next + } + + if node2 != nil { + tmp = tmp + node2.Val + node2 = node2.Next + } + if overten { + tmp++ + } + + if tmp >= 10 { + overten = true + tmp -= 10 + } else { + overten = false + } + + node.Val = tmp + + if node1 != nil || node2 != nil { + node.Next = &ListNode{} + node = node.Next + } + } + + if overten { + node.Next = &ListNode{} + node = node.Next + node.Val = 1 + } + + return results +} diff --git a/Golang/longest-substring-without-repeating-characters.go b/Golang/longest-substring-without-repeating-characters.go new file mode 100644 index 000000000..11dd57570 --- /dev/null +++ b/Golang/longest-substring-without-repeating-characters.go @@ -0,0 +1,34 @@ +package leetcode + +// Given a string, find the length of the longest substring without repeating characters. +// +// Examples: +// Given "abcabcbb", the answer is "abc", which the length is 3. +// Given "bbbbb", the answer is "b", with the length of 1. +// Given "pwwkew", the answer is "wke", with the length of 3. +// Note that the answer must be a substring, "pwke" is a subsequence and not a substring. +// +func lengthOfLongestSubstring(s string) int { + hashmap := map[byte]int{} + max := 0 + for i := range s { + _, ok := hashmap[s[i]] + if !ok { + hashmap[s[i]] = i + if len(hashmap) > max { + max = len(hashmap) + } + } else { + // remove repeated + oldI := hashmap[s[i]] + hashmap[s[i]] = i + + for key, value := range hashmap { + if value < oldI { + delete(hashmap, key) + } + } + } + } + return max +} diff --git a/Golang/two-sum.go b/Golang/two-sum.go new file mode 100644 index 000000000..bdf987986 --- /dev/null +++ b/Golang/two-sum.go @@ -0,0 +1,37 @@ +package leetcode + +import "sort" + +// Given an array of integers, return indices of the two numbers +// such that they add up to a specific target. +// You may assume that each input would have exactly one solution. +// +// Example: +// Given nums = [2, 7, 11, 15], target = 9, +// Because nums[0] + nums[1] = 2 + 7 = 9, +// return [0, 1]. +func TwoSum(nums []int, target int) []int { + + indexs := make([]int, 2) + hash := map[int]int{} + + for i := range nums { + hash[target-nums[i]] = i + } + + for i := range nums { + index, ok := hash[nums[i]] + if ok { + if i == index { + continue + } + indexs[0] = index + indexs[1] = i + sort.Ints(indexs) + break + } + continue + } + + return indexs +} diff --git a/Golang/two-sum_test.go b/Golang/two-sum_test.go new file mode 100644 index 000000000..e6e6c414b --- /dev/null +++ b/Golang/two-sum_test.go @@ -0,0 +1,13 @@ +package leetcode + +import "testing" + +func Test_two_sum(t *testing.T) { + + if result := TwoSum([]int{1, 3, 5}, 4); result[0] != 0 && result[1] != 1 { + t.Errorf("Error") + } + if result := TwoSum([]int{3, 1, 5}, 6); result[0] != 1 && result[1] != 2 { + t.Errorf("Error") + } +} diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..2288c82f8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 https://github.com/kamyu104/LeetCode + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MySQL/average-salary-departments-vs-company.sql b/MySQL/average-salary-departments-vs-company.sql new file mode 100644 index 000000000..7106e85d3 --- /dev/null +++ b/MySQL/average-salary-departments-vs-company.sql @@ -0,0 +1,23 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT department_salary.pay_month, department_id, +CASE + WHEN department_avg < company_avg THEN 'lower' + WHEN department_avg > company_avg THEN 'higher' + ELSE 'same' +END AS comparison +FROM +( + SELECT department_id, AVG(amount) AS department_avg, date_format(pay_date, '%Y-%m') AS pay_month + FROM salary JOIN employee ON salary.employee_id = employee.employee_id + GROUP BY department_id, pay_month +) AS department_salary +JOIN +( + SELECT AVG(amount) AS company_avg, date_format(pay_date, '%Y-%m') AS pay_month + FROM salary + GROUP BY date_format(pay_date, '%Y-%m') +) AS company_salary +ON department_salary.pay_month = company_salary.pay_month +; diff --git a/MySQL/big-countries.sql b/MySQL/big-countries.sql new file mode 100644 index 000000000..5bc687b3b --- /dev/null +++ b/MySQL/big-countries.sql @@ -0,0 +1,27 @@ +# Time: O(n) +# Space: O(1) + +# There is a table World +# +-----------------+------------+------------+--------------+---------------+ +# | name | continent | area | population | gdp | +# +-----------------+------------+------------+--------------+---------------+ +# | Afghanistan | Asia | 652230 | 25500100 | 20343000 | +# | Albania | Europe | 28748 | 2831741 | 12960000 | +# | Algeria | Africa | 2381741 | 37100000 | 188681000 | +# | Andorra | Europe | 468 | 78115 | 3712000 | +# | Angola | Africa | 1246700 | 20609294 | 100990000 | +# +-----------------+------------+------------+--------------+---------------+ +# +# A country is big if it has an area of bigger than 3 million square km or a population of more than 25 million. +# Write a SQL solution to output big countries' name, population and area. +# For example, according to the above table, we should output: +# +--------------+-------------+--------------+ +# | name | population | area | +# +--------------+-------------+--------------+ +# | Afghanistan | 25500100 | 652230 | +# | Algeria | 37100000 | 2381741 | +# +--------------+-------------+--------------+ + +SELECT name, population, area +FROM World +WHERE area > 3000000 OR population > 25000000; diff --git a/MySQL/biggest-single-number.sql b/MySQL/biggest-single-number.sql new file mode 100644 index 000000000..2a195a016 --- /dev/null +++ b/MySQL/biggest-single-number.sql @@ -0,0 +1,19 @@ +# Time: O(n) +# Space: O(n) + +SELECT +IFNULL( + (SELECT + MAX(num) + FROM + (SELECT + num + FROM + number + GROUP BY num + HAVING COUNT(num) = 1 + ORDER BY NULL) AS t + ) + , NULL +) AS num +; diff --git a/MySQL/classes-more-than-5-students.sql b/MySQL/classes-more-than-5-students.sql new file mode 100644 index 000000000..b225427dc --- /dev/null +++ b/MySQL/classes-more-than-5-students.sql @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(n) + +# There is a table courses with columns: student and class +# Please list out all classes which have more than or equal to 5 students. +# For example, the table: +# +---------+------------+ +# | student | class | +# +---------+------------+ +# | A | Math | +# | B | English | +# | C | Math | +# | D | Biology | +# | E | Math | +# | F | Computer | +# | G | Math | +# | H | Math | +# | I | Math | +# +---------+------------+ +# +# Should output: +# +---------+ +# | class | +# +---------+ +# | Math | +# +---------+ +# +# Note: +# The students should not be counted duplicate in each course. + +SELECT class +FROM courses +GROUP BY class +HAVING COUNT(DISTINCT student) >= 5 +ORDER BY NULL; diff --git a/MySQL/consecutive-available-seats.sql b/MySQL/consecutive-available-seats.sql new file mode 100644 index 000000000..79025770a --- /dev/null +++ b/MySQL/consecutive-available-seats.sql @@ -0,0 +1,9 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT DISTINCT c1.seat_id +FROM cinema c1 JOIN cinema c2 + ON ((c1.seat_id = c2.seat_id - 1) OR (c1.seat_id = c2.seat_id + 1)) + AND c1.free = true AND c2.free = true +ORDER BY c1.seat_id +; diff --git a/MySQL/consecutive-numbers.sql b/MySQL/consecutive-numbers.sql index 47026f66f..7d4cc2e27 100644 --- a/MySQL/consecutive-numbers.sql +++ b/MySQL/consecutive-numbers.sql @@ -17,8 +17,9 @@ # For example, given the above Logs table, 1 is the only number that appears consecutively for at least three times. # +# Solution 1 # Write your MySQL query statement below -SELECT DISTINCT(Num) AS ConsecutiveNums +SELECT DISTINCT(Num) AS ConsecutiveNums FROM ( SELECT Num, @@ -27,3 +28,8 @@ FROM ( FROM Logs y, (SELECT @counter:=1, @prev:=NULL) vars ) sq WHERE how_many_cnt_in_a_row >= 3 + +# Solution 2 +SELECT DISTINCT l1.Num as ConsecutiveNums +FROM Logs l1, Logs l2, Logs l3 +WHERE l1.Id + 1 = l2.Id AND l2.Id + 1 = l3.Id AND l1.Num = l2.Num AND l2.Num = l3.Num diff --git "a/MySQL/count-student-number-in-departments\b.sql" "b/MySQL/count-student-number-in-departments\b.sql" new file mode 100644 index 000000000..335c6430d --- /dev/null +++ "b/MySQL/count-student-number-in-departments\b.sql" @@ -0,0 +1,12 @@ +# Time: O(s+dlogd) +# Space: O(d+s) + +SELECT + dept_name, COUNT(student_id) AS student_number +FROM + department + LEFT JOIN + student ON department.dept_id = student.dept_id +GROUP BY department.dept_name +ORDER BY student_number DESC , department.dept_name +; diff --git a/MySQL/customer-placing-the-largest-number-of-orders.sql b/MySQL/customer-placing-the-largest-number-of-orders.sql new file mode 100644 index 000000000..164017d90 --- /dev/null +++ b/MySQL/customer-placing-the-largest-number-of-orders.sql @@ -0,0 +1,19 @@ +# Time: O(n) +# Space: O(n) + +SELECT customer_number +FROM orders +GROUP BY customer_number +HAVING COUNT(order_number) = + (SELECT MAX(*) + FROM + (SELECT COUNT(*) AS cnt + FROM + orders + GROUP BY customer_number + ORDER BY NULL + ) AS cnt_tbl + ) +ORDER BY NULL +LIMIT 1 +; diff --git a/MySQL/customers-who-never-order.sql b/MySQL/customers-who-never-order.sql new file mode 100644 index 000000000..c63d41aaa --- /dev/null +++ b/MySQL/customers-who-never-order.sql @@ -0,0 +1,42 @@ +# Time: O(n^2) +# Space: O(1) +# +# Suppose that a website contains two tables, the Customers table and the Orders table. Write a SQL query to find all customers who never order anything. +# +# Table: Customers. +# +# +----+-------+ +# | Id | Name | +# +----+-------+ +# | 1 | Joe | +# | 2 | Henry | +# | 3 | Sam | +# | 4 | Max | +# +----+-------+ +# Table: Orders. +# +# +----+------------+ +# | Id | CustomerId | +# +----+------------+ +# | 1 | 3 | +# | 2 | 1 | +# +----+------------+ +# Using the above tables as example, return the following: +# +# +-----------+ +# | Customers | +# +-----------+ +# | Henry | +# | Max | +# +-----------+ +# + +# Time: O(n^2) +# Space: O(1) +# Write your MySQL query statement below +SELECT Name AS Customers FROM Customers WHERE Id NOT IN (SELECT CustomerId FROM Orders) + +# Time: O(n^2) +# Space: O(n) +# Write your MySQL query statement below +SELECT Customers.Name AS Customers FROM (Customers LEFT JOIN Orders ON Customers.Id = Orders.CustomerId) WHERE Orders.CustomerId IS NULL diff --git a/MySQL/delete-duplicate-emails.sql b/MySQL/delete-duplicate-emails.sql new file mode 100644 index 000000000..b098426ca --- /dev/null +++ b/MySQL/delete-duplicate-emails.sql @@ -0,0 +1,28 @@ +# Time: O(n^2) +# Space: O(n) +# +# Write a SQL query to delete all duplicate email entries in a table named Person, +# keeping only unique emails based on its smallest Id. +# +# +----+------------------+ +# | Id | Email | +# +----+------------------+ +# | 1 | john@example.com | +# | 2 | bob@example.com | +# | 3 | john@example.com | +# +----+------------------+ +# Id is the primary key column for this table. +# For example, after running your query, the above Person table should have the following rows: +# +# +----+------------------+ +# | Id | Email | +# +----+------------------+ +# | 1 | john@example.com | +# | 2 | bob@example.com | +# +----+------------------+ +# + +# Write your MySQL query statement below +DELETE p1 +FROM Person p1, Person p2 +WHERE p1.Email = p2.Email AND p1.Id > p2.Id diff --git a/MySQL/department-highest-salary.sql b/MySQL/department-highest-salary.sql new file mode 100644 index 000000000..69c88f734 --- /dev/null +++ b/MySQL/department-highest-salary.sql @@ -0,0 +1,42 @@ +# Time: O(n^2) +# Space: O(n) +# +# The Employee table holds all employees. Every employee has an Id, a salary, and there is also a column for the department Id. +# +# +----+-------+--------+--------------+ +# | Id | Name | Salary | DepartmentId | +# +----+-------+--------+--------------+ +# | 1 | Joe | 70000 | 1 | +# | 2 | Henry | 80000 | 2 | +# | 3 | Sam | 60000 | 2 | +# | 4 | Max | 90000 | 1 | +# +----+-------+--------+--------------+ +# The Department table holds all departments of the company. +# +# +----+----------+ +# | Id | Name | +# +----+----------+ +# | 1 | IT | +# | 2 | Sales | +# +----+----------+ +# Write a SQL query to find employees who have the highest salary in each of the departments. For the above tables, Max has the highest salary in the IT department and Henry has the highest salary in the Sales department. +# +# +------------+----------+--------+ +# | Department | Employee | Salary | +# +------------+----------+--------+ +# | IT | Max | 90000 | +# | Sales | Henry | 80000 | +# +------------+----------+--------+ +# +# Write your MySQL query statement below +SELECT d.Department AS Department, e.Name AS Employee, d.Salary AS Salary +FROM (SELECT Department.Id AS DepartmentId, Department.Name AS Department, emp.Salary AS Salary + FROM Department JOIN (SELECT DepartmentId, MAX(Salary) AS Salary FROM Employee GROUP BY DepartmentId) emp + ON Department.Id = emp.DepartmentId) d + JOIN Employee e + ON e.DepartmentId = d.DepartmentId and e.Salary = d.Salary + +# Write your MySQL query statement below +SELECT Department.Name AS Department, Employee.Name AS Employee, Employee.Salary AS Salary +FROM Department JOIN Employee ON Employee.DepartmentId = Department.Id +WHERE Employee.Salary IN (SELECT MAX(e.Salary) FROM Employee e WHERE e.DepartmentId = Employee.DepartmentId) diff --git a/MySQL/department-top-three-salaries.sql b/MySQL/department-top-three-salaries.sql new file mode 100644 index 000000000..337c3ff81 --- /dev/null +++ b/MySQL/department-top-three-salaries.sql @@ -0,0 +1,41 @@ +# Time: O(n^2) +# Space: O(n) +# +# The Employee table holds all employees. Every employee has an Id, and there is also a column for the department Id. +# +# +----+-------+--------+--------------+ +# | Id | Name | Salary | DepartmentId | +# +----+-------+--------+--------------+ +# | 1 | Joe | 70000 | 1 | +# | 2 | Henry | 80000 | 2 | +# | 3 | Sam | 60000 | 2 | +# | 4 | Max | 90000 | 1 | +# | 5 | Janet | 69000 | 1 | +# | 6 | Randy | 85000 | 1 | +# +----+-------+--------+--------------+ +# The Department table holds all departments of the company. +# +# +----+----------+ +# | Id | Name | +# +----+----------+ +# | 1 | IT | +# | 2 | Sales | +# +----+----------+ +# Write a SQL query to find employees who earn the top three salaries in each of the department. For the above tables, your SQL query should return the following rows. +# +# +------------+----------+--------+ +# | Department | Employee | Salary | +# +------------+----------+--------+ +# | IT | Max | 90000 | +# | IT | Randy | 85000 | +# | IT | Joe | 70000 | +# | Sales | Henry | 80000 | +# | Sales | Sam | 60000 | +# +------------+----------+--------+ + +# Write your MySQL query statement below +SELECT D.Name AS Department, E.Name AS Employee, E.Salary AS Salary +FROM Employee E INNER JOIN Department D ON E.DepartmentId = D.Id +WHERE (SELECT COUNT(DISTINCT(Salary)) FROM Employee + WHERE DepartmentId = E.DepartmentId AND Salary > E.Salary) < 3 +ORDER by E.DepartmentId, E.Salary DESC; diff --git a/MySQL/duplicate-emails.sql b/MySQL/duplicate-emails.sql new file mode 100644 index 000000000..836ad0490 --- /dev/null +++ b/MySQL/duplicate-emails.sql @@ -0,0 +1,24 @@ +# Time: O(n^2) +# Space: O(n) +# +# Write a SQL query to find all duplicate emails in a table named Person. +# +# +----+---------+ +# | Id | Email | +# +----+---------+ +# | 1 | a@b.com | +# | 2 | c@d.com | +# | 3 | a@b.com | +# +----+---------+ +# For example, your query should return the following for the above table: +# +# +---------+ +# | Email | +# +---------+ +# | a@b.com | +# +---------+ +# Note: All emails are in lowercase. +# + +# Write your MySQL query statement below +SELECT Email FROM Person GROUP BY Email HAVING COUNT(*) > 1 diff --git a/MySQL/employee-bonus.sql b/MySQL/employee-bonus.sql new file mode 100644 index 000000000..706ef70d9 --- /dev/null +++ b/MySQL/employee-bonus.sql @@ -0,0 +1,14 @@ +# Time: O(n) if hash join, O(nlogn) if merge join +# Space: O(n) + +# https://www.quora.com/What-is-time-complexity-of-Join-algorithm-in-Database + +SELECT + Employee.name, Bonus.bonus +FROM + Employee + LEFT JOIN + Bonus ON Employee.empid = Bonus.empid +WHERE + Bonus.bonus < 1000 OR Bonus.bonus IS NULL +; diff --git a/MySQL/employees-earning-more-than-their-managers.sql b/MySQL/employees-earning-more-than-their-managers.sql new file mode 100644 index 000000000..eaafe2a00 --- /dev/null +++ b/MySQL/employees-earning-more-than-their-managers.sql @@ -0,0 +1,37 @@ +# Time: O(n^2) +# Space: O(1) +# +# The Employee table holds all employees including their managers. Every employee has an Id, and there is also a column for the manager Id. +# +# +----+-------+--------+-----------+ +# | Id | Name | Salary | ManagerId | +# +----+-------+--------+-----------+ +# | 1 | Joe | 70000 | 3 | +# | 2 | Henry | 80000 | 4 | +# | 3 | Sam | 60000 | NULL | +# | 4 | Max | 90000 | NULL | +# +----+-------+--------+-----------+ +# Given the Employee table, write a SQL query that finds out employees who earn more than their managers. For the above table, Joe is the only employee who earns more than his manager. +# +# +----------+ +# | Employee | +# +----------+ +# | Joe | +# +----------+ +# + +# Time: O(n^2) +# Space: O(n) +# Write your MySQL query statement below +SELECT e.Name AS Employee FROM Employee e LEFT JOIN Employee b + ON e.ManagerId=b.Id + WHERE e.Salary > b.Salary + +# Time: O(n^2) +# Space: O(1) +# Write your MySQL query statement below +SELECT Name AS Employee + FROM Employee e + WHERE e.ManagerId IS NOT NULL AND e.Salary > (SELECT Salary + FROM Employee + WHERE e.ManagerId = Id) diff --git a/MySQL/exchange-seats.sql b/MySQL/exchange-seats.sql new file mode 100644 index 000000000..1a80d7664 --- /dev/null +++ b/MySQL/exchange-seats.sql @@ -0,0 +1,40 @@ +# Time: O(nlogn) +# Space: O(n) + +# Mary is a teacher in a middle school and she has a table seat storing +# students' names and their corresponding seat ids. +# +# The column id is continuous increment. +# Mary wants to change seats for the adjacent students. +# Can you write a SQL query to output the result for Mary? +# +---------+---------+ +# | id | student | +# +---------+---------+ +# | 1 | Abbot | +# | 2 | Doris | +# | 3 | Emerson | +# | 4 | Green | +# | 5 | Jeames | +# +---------+---------+ +# +# For the sample input, the output is: +# +---------+---------+ +# | id | student | +# +---------+---------+ +# | 1 | Doris | +# | 2 | Abbot | +# | 3 | Green | +# | 4 | Emerson | +# | 5 | Jeames | +# +---------+---------+ +# +# Note: +# If the number of students is odd, there is no need to change the last one's seat. + +SELECT + s1.id, COALESCE(s2.student, s1.student) AS student +FROM + seat s1 + LEFT JOIN + seat s2 ON ((s1.id + 1) ^ 1) - 1 = s2.id +ORDER BY s1.id; diff --git a/MySQL/find-cumulative-salary-of-an-employee.sql b/MySQL/find-cumulative-salary-of-an-employee.sql new file mode 100644 index 000000000..be723db8a --- /dev/null +++ b/MySQL/find-cumulative-salary-of-an-employee.sql @@ -0,0 +1,22 @@ +# Time: O(n^2) +# Space: O(n) + +SELECT EA.Id, + EA.Month, + SUM(EB.salary) AS Salary +FROM (SELECT E1.* + FROM employee E1 + LEFT JOIN (SELECT id, + MAX(month) AS month + FROM employee + GROUP BY id) E2 + ON E1.id = E2.id + WHERE E1.month < E2.month) EA + LEFT JOIN employee EB + ON EA.id = EB.id +WHERE EA.month - 2 <= EB.month + AND EB.month <= EA.month +GROUP BY EA.id, + EA.month +ORDER BY EA.id, + month DESC diff --git a/MySQL/find-customer-referee.sql b/MySQL/find-customer-referee.sql new file mode 100644 index 000000000..4364ed01d --- /dev/null +++ b/MySQL/find-customer-referee.sql @@ -0,0 +1,6 @@ +# Time: O(n) +# Space: O(1) + +SELECT name +FROM customer +WHERE referee_id is NULL OR referee_id != 2; diff --git a/MySQL/find-median-given-frequency-of-numbers.sql b/MySQL/find-median-given-frequency-of-numbers.sql new file mode 100644 index 000000000..6007b846b --- /dev/null +++ b/MySQL/find-median-given-frequency-of-numbers.sql @@ -0,0 +1,15 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT AVG(n.Number) AS median +FROM Numbers n LEFT JOIN +( +SELECT Number, @prev := @count AS prevNumber, (@count := @count + Frequency) AS countNumber +FROM Numbers, +(SELECT @count := 0, @prev := 0, @total := (SELECT SUM(Frequency) FROM Numbers)) temp ORDER BY Number +) n2 +ON n.Number = n2.Number +WHERE +(prevNumber < floor((@total+1)/2) AND countNumber >= floor((@total+1)/2)) +OR +(prevNumber < floor((@total+2)/2) AND countNumber >= floor((@total+2)/2)) diff --git a/MySQL/friend-requests-i-overall-acceptance-rate.sql b/MySQL/friend-requests-i-overall-acceptance-rate.sql new file mode 100644 index 000000000..5ca34216d --- /dev/null +++ b/MySQL/friend-requests-i-overall-acceptance-rate.sql @@ -0,0 +1,11 @@ +# Time: O(rlogr + aloga) +# Space: O(r + a) + +SELECT +ROUND( + IFNULL( + (SELECT COUNT(*) FROM (SELECT DISTINCT requester_id, accepter_id FROM request_accepted) AS r) + / + (SELECT COUNT(*) FROM (SELECT DISTINCT sender_id, send_to_id FROM friend_request) AS a), + 0) +, 2) AS accept_rate; diff --git a/MySQL/friend-requests-ii-who-has-the-most-friends.sql b/MySQL/friend-requests-ii-who-has-the-most-friends.sql new file mode 100644 index 000000000..baff9f17c --- /dev/null +++ b/MySQL/friend-requests-ii-who-has-the-most-friends.sql @@ -0,0 +1,14 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT ids as id, COUNT(*) AS num + FROM + ( + SELECT requester_id AS ids FROM request_accepted + UNION ALL + SELECT accepter_id FROM request_accepted + ) AS tmp +GROUP BY ids +ORDER BY num DESC +LIMIT 1 +; diff --git a/MySQL/get-highest-answer-rate-question.sql b/MySQL/get-highest-answer-rate-question.sql new file mode 100644 index 000000000..e39d30a99 --- /dev/null +++ b/MySQL/get-highest-answer-rate-question.sql @@ -0,0 +1,10 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT + question_id AS 'survey_log' +FROM + survey_log +GROUP BY question_id +ORDER BY COUNT(answer_id) / COUNT(IF(action = 'show', 1, 0)) DESC +LIMIT 1; diff --git a/MySQL/human-traffic-of-stadium.sql b/MySQL/human-traffic-of-stadium.sql new file mode 100644 index 000000000..fcf908393 --- /dev/null +++ b/MySQL/human-traffic-of-stadium.sql @@ -0,0 +1,16 @@ +# Time: O(n^3) +# Space: O(n^3) + +SELECT DISTINCT s1.* +FROM stadium AS s1, stadium AS s2, stadium AS s3 +WHERE s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100 +AND +( + (s2.id = s1.id + 1 AND s3.id = s2.id + 1 AND s3.id = s1.id + 2) -- s1, s2, s3 + OR + (s1.id = s2.id + 1 AND s3.id = s1.id + 1 AND s3.id = s2.id + 2) -- s2, s1, s3 + OR + (s3.id = s2.id + 1 AND s1.id = s3.id + 1 AND s1.id = s2.id + 2) -- s2, s3, s1 +) +ORDER BY s1.id +; diff --git a/MySQL/investments-in-2016.sql b/MySQL/investments-in-2016.sql new file mode 100644 index 000000000..6d9e1ad1e --- /dev/null +++ b/MySQL/investments-in-2016.sql @@ -0,0 +1,29 @@ +# Time: O(n^2) +# Space: O(n) + +SELECT + SUM(insurance.TIV_2016) AS TIV_2016 +FROM + insurance +WHERE + insurance.TIV_2015 IN + ( + SELECT + TIV_2015 + FROM + insurance + GROUP BY TIV_2015 + HAVING COUNT(*) > 1 + ORDER BY NULL + ) + AND CONCAT(LAT, LON) IN + ( + SELECT + CONCAT(LAT, LON) + FROM + insurance + GROUP BY LAT , LON + HAVING COUNT(*) = 1 + ORDER BY NULL + ) +; diff --git a/MySQL/managers-with-at-least-5-direct-reports.sql b/MySQL/managers-with-at-least-5-direct-reports.sql new file mode 100644 index 000000000..f2fc77644 --- /dev/null +++ b/MySQL/managers-with-at-least-5-direct-reports.sql @@ -0,0 +1,16 @@ +# Time: O(n) +# Space: O(n) + +SELECT + Name +FROM + Employee AS t1 INNER JOIN + (SELECT + ManagerId + FROM + Employee + GROUP BY ManagerId + HAVING COUNT(ManagerId) >= 5 + ORDER BY NULL) AS t2 + ON t1.Id = t2.ManagerId +; diff --git a/MySQL/median-employee-salary.sql b/MySQL/median-employee-salary.sql new file mode 100644 index 000000000..29bd42dbf --- /dev/null +++ b/MySQL/median-employee-salary.sql @@ -0,0 +1,14 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT Id, Company, Salary FROM +( +SELECT e.Id, e.Salary, e.Company, IF (@Prev = e.Company , @Rank := @Rank + 1, @Rank := 1) AS Rank, @Prev := e.Company +FROM Employee e , (SELECT @Rank := 0, @prev := 0) AS Temp ORDER BY e.Company, e.Salary, e.Id +) Ranking +INNER JOIN +( +SELECT COUNT(*) AS TotalCount, Company AS Name FROM Employee e2 GROUP BY e2.Company +) CompanyCount +ON CompanyCount.Name = Ranking.Company +WHERE Rank = floor((TotalCount+1)/2) OR Rank = floor((TotalCount+2)/2) diff --git a/MySQL/not-boring-movies.sql b/MySQL/not-boring-movies.sql new file mode 100644 index 000000000..765a9dbc8 --- /dev/null +++ b/MySQL/not-boring-movies.sql @@ -0,0 +1,31 @@ +# Time: O(nlogn) +# Space: O(1) + +# X city opened a new cinema, many people would like to go to this cinema. +# The cinema also gives out a poster indicating the movies’ ratings and descriptions. +# +# Please write a SQL query to output movies with an odd numbered ID and +# a description that is not 'boring'. Order the result by rating. +# +# For example, table cinema: +# +---------+-----------+--------------+-----------+ +# | id | movie | description | rating | +# +---------+-----------+--------------+-----------+ +# | 1 | War | great 3D | 8.9 | +# | 2 | Science | fiction | 8.5 | +# | 3 | irish | boring | 6.2 | +# | 4 | Ice song | Fantacy | 8.6 | +# | 5 | House card| Interesting| 9.1 | +# +---------+-----------+--------------+-----------+ +# +# For the example above, the output should be: +# +---------+-----------+--------------+-----------+ +# | id | movie | description | rating | +# +---------+-----------+--------------+-----------+ +# | 5 | House card| Interesting| 9.1 | +# | 1 | War | great 3D | 8.9 | +# +---------+-----------+--------------+-----------+ + +SELECT * FROM cinema +WHERE id % 2 != 0 and description != 'boring' +ORDER BY rating DESC; diff --git a/MySQL/rising-temperature.sql b/MySQL/rising-temperature.sql new file mode 100644 index 000000000..91c25d228 --- /dev/null +++ b/MySQL/rising-temperature.sql @@ -0,0 +1,28 @@ +# Time: O(n^2) +# Space: O(n) +# +# Given a Weather table, write a SQL query to find all dates' +# Ids with higher temperature compared to its previous (yesterday's) dates. +# +# +---------+------------+------------------+ +# | Id(INT) | Date(DATE) | Temperature(INT) | +# +---------+------------+------------------+ +# | 1 | 2015-01-01 | 10 | +# | 2 | 2015-01-02 | 25 | +# | 3 | 2015-01-03 | 20 | +# | 4 | 2015-01-04 | 30 | +# +---------+------------+------------------+ +# For example, return the following Ids for the above Weather table: +# +----+ +# | Id | +# +----+ +# | 2 | +# | 4 | +# +----+ +# + +# Write your MySQL query statement below +SELECT wt1.Id +FROM Weather wt1, Weather wt2 +WHERE wt1.Temperature > wt2.Temperature AND + TO_DAYS(wt1.DATE)-TO_DAYS(wt2.DATE)=1; diff --git a/MySQL/sales-person.sql b/MySQL/sales-person.sql new file mode 100644 index 000000000..9a008d568 --- /dev/null +++ b/MySQL/sales-person.sql @@ -0,0 +1,17 @@ +# Time: O(s * o) +# Space: O(s + o) + +SELECT + s.name +FROM + salesperson AS s +WHERE + s.sales_id NOT IN (SELECT + o.sales_id + FROM + orders AS o + LEFT JOIN + company AS c ON o.com_id = c.com_id + WHERE + c.name = 'RED') +; diff --git a/MySQL/second-degree-follower.sql b/MySQL/second-degree-follower.sql new file mode 100644 index 000000000..3fa3462c2 --- /dev/null +++ b/MySQL/second-degree-follower.sql @@ -0,0 +1,7 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT f1.follower, COUNT(DISTINCT f2.follower) AS num +FROM follow f1 +JOIN follow f2 ON f1.follower = f2.followee +GROUP BY f1.follower diff --git a/MySQL/second-highest-salary.sql b/MySQL/second-highest-salary.sql index 0a1a3e1c7..272ee4713 100644 --- a/MySQL/second-highest-salary.sql +++ b/MySQL/second-highest-salary.sql @@ -1,7 +1,7 @@ # Time: O(n) # Space: O(1) # -# Write a SQL query to get the second highest salary from the Employee table. +# Write a SQL query to get the second highest salary from the Employee table. Alias Salary as SecondHighestSalary. # # +----+--------+ # | Id | Salary | @@ -13,5 +13,6 @@ # For example, given the above Employee table, the second highest salary is 200. If there is no second highest salary, then the query should return null. # # Write your MySQL query statement below -SELECT MAX(Salary) FROM Employee -WHERE Salary NOT IN (SELECT MAX(Salary) FROM Employee) +SELECT (SELECT MAX(Salary) FROM Employee WHERE Salary NOT IN (SELECT MAX(Salary) FROM Employee)) SecondHighestSalary; +# or +SELECT (SELECT Salary FROM Employee GROUP BY Salary ORDER BY Salary DESC LIMIT 1,1) SecondHighestSalary; diff --git a/MySQL/shortest-distance-in-a-line.sql b/MySQL/shortest-distance-in-a-line.sql new file mode 100644 index 000000000..41b702618 --- /dev/null +++ b/MySQL/shortest-distance-in-a-line.sql @@ -0,0 +1,30 @@ +# Time: O(nlogn) +# Space: O(n) +SET @prev := -100000000; +SELECT MIN(diff) AS shortest +FROM (SELECT (x - @prev) AS diff, @prev := x + FROM (SELECT * + FROM point + ORDER BY x) AS t1 + ) AS t2 +; + +# Time: O(nlogn) +# Space: O(n) +SELECT MIN(P1.x - P2.x) AS shortest +FROM (SELECT @id1:=0, @id2:=0) AS t, + (SELECT @id1:=@id1+1 AS id, x FROM point ORDER BY x) AS P1 + JOIN + (SELECT @id2:=@id2+1 AS id, x FROM point ORDER BY x) AS P2 + ON P1.id = P2.id + 1 +WHERE P1.id > 1; + +# Time: O(n^2) +# Space: O(n) +SELECT + MIN(p2.x - p1.x) AS shortest +FROM + point p1 + JOIN + point p2 ON p1.x < p2.x +; diff --git a/MySQL/shortest-distance-in-a-plane.sql b/MySQL/shortest-distance-in-a-plane.sql new file mode 100644 index 000000000..374363906 --- /dev/null +++ b/MySQL/shortest-distance-in-a-plane.sql @@ -0,0 +1,10 @@ +# Time: O(n^2) +# Space: O(n^2) + +SELECT + ROUND(SQRT(MIN((POW(p1.x - p2.x, 2) + POW(p1.y - p2.y, 2)))),2) AS shortest +FROM + point_2d p1 + JOIN + point_2d p2 ON (p1.x < p2.x) OR (p1.x = p2.x AND p1.y < p2.y) +; diff --git a/MySQL/students-report-by-geography.sql b/MySQL/students-report-by-geography.sql new file mode 100644 index 000000000..30186537d --- /dev/null +++ b/MySQL/students-report-by-geography.sql @@ -0,0 +1,31 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT + America, Asia, Europe +FROM + (SELECT @as:=0, @am:=0, @eu:=0) t, + (SELECT + @am:=@am + 1 AS amid, name AS America + FROM + student + WHERE + continent = 'America' + ORDER BY America) AS t1 + LEFT JOIN + (SELECT + @as:=@as + 1 AS asid, name AS Asia + FROM + student + WHERE + continent = 'Asia' + ORDER BY Asia) AS t2 ON amid = asid + LEFT JOIN + (SELECT + @eu:=@eu + 1 AS euid, name AS Europe + FROM + student + WHERE + continent = 'Europe' + ORDER BY Europe) AS t3 ON amid = euid +; diff --git a/MySQL/swap-salary.sql b/MySQL/swap-salary.sql new file mode 100644 index 000000000..0d468a90d --- /dev/null +++ b/MySQL/swap-salary.sql @@ -0,0 +1,23 @@ +# Time: O(n) +# Space: O(1) + +# Given a table salary, such as the one below, that has m=male and f=female values. +# Swap all f and m values (i.e., change all f values to m and vice versa) with a single update query and no intermediate temp table. +# +# For example: +# | id | name | sex | salary | +# |----|------|-----|--------| +# | 1 | A | m | 2500 | +# | 2 | B | f | 1500 | +# | 3 | C | m | 5500 | +# | 4 | D | f | 500 | +# +# After running your query, the above salary table should have the following rows: +# | id | name | sex | salary | +# |----|------|-----|--------| +# | 1 | A | f | 2500 | +# | 2 | B | m | 1500 | +# | 3 | C | f | 5500 | +# | 4 | D | m | 500 | + +UPDATE salary SET sex = IF(sex = 'm', 'f', 'm') diff --git a/MySQL/tree-node.sql b/MySQL/tree-node.sql new file mode 100644 index 000000000..a432b325d --- /dev/null +++ b/MySQL/tree-node.sql @@ -0,0 +1,11 @@ +# Time: O(n^2) +# Space: O(n) + +SELECT + atree.id, + IF(ISNULL(atree.p_id), + 'Root', + IF(atree.id IN (SELECT p_id FROM tree), 'Inner','Leaf')) AS Type +FROM + tree AS atree +ORDER BY atree.id diff --git a/MySQL/triangle-judgement.sql b/MySQL/triangle-judgement.sql new file mode 100644 index 000000000..996d7dbc7 --- /dev/null +++ b/MySQL/triangle-judgement.sql @@ -0,0 +1,6 @@ +# Time: O(n) +# Space: O(1) + +SELECT *, + IF (x+y>z AND x+z>y AND y+z>x, "Yes","No") AS triangle +FROM triangle; diff --git a/MySQL/trips-and-users.sql b/MySQL/trips-and-users.sql new file mode 100644 index 000000000..751ad9b5c --- /dev/null +++ b/MySQL/trips-and-users.sql @@ -0,0 +1,56 @@ +# Time: O((t * u) + tlogt) +# Space: O(t) +# +# The Trips table holds all taxi trips. Each trip has a unique Id, while Client_Id and Driver_Id +# are both foreign keys to the Users_Id at the Users table. Status is an ENUM type of +# (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’). +# +# +----+-----------+-----------+---------+--------------------+----------+ +# | Id | Client_Id | Driver_Id | City_Id | Status |Request_at| +# +----+-----------+-----------+---------+--------------------+----------+ +# | 1 | 1 | 10 | 1 | completed |2013-10-01| +# | 2 | 2 | 11 | 1 | cancelled_by_driver|2013-10-01| +# | 3 | 3 | 12 | 6 | completed |2013-10-01| +# | 4 | 4 | 13 | 6 | cancelled_by_client|2013-10-01| +# | 5 | 1 | 10 | 1 | completed |2013-10-02| +# | 6 | 2 | 11 | 6 | completed |2013-10-02| +# | 7 | 3 | 12 | 6 | completed |2013-10-02| +# | 8 | 2 | 12 | 12 | completed |2013-10-03| +# | 9 | 3 | 10 | 12 | completed |2013-10-03| +# | 10 | 4 | 13 | 12 | cancelled_by_driver|2013-10-03| +# +----+-----------+-----------+---------+--------------------+----------+ +# The Users table holds all users. Each user has an unique Users_Id, and Role is an ENUM type of +# (‘client’, ‘driver’, ‘partner’). +# +# +----------+--------+--------+ +# | Users_Id | Banned | Role | +# +----------+--------+--------+ +# | 1 | No | client | +# | 2 | Yes | client | +# | 3 | No | client | +# | 4 | No | client | +# | 10 | No | driver | +# | 11 | No | driver | +# | 12 | No | driver | +# | 13 | No | driver | +# +----------+--------+--------+ +# Write a SQL query to find the cancellation rate of requests made by unbanned clients between +# Oct 1, 2013 and Oct 3, 2013. For the above tables, your SQL query should return the following +# rows with the cancellation rate being rounded to two decimal places. +# +# +------------+-------------------+ +# | Day | Cancellation Rate | +# +------------+-------------------+ +# | 2013-10-01 | 0.33 | +# | 2013-10-02 | 0.00 | +# | 2013-10-03 | 0.50 | +# +------------+-------------------+ +# +select +t.Request_at Day, +round(sum(case when t.Status = 'completed' then 0 else 1 end) / count(*), 2) Rate +from Trips t +inner join Users u +on t.Client_Id = u.Users_Id and u.Banned = 'No' +where t.Request_at between '2013-10-01' and '2013-10-03' +group by t.Request_at diff --git a/MySQL/winning-candidate.sql b/MySQL/winning-candidate.sql new file mode 100644 index 000000000..ec491535d --- /dev/null +++ b/MySQL/winning-candidate.sql @@ -0,0 +1,18 @@ +# Time: O(nlogn) +# Space: O(n) + +SELECT + name AS Name +FROM + Candidate + JOIN + (SELECT + Candidateid + FROM + Vote + GROUP BY Candidateid + ORDER BY COUNT(*) DESC + LIMIT 1) AS Winner +WHERE + Candidate.id = Winner.Candidateid +; diff --git a/Python/01-matrix.py b/Python/01-matrix.py new file mode 100644 index 000000000..16934096d --- /dev/null +++ b/Python/01-matrix.py @@ -0,0 +1,61 @@ +# Time: O(m * n) +# Space: O(m * n) + +# Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell. +# The distance between two adjacent cells is 1. +# +# Example 1: +# +# Input: +# 0 0 0 +# 0 1 0 +# 0 0 0 +# +# Output: +# 0 0 0 +# 0 1 0 +# 0 0 0 +# +# Example 2: +# +# Input: +# 0 0 0 +# 0 1 0 +# 1 1 1 +# +# Output: +# 0 0 0 +# 0 1 0 +# 1 2 1 +# +# Note: +# The number of elements of the given matrix will not exceed 10,000. +# There are at least one 0 in the given matrix. +# The cells are adjacent in only four directions: up, down, left and right. + +class Solution(object): + def updateMatrix(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: List[List[int]] + """ + queue = collections.deque([]) + for i in xrange(len(matrix)): + for j in xrange(len(matrix[0])): + if matrix[i][j] == 0: + queue.append((i, j)) + else: + matrix[i][j] = float("inf") + + dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)] + while queue: + cell = queue.popleft() + for dir in dirs: + i, j = cell[0]+dir[0], cell[1]+dir[1] + if not (0 <= i < len(matrix)) or not (0 <= j < len(matrix[0])) or \ + matrix[i][j] <= matrix[cell[0]][cell[1]]+1: + continue + queue.append((i, j)) + matrix[i][j] = matrix[cell[0]][cell[1]]+1 + + return matrix diff --git a/Python/1-bit-and-2-bit-characters.py b/Python/1-bit-and-2-bit-characters.py new file mode 100644 index 000000000..a92f26b67 --- /dev/null +++ b/Python/1-bit-and-2-bit-characters.py @@ -0,0 +1,41 @@ +# Time: O(n) +# Space: O(1) + +# We have two special characters. The first character can be represented by one bit 0. +# The second character can be represented by two bits (10 or 11). +# +# Now given a string represented by several bits. Return whether the last character must +# be a one-bit character or not. The given string will always end with a zero. +# +# Example 1: +# Input: +# bits = [1, 0, 0] +# Output: True +# Explanation: +# The only way to decode it is two-bit character and one-bit character. +# So the last character is one-bit character. +# +# Example 2: +# Input: +# bits = [1, 1, 1, 0] +# Output: False +# Explanation: +# The only way to decode it is two-bit character and two-bit character. +# So the last character is NOT one-bit character. +# Note: +# +# 1 <= len(bits) <= 1000. +# bits[i] is always 0 or 1. + +class Solution(object): + def isOneBitCharacter(self, bits): + """ + :type bits: List[int] + :rtype: bool + """ + parity = 0 + for i in reversed(xrange(len(bits)-1)): + if bits[i] == 0: + break + parity ^= bits[i] + return parity == 0 diff --git a/Python/132-pattern.py b/Python/132-pattern.py new file mode 100644 index 000000000..0ad03e480 --- /dev/null +++ b/Python/132-pattern.py @@ -0,0 +1,45 @@ +# Time: O(n) +# Space: O(n) + +# Given a sequence of n integers a1, a2, ..., an, +# a 132 pattern is a subsequence ai, aj, ak such that i < j < k and +# ai < ak < aj. Design an algorithm that takes a list of n numbers as +# input and checks whether there is a 132 pattern in the list. +# +# Note: n will be less than 15,000. +# +# Example 1: +# Input: [1, 2, 3, 4] +# +# Output: False +# +# Explanation: There is no 132 pattern in the sequence. +# Example 2: +# Input: [3, 1, 4, 2] +# +# Output: True +# +# Explanation: There is a 132 pattern in the sequence: [1, 4, 2]. +# Example 3: +# Input: [-1, 3, 2, 0] +# +# Output: True +# +# Explanation: There are three 132 patterns in the sequence: [-1, 3, 2], [-1, 3, 0] and [-1, 2, 0]. + +class Solution(object): + def find132pattern(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + ak = float("-inf") + st = [] + for i in reversed(xrange(len(nums))): + if nums[i] < ak: + return True + else: + while st and nums[i] > st[-1]: + ak = st.pop() + st.append(nums[i]) + return False diff --git a/Python/2-keys-keyboard.py b/Python/2-keys-keyboard.py new file mode 100644 index 000000000..24282da4d --- /dev/null +++ b/Python/2-keys-keyboard.py @@ -0,0 +1,40 @@ +# Time: O(sqrt(n)) +# Space: O(1) + +# Initially on a notepad only one character 'A' is present. +# You can perform two operations on this notepad for each step: +# +# Copy All: You can copy all the characters present on the notepad (partial copy is not allowed). +# Paste: You can paste the characters which are copied last time. +# Given a number n. +# You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. +# Output the minimum number of steps to get n 'A'. +# +# Example 1: +# Input: 3 +# Output: 3 +# Explanation: +# Intitally, we have one character 'A'. +# In step 1, we use Copy All operation. +# In step 2, we use Paste operation to get 'AA'. +# In step 3, we use Paste operation to get 'AAA'. +# Note: +# The n will be in the range [1, 1000]. + +class Solution(object): + def minSteps(self, n): + """ + :type n: int + :rtype: int + """ + result = 0 + p = 2 + # the answer is the sum of prime factors + while p**2 <= n: + while n % p == 0: + result += p + n //= p + p += 1 + if n > 1: + result += n + return result diff --git a/Python/24-game.py b/Python/24-game.py new file mode 100644 index 000000000..bd91f330a --- /dev/null +++ b/Python/24-game.py @@ -0,0 +1,78 @@ +# Time: O(n^3 * 4^n) = O(1), n = 4 +# Space: O(n^2) = O(1) + +# You have 4 cards each containing a number from 1 to 9. +# You need to judge whether they could operated through *, /, +, -, (, ) to get the value of 24. +# +# Example 1: +# Input: [4, 1, 8, 7] +# Output: True +# Explanation: (8-4) * (7-1) = 24 +# Example 2: +# Input: [1, 2, 1, 2] +# Output: False +# Note: +# The division operator / represents real division, not integer division. +# For example, 4 / (1 - 2/3) = 12. +# Every operation done is between two numbers. In particular, we cannot use - as a unary operator. +# For example, with [1, 1, 1, 1] as input, the expression -1 - 1 - 1 - 1 is not allowed. +# You cannot concatenate numbers together. For example, if the input is [1, 2, 1, 2], we cannot write this as 12 + 12. + +from operator import add, sub, mul, truediv + +class Solution(object): + def judgePoint24(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + if len(nums) == 1: + return abs(nums[0]-24) < 1e-6 + ops = [add, sub, mul, truediv] + for i in xrange(len(nums)): + for j in xrange(len(nums)): + if i == j: + continue + next_nums = [nums[k] for k in xrange(len(nums)) if i != k != j] + for op in ops: + if ((op is add or op is mul) and j > i) or \ + (op == truediv and nums[j] == 0): + continue + next_nums.append(op(nums[i], nums[j])) + if self.judgePoint24(next_nums): + return True + next_nums.pop() + return False + + +# Time: O(n^3 * 4^n) = O(1), n = 4 +# Space: O(n^2) = O(1) +from fractions import Fraction +from operator import add, sub, mul, div + +class Solution2(object): + def judgePoint24(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + def dfs(nums): + if len(nums) == 1: + return nums[0] == 24 + ops = [add, sub, mul, div] + for i in xrange(len(nums)): + for j in xrange(len(nums)): + if i == j: + continue + next_nums = [nums[k] for k in xrange(len(nums)) if i != k != j] + for op in ops: + if ((op is add or op is mul) and j > i) or \ + (op == div and nums[j] == 0): + continue + next_nums.append(op(nums[i], nums[j])) + if dfs(next_nums): + return True + next_nums.pop() + return False + + return dfs(map(Fraction, nums)) diff --git a/Python/3sum-closest.py b/Python/3sum-closest.py index 0681ae221..742e1fa57 100644 --- a/Python/3sum-closest.py +++ b/Python/3sum-closest.py @@ -9,28 +9,31 @@ # For example, given array S = {-1 2 1 -4}, and target = 1. # # The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). -# -class Solution: - # @return an integer + +class Solution(object): def threeSumClosest(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ nums, result, min_diff, i = sorted(nums), float("inf"), float("inf"), 0 while i < len(nums) - 2: - j, k = i + 1, len(nums) - 1 - while j < k: - diff = nums[i] + nums[j] + nums[k] - target - if abs(diff) < min_diff: - min_diff = abs(diff) - result = nums[i] + nums[j] + nums[k] - if diff < 0: - j += 1 - elif diff > 0: - k -= 1 - else: - return target + if i == 0 or nums[i] != nums[i - 1]: + j, k = i + 1, len(nums) - 1 + while j < k: + diff = nums[i] + nums[j] + nums[k] - target + if abs(diff) < min_diff: + min_diff = abs(diff) + result = nums[i] + nums[j] + nums[k] + if diff < 0: + j += 1 + elif diff > 0: + k -= 1 + else: + return target i += 1 - while i < len(nums) - 2 and nums[i] == nums[i - 1]: - i += 1 return result if __name__ == '__main__': diff --git a/Python/3sum-smaller.py b/Python/3sum-smaller.py new file mode 100644 index 000000000..bcc9b533b --- /dev/null +++ b/Python/3sum-smaller.py @@ -0,0 +1,23 @@ +# Time: O(n^2) +# Space: O(1) + +class Solution: + # @param {integer[]} nums + # @param {integer} target + # @return {integer} + def threeSumSmaller(self, nums, target): + nums.sort() + n = len(nums) + + count, k = 0, 2 + while k < n: + i, j = 0, k - 1 + while i < j: # Two Pointers, linear time. + if nums[i] + nums[j] + nums[k] >= target: + j -= 1 + else: + count += j - i + i += 1 + k += 1 + + return count diff --git a/Python/3sum.py b/Python/3sum.py index 2ad5ea356..404c19099 100644 --- a/Python/3sum.py +++ b/Python/3sum.py @@ -13,31 +13,55 @@ # A solution set is: # (-1, 0, 1) # (-1, -1, 2) -# +import collections + -class Solution: - # @return a list of lists of length 3, [[val1,val2,val3]] +class Solution(object): def threeSum(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ nums, result, i = sorted(nums), [], 0 while i < len(nums) - 2: - j, k = i + 1, len(nums) - 1 - while j < k: - if nums[i] + nums[j] + nums[k] < 0: - j += 1 - elif nums[i] + nums[j] + nums[k] > 0: - k -= 1 - else: - result.append([nums[i], nums[j], nums[k]]) - j, k = j + 1, k - 1 - while j < k and nums[j] == nums[j - 1]: + if i == 0 or nums[i] != nums[i - 1]: + j, k = i + 1, len(nums) - 1 + while j < k: + if nums[i] + nums[j] + nums[k] < 0: j += 1 - while j < k and nums[k] == nums[k + 1]: + elif nums[i] + nums[j] + nums[k] > 0: k -= 1 + else: + result.append([nums[i], nums[j], nums[k]]) + j, k = j + 1, k - 1 + while j < k and nums[j] == nums[j - 1]: + j += 1 + while j < k and nums[k] == nums[k + 1]: + k -= 1 i += 1 - while i < len(nums) - 2 and nums[i] == nums[i - 1]: - i += 1 return result + def threeSum2(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + d = collections.Counter(nums) + nums_2 = [x[0] for x in d.items() if x[1] > 1] + nums_new = sorted([x[0] for x in d.items()]) + rtn = [[0, 0, 0]] if d[0] >= 3 else [] + for i, j in enumerate(nums_new): + if j <= 0: + numss2 = nums_new[i + 1:] + for x, y in enumerate(numss2): + if 0 - j - y in [j, y] and 0 - j - y in nums_2: + if sorted([j, y, 0 - j - y]) not in rtn: + rtn.append(sorted([j, y, 0 - j - y])) + if 0 - j - y not in [j, y] and 0 - j - y in nums_new: + if sorted([j, y, 0 - j - y]) not in rtn: + rtn.append(sorted([j, y, 0 - j - y])) + return rtn + if __name__ == '__main__': result = Solution().threeSum([-1, 0, 1, 2, -1, -4]) - print result \ No newline at end of file + print result diff --git a/Python/4-keys-keyboard.py b/Python/4-keys-keyboard.py new file mode 100644 index 000000000..38d212b56 --- /dev/null +++ b/Python/4-keys-keyboard.py @@ -0,0 +1,35 @@ +# Time: O(1) +# Space: O(1) + +class Solution(object): + def maxA(self, N): + """ + :type N: int + :rtype: int + """ + if N < 7: return N + if N == 10: return 20 # the following rule doesn't hold when N = 10 + + n = N // 5 + 1 # n3 + n4 increases one every 5 keys + # (1) n = n3 + n4 + # (2) N + 1 = 4 * n3 + 5 * n4 + # 5 x (1) - (2) => 5*n - N - 1 = n3 + n3 = 5*n - N - 1 + n4 = n - n3 + return 3**n3 * 4**n4 + + +# Time: O(n) +# Space: O(1) +class Solution2(object): + def maxA(self, N): + """ + :type N: int + :rtype: int + """ + if N < 7: return N + dp = range(N+1) + for i in xrange(7, N+1): + dp[i % 6] = max(dp[(i-4) % 6]*3, dp[(i-5) % 6]*4) + return dp[N % 6] + diff --git a/Python/4sum-ii.py b/Python/4sum-ii.py new file mode 100644 index 000000000..016952602 --- /dev/null +++ b/Python/4sum-ii.py @@ -0,0 +1,37 @@ +# Time: O(n^2) +# Space: O(n^2) + +# Given four lists A, B, C, D of integer values, +# compute how many tuples (i, j, k, l) there are +# such that A[i] + B[j] + C[k] + D[l] is zero. +# +# To make problem a bit easier, all A, B, C, D have same length of N where 0 <= N <= 500. +# All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1. +# +# Example: +# +# Input: +# A = [ 1, 2] +# B = [-2,-1] +# C = [-1, 2] +# D = [ 0, 2] +# +# Output: +# 2 +# +# Explanation: +# The two tuples are: +# 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 +# 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 + +class Solution(object): + def fourSumCount(self, A, B, C, D): + """ + :type A: List[int] + :type B: List[int] + :type C: List[int] + :type D: List[int] + :rtype: int + """ + A_B_sum = collections.Counter(a+b for a in A for b in B) + return sum(A_B_sum[-c-d] for c in C for d in D) diff --git a/Python/4sum.py b/Python/4sum.py index c049c577c..d65759bdc 100644 --- a/Python/4sum.py +++ b/Python/4sum.py @@ -1,6 +1,6 @@ -# Time: O(n^2) ~ O(n^4) -# Space: O(n^2) -# +# Time: O(n^3) +# Space: O(1) + # Given an array S of n integers, # are there elements a, b, c, and d in S such that a + b + c + d = target? # Find all unique quadruplets in the array which gives the sum of target. @@ -16,14 +16,86 @@ # (-2, 0, 0, 2) # -class Solution: - # @return a list of lists of length 4, [[val1,val2,val3,val4]] +# Two pointer solution. (1356ms) +class Solution(object): + def fourSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + nums.sort() + res = [] + for i in xrange(len(nums) - 3): + if i and nums[i] == nums[i - 1]: + continue + for j in xrange(i + 1, len(nums) - 2): + if j != i + 1 and nums[j] == nums[j - 1]: + continue + sum = target - nums[i] - nums[j] + left, right = j + 1, len(nums) - 1 + while left < right: + if nums[left] + nums[right] == sum: + res.append([nums[i], nums[j], nums[left], nums[right]]) + right -= 1 + left += 1 + while left < right and nums[left] == nums[left - 1]: + left += 1 + while left < right and nums[right] == nums[right + 1]: + right -= 1 + elif nums[left] + nums[right] > sum: + right -= 1 + else: + left += 1 + return res + + +# Time: O(n^2 * p) +# Space: O(n^2 * p) +# Hash solution. (224ms) +class Solution2(object): + def fourSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + nums, result, lookup = sorted(nums), [], collections.defaultdict(list) + for i in xrange(0, len(nums) - 1): + for j in xrange(i + 1, len(nums)): + is_duplicated = False + for [x, y] in lookup[nums[i] + nums[j]]: + if nums[x] == nums[i]: + is_duplicated = True + break + if not is_duplicated: + lookup[nums[i] + nums[j]].append([i, j]) + ans = {} + for c in xrange(2, len(nums)): + for d in xrange(c+1, len(nums)): + if target - nums[c] - nums[d] in lookup: + for [a, b] in lookup[target - nums[c] - nums[d]]: + if b < c: + quad = [nums[a], nums[b], nums[c], nums[d]] + quad_hash = " ".join(str(quad)) + if quad_hash not in ans: + ans[quad_hash] = True + result.append(quad) + return result + + +# Time: O(n^2 * p) ~ O(n^4) +# Space: O(n^2) +class Solution3(object): def fourSum(self, nums, target): - nums, result, lookup = sorted(nums), [], {} + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + nums, result, lookup = sorted(nums), [], collections.defaultdict(list) for i in xrange(0, len(nums) - 1): for j in xrange(i + 1, len(nums)): - if nums[i] + nums[j] not in lookup: - lookup[nums[i] + nums[j]] = [] lookup[nums[i] + nums[j]].append([i, j]) for i in lookup.keys(): @@ -37,6 +109,7 @@ def fourSum(self, nums, target): result.append(quad) return sorted(result) + if __name__ == '__main__': result = Solution().fourSum([1, 0, -1, 0, -2, 2], 0) print result diff --git a/Python/accounts-merge.py b/Python/accounts-merge.py new file mode 100644 index 000000000..3f3a57b40 --- /dev/null +++ b/Python/accounts-merge.py @@ -0,0 +1,83 @@ +# Time: O(nlogn), n is the number of total emails, and the max length of email is 320, p.s. {64}@{255} +# Space: O(n) + +# Given a list accounts, each element accounts[i] is a list of strings, +# where the first element accounts[i][0] is a name, +# and the rest of the elements are emails representing emails of the account. +# +# Now, we would like to merge these accounts. +# Two accounts definitely belong to the same person if there is some email that is common to both accounts. +# Note that even if two accounts have the same name, +# they may belong to different people as people could have the same name. +# A person can have any number of accounts initially, but all of their accounts definitely have the same name. +# +# After merging the accounts, return the accounts in the following format: +# the first element of each account is the name, and the rest of the elements are emails in sorted order. +# The accounts themselves can be returned in any order. +# +# Example 1: +# Input: +# accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], +# ["John", "johnnybravo@mail.com"], +# ["John", "johnsmith@mail.com", "john_newyork@mail.com"], +# ["Mary", "mary@mail.com"]] +# Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], +# ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]] +# +# Explanation: +# The first and third John's are the same person as they have the common email "johnsmith@mail.com". +# The second John and Mary are different people as none of their email addresses are used by other accounts. +# We could return these lists in any order, +# for example the answer [['Mary', 'mary@mail.com'], +# ['John', 'johnnybravo@mail.com'], +# ['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] +# would still be accepted. +# +# Note: +# +# The length of accounts will be in the range [1, 1000]. +# The length of accounts[i] will be in the range [1, 10]. +# The length of accounts[i][j] will be in the range [1, 30]. + +class UnionFind(object): + def __init__(self): + self.set = [] + + def get_id(self): + self.set.append(len(self.set)) + return len(self.set)-1 + + def find_set(self, x): + if self.set[x] != x: + self.set[x] = self.find_set(self.set[x]) # path compression. + return self.set[x] + + def union_set(self, x, y): + x_root, y_root = map(self.find_set, (x, y)) + if x_root != y_root: + self.set[min(x_root, y_root)] = max(x_root, y_root) + + +class Solution(object): + def accountsMerge(self, accounts): + """ + :type accounts: List[List[str]] + :rtype: List[List[str]] + """ + union_find = UnionFind() + email_to_name = {} + email_to_id = {} + for account in accounts: + name = account[0] + for i in xrange(1, len(account)): + if account[i] not in email_to_id: + email_to_name[account[i]] = name + email_to_id[account[i]] = union_find.get_id() + union_find.union_set(email_to_id[account[1]], email_to_id[account[i]]) + + result = collections.defaultdict(list) + for email in email_to_name.keys(): + result[union_find.find_set(email_to_id[email])].append(email) + for emails in result.values(): + emails.sort() + return [[email_to_name[emails[0]]] + emails for emails in result.values()] diff --git a/Python/add-and-search-word-data-structure-design.py b/Python/add-and-search-word-data-structure-design.py new file mode 100644 index 000000000..384b97d64 --- /dev/null +++ b/Python/add-and-search-word-data-structure-design.py @@ -0,0 +1,67 @@ +# Time: O(min(n, h)), per operation +# Space: O(min(n, h)) +# +# Design a data structure that supports the following two operations: +# +# void addWord(word) +# bool search(word) +# search(word) can search a literal word or a regular expression string containing only letters a-z or .. +# A . means it can represent any one letter. +# +# For example: +# +# addWord("bad") +# addWord("dad") +# addWord("mad") +# search("pad") -> false +# search("bad") -> true +# search(".ad") -> true +# search("b..") -> true +# Note: +# You may assume that all words are consist of lowercase letters a-z. +# + +class TrieNode: + # Initialize your data structure here. + def __init__(self): + self.is_string = False + self.leaves = {} + +class WordDictionary: + def __init__(self): + self.root = TrieNode() + + # @param {string} word + # @return {void} + # Adds a word into the data structure. + def addWord(self, word): + curr = self.root + for c in word: + if not c in curr.leaves: + curr.leaves[c] = TrieNode() + curr = curr.leaves[c] + curr.is_string = True + + # @param {string} word + # @return {boolean} + # Returns if the word is in the data structure. A word could + # contain the dot character '.' to represent any one letter. + def search(self, word): + return self.searchHelper(word, 0, self.root) + + def searchHelper(self, word, start, curr): + if start == len(word): + return curr.is_string + if word[start] in curr.leaves: + return self.searchHelper(word, start+1, curr.leaves[word[start]]) + elif word[start] == '.': + for c in curr.leaves: + if self.searchHelper(word, start+1, curr.leaves[c]): + return True + + return False + +# Your WordDictionary object will be instantiated and called as such: +# wordDictionary = WordDictionary() +# wordDictionary.addWord("word") +# wordDictionary.search("pattern") diff --git a/Python/add-binary.py b/Python/add-binary.py index 054570ade..a2585157c 100644 --- a/Python/add-binary.py +++ b/Python/add-binary.py @@ -14,18 +14,18 @@ class Solution: # @param b, a string # @return a string def addBinary(self, a, b): - result, carry, val, len_a, len_b, i = "", 0, 0, len(a), len(b), 0 - for i in xrange(max(len_a, len_b)): + result, carry, val = "", 0, 0 + for i in xrange(max(len(a), len(b))): val = carry - if i < len_a: - sum += int(a[-(i + 1)]) - if i < len_b: - sum += int(b[-(i + 1)]) + if i < len(a): + val += int(a[-(i + 1)]) + if i < len(b): + val += int(b[-(i + 1)]) carry, val = val / 2, val % 2 - result = "{0}{1}".format(val, result) - if carry == 1: - result = "1" + result - return result + result += str(val) + if carry: + result += str(carry) + return result[::-1] if __name__ == '__main__': result = Solution().addBinary('11', '1') diff --git a/Python/add-bold-tag-in-string.py b/Python/add-bold-tag-in-string.py new file mode 100644 index 000000000..12b709857 --- /dev/null +++ b/Python/add-bold-tag-in-string.py @@ -0,0 +1,26 @@ +# Time: O(s * d * l), l is the average string length +# Space: O(s) + +class Solution(object): + def addBoldTag(self, s, dict): + """ + :type s: str + :type dict: List[str] + :rtype: str + """ + bold = [0] * len(s) + for d in dict: + pos = s.find(d) + while pos != -1: + bold[pos:pos+len(d)] = [1] * len(d) + pos = s.find(d, pos + 1) + + result, prev = [], 0 + for i in xrange(len(s)): + if prev != bold[i]: + result += "" if prev else "" + prev = bold[i] + result += s[i] + if prev: + result += "" + return "".join(result) diff --git a/Python/add-digits.py b/Python/add-digits.py new file mode 100644 index 000000000..5d28264e6 --- /dev/null +++ b/Python/add-digits.py @@ -0,0 +1,34 @@ +# Time: O(1) +# Space: O(1) +# +# Given a non-negative integer num, repeatedly add +# all its digits until the result has only one digit. +# +# For example: +# +# Given num = 38, the process is like: 3 + 8 = 11, +# 1 + 1 = 2. Since 2 has only one digit, return it. +# +# Follow up: +# Could you do it without any loop/recursion in O(1) +# runtime? +# +# Hint: +# +# A naive implementation of the above process is trivial. +# Could you come up with other methods? + + +class Solution: + """ + :type num: int + :rtype: int + """ + def addDigits(self, num): + return (num - 1) % 9 + 1 if num > 0 else 0 + + +if __name__ == '__main__': + s = Solution() + r = s.addDigits(12345) + print r diff --git a/Python/add-one-row-to-tree.py b/Python/add-one-row-to-tree.py new file mode 100644 index 000000000..2bda9d172 --- /dev/null +++ b/Python/add-one-row-to-tree.py @@ -0,0 +1,88 @@ +# Time: O(n) +# Space: O(h) + +# Given the root of a binary tree, then value v and depth d, +# you need to add a row of nodes with value v at the given depth d. The root node is at depth 1. +# +# The adding rule is: given a positive integer depth d, +# for each NOT null tree nodes N in depth d-1, create two tree nodes +# with value v as N's left subtree root and right subtree root. +# And N's original left subtree should be the left subtree of the new left subtree root, +# its original right subtree should be the right subtree of the new right subtree root. +# If depth d is 1 that means there is no depth d-1 at all, +# then create a tree node with value v as the new root of the whole original tree, +# and the original tree is the new root's left subtree. +# +# Example 1: +# Input: +# A binary tree as following: +# 4 +# / \ +# 2 6 +# / \ / +# 3 1 5 +# +# v = 1 +# +# d = 2 +# +# Output: +# 4 +# / \ +# 1 1 +# / \ +# 2 6 +# / \ / +# 3 1 5 +# +# Example 2: +# Input: +# A binary tree as following: +# 4 +# / +# 2 +# / \ +# 3 1 +# +# v = 1 +# +# d = 3 +# +# Output: +# 4 +# / +# 2 +# / \ +# 1 1 +# / \ +# 3 1 +# Note: +# 1. The given d is in range [1, maximum depth of the given tree + 1]. +# 2. The given binary tree has at least one tree node. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def addOneRow(self, root, v, d): + """ + :type root: TreeNode + :type v: int + :type d: int + :rtype: TreeNode + """ + if d in (0, 1): + node = TreeNode(v) + if d == 1: + node.left = root + else: + node.right = root + return node + if root and d >= 2: + root.left = self.addOneRow(root.left, v, d-1 if d > 2 else 1) + root.right = self.addOneRow(root.right, v, d-1 if d > 2 else 0) + return root diff --git a/Python/add-strings.py b/Python/add-strings.py new file mode 100644 index 000000000..b70851700 --- /dev/null +++ b/Python/add-strings.py @@ -0,0 +1,58 @@ +# Time: O(n) +# Space: O(1) + +# Given two non-negative numbers num1 and num2 represented as string, +# return the sum of num1 and num2. +# +# Note: +# +# The length of both num1 and num2 is < 5100. +# Both num1 and num2 contains only digits 0-9. +# Both num1 and num2 does not contain any leading zero. +# You must not use any built-in BigInteger library or +# convert the inputs to integer directly. + + +class Solution(object): + def addStrings(self, num1, num2): + """ + :type num1: str + :type num2: str + :rtype: str + """ + result = [] + i, j, carry = len(num1) - 1, len(num2) - 1, 0 + + while i >= 0 or j >= 0 or carry: + if i >= 0: + carry += ord(num1[i]) - ord('0'); + i -= 1 + if j >= 0: + carry += ord(num2[j]) - ord('0'); + j -= 1 + result.append(str(carry % 10)) + carry /= 10 + result.reverse() + + return "".join(result) + + def addStrings2(self, num1, num2): + """ + :type num1: str + :type num2: str + :rtype: str + """ + length = max(len(num1), len(num2)) + num1 = num1.zfill(length)[::-1] + num2 = num2.zfill(length)[::-1] + res, plus = '', 0 + for index, num in enumerate(num1): + tmp = str(int(num) + int(num2[index]) + plus) + res += tmp[-1] + if int(tmp) > 9: + plus = 1 + else: + plus = 0 + if plus: + res += '1' + return res[::-1] diff --git a/Python/add-two-numbers-ii.py b/Python/add-two-numbers-ii.py new file mode 100644 index 000000000..cde8fc554 --- /dev/null +++ b/Python/add-two-numbers-ii.py @@ -0,0 +1,56 @@ +# Time: O(m + n) +# Space: O(m + n) + +# You are given two linked lists representing two non-negative numbers. +# The most significant digit comes first and each of their nodes contain a single digit. +# Add the two numbers and return it as a linked list. +# +# You may assume the two numbers do not contain any leading zero, except the number 0 itself. +# +# Follow up: +# What if you cannot modify the input lists? In other words, reversing the lists is not allowed. +# +# Example: +# +# Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) +# Output: 7 -> 8 -> 0 -> 7 + +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution(object): + def addTwoNumbers(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + stk1, stk2 = [], [] + while l1: + stk1.append(l1.val) + l1 = l1.next + while l2: + stk2.append(l2.val) + l2 = l2.next + + prev, head = None, None + sum = 0 + while stk1 or stk2: + sum /= 10 + if stk1: + sum += stk1.pop() + if stk2: + sum += stk2.pop() + + head = ListNode(sum % 10) + head.next = prev + prev = head + + if sum >= 10: + head = ListNode(sum / 10) + head.next = prev + + return head diff --git a/Python/add-two-numbers.py b/Python/add-two-numbers.py index 158d85fd1..ee93acf4c 100644 --- a/Python/add-two-numbers.py +++ b/Python/add-two-numbers.py @@ -14,18 +14,22 @@ def __init__(self, x): self.val = x self.next = None -class Solution: - # @return a ListNode +class Solution(object): def addTwoNumbers(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ dummy = ListNode(0) current, carry = dummy, 0 - while l1 is not None or l2 is not None: + while l1 or l2: val = carry - if l1 is not None: + if l1: val += l1.val l1 = l1.next - if l2 is not None: + if l2: val += l2.val l2 = l2.next carry, val = val / 10, val % 10 @@ -42,4 +46,4 @@ def addTwoNumbers(self, l1, l2): b, b.next, b.next.next = ListNode(5), ListNode(6), ListNode(4) result = Solution().addTwoNumbers(a, b) print "{0} -> {1} -> {2}".format(result.val, result.next.val, result.next.next.val) - \ No newline at end of file + diff --git a/Python/additive-number.py b/Python/additive-number.py new file mode 100644 index 000000000..edde1bc02 --- /dev/null +++ b/Python/additive-number.py @@ -0,0 +1,64 @@ +# Time: O(n^3) +# Space: O(n) +# +# Additive number is a positive integer whose digits can form additive sequence. +# +# A valid additive sequence should contain at least three numbers. +# Except for the first two numbers, each subsequent number in the sequence +# must be the sum of the preceding two. +# +# For example: +# "112358" is an additive number because the digits can form an additive sequence: +# 1, 1, 2, 3, 5, 8. +# +# 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8 +# "199100199" is also an additive number, the additive sequence is: +# 1, 99, 100, 199. +# +# 1 + 99 = 100, 99 + 100 = 199 +# Note: Numbers in the additive sequence cannot have leading zeros, +# so sequence 1, 2, 03 or 1, 02, 3 is invalid. +# +# Given a string represents an integer, write a function to determine +# if it's an additive number. +# +# Follow up: +# How would you handle overflow for very large input integers? +# + +class Solution(object): + def isAdditiveNumber(self, num): + """ + :type num: str + :rtype: bool + """ + def add(a, b): + res, carry, val = "", 0, 0 + for i in xrange(max(len(a), len(b))): + val = carry + if i < len(a): + val += int(a[-(i + 1)]) + if i < len(b): + val += int(b[-(i + 1)]) + carry, val = val / 10, val % 10 + res += str(val) + if carry: + res += str(carry) + return res[::-1] + + + for i in xrange(1, len(num)): + for j in xrange(i + 1, len(num)): + s1, s2 = num[0:i], num[i:j] + if (len(s1) > 1 and s1[0] == '0') or \ + (len(s2) > 1 and s2[0] == '0'): + continue + + expected = add(s1, s2) + cur = s1 + s2 + expected + while len(cur) < len(num): + s1, s2, expected = s2, expected, add(s2, expected) + cur += expected + if cur == num: + return True + return False diff --git a/Python/alien-dictionary.py b/Python/alien-dictionary.py new file mode 100644 index 000000000..b9eccb43b --- /dev/null +++ b/Python/alien-dictionary.py @@ -0,0 +1,110 @@ +# Time: O(n) +# Space: O(|V|+|E|) = O(26 + 26^2) = O(1) + +# BFS solution. +class Solution(object): + def alienOrder(self, words): + """ + :type words: List[str] + :rtype: str + """ + result, zero_in_degree_queue, in_degree, out_degree = [], collections.deque(), {}, {} + nodes = sets.Set() + for word in words: + for c in word: + nodes.add(c) + + for i in xrange(1, len(words)): + if len(words[i-1]) > len(words[i]) and \ + words[i-1][:len(words[i])] == words[i]: + return "" + self.findEdges(words[i - 1], words[i], in_degree, out_degree) + + for node in nodes: + if node not in in_degree: + zero_in_degree_queue.append(node) + + while zero_in_degree_queue: + precedence = zero_in_degree_queue.popleft() + result.append(precedence) + + if precedence in out_degree: + for c in out_degree[precedence]: + in_degree[c].discard(precedence) + if not in_degree[c]: + zero_in_degree_queue.append(c) + + del out_degree[precedence] + + if out_degree: + return "" + + return "".join(result) + + + # Construct the graph. + def findEdges(self, word1, word2, in_degree, out_degree): + str_len = min(len(word1), len(word2)) + for i in xrange(str_len): + if word1[i] != word2[i]: + if word2[i] not in in_degree: + in_degree[word2[i]] = sets.Set() + if word1[i] not in out_degree: + out_degree[word1[i]] = sets.Set() + in_degree[word2[i]].add(word1[i]) + out_degree[word1[i]].add(word2[i]) + break + + +# DFS solution. +class Solution2(object): + def alienOrder(self, words): + """ + :type words: List[str] + :rtype: str + """ + # Find ancestors of each node by DFS. + nodes, ancestors = sets.Set(), {} + for i in xrange(len(words)): + for c in words[i]: + nodes.add(c) + for node in nodes: + ancestors[node] = [] + for i in xrange(1, len(words)): + if len(words[i-1]) > len(words[i]) and \ + words[i-1][:len(words[i])] == words[i]: + return "" + self.findEdges(words[i - 1], words[i], ancestors) + + # Output topological order by DFS. + result = [] + visited = {} + for node in nodes: + if self.topSortDFS(node, node, ancestors, visited, result): + return "" + + return "".join(result) + + + # Construct the graph. + def findEdges(self, word1, word2, ancestors): + min_len = min(len(word1), len(word2)) + for i in xrange(min_len): + if word1[i] != word2[i]: + ancestors[word2[i]].append(word1[i]) + break + + + # Topological sort, return whether there is a cycle. + def topSortDFS(self, root, node, ancestors, visited, result): + if node not in visited: + visited[node] = root + for ancestor in ancestors[node]: + if self.topSortDFS(root, ancestor, ancestors, visited, result): + return True + result.append(node) + elif visited[node] == root: + # Visited from the same root in the DFS path. + # So it is cyclic. + return True + return False diff --git a/Python/all-oone-data-structure.py b/Python/all-oone-data-structure.py new file mode 100644 index 000000000..55327cdd6 --- /dev/null +++ b/Python/all-oone-data-structure.py @@ -0,0 +1,121 @@ +# Time: O(1), per operation +# Space: O(k) + +# Implement a data structure supporting the following operations: +# +# Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. +# Key is guaranteed to be a non-empty string. +# Dec(Key) - If Key's value is 1, remove it from the data structure. +# Otherwise decrements an existing key by 1. If the key does not exist, +# this function does nothing. Key is guaranteed to be a non-empty string. +# GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string "". +# GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string "". +# Challenge: Perform all these in O(1) time complexity. + +class Node(object): + """ + double linked list node + """ + def __init__(self, value, keys): + self.value = value + self.keys = keys + self.prev = None + self.next = None + + +class LinkedList(object): + def __init__(self): + self.head, self.tail = Node(0, set()), Node(0, set()) + self.head.next, self.tail.prev = self.tail, self.head + + def insert(self, pos, node): + node.prev, node.next = pos.prev, pos + pos.prev.next, pos.prev = node, node + return node + + def erase(self, node): + node.prev.next, node.next.prev = node.next, node.prev + del node + + def empty(self): + return self.head.next is self.tail + + def begin(self): + return self.head.next + + def end(self): + return self.tail + + def front(self): + return self.head.next + + def back(self): + return self.tail.prev + + +class AllOne(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.bucket_of_key = {} + self.buckets = LinkedList() + + def inc(self, key): + """ + Inserts a new key with value 1. Or increments an existing key by 1. + :type key: str + :rtype: void + """ + if key not in self.bucket_of_key: + self.bucket_of_key[key] = self.buckets.insert(self.buckets.begin(), Node(0, set([key]))) + + bucket, next_bucket = self.bucket_of_key[key], self.bucket_of_key[key].next + if next_bucket is self.buckets.end() or next_bucket.value > bucket.value+1: + next_bucket = self.buckets.insert(next_bucket, Node(bucket.value+1, set())) + next_bucket.keys.add(key) + self.bucket_of_key[key] = next_bucket + + bucket.keys.remove(key) + if not bucket.keys: + self.buckets.erase(bucket) + + def dec(self, key): + """ + Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. + :type key: str + :rtype: void + """ + if key not in self.bucket_of_key: + return + + bucket, prev_bucket = self.bucket_of_key[key], self.bucket_of_key[key].prev + self.bucket_of_key.pop(key, None) + if bucket.value > 1: + if bucket is self.buckets.begin() or prev_bucket.value < bucket.value-1: + prev_bucket = self.buckets.insert(bucket, Node(bucket.value-1, set())) + prev_bucket.keys.add(key) + self.bucket_of_key[key] = prev_bucket + + bucket.keys.remove(key) + if not bucket.keys: + self.buckets.erase(bucket) + + def getMaxKey(self): + """ + Returns one of the keys with maximal value. + :rtype: str + """ + if self.buckets.empty(): + return "" + return iter(self.buckets.back().keys).next() + + def getMinKey(self): + """ + Returns one of the keys with Minimal value. + :rtype: str + """ + if self.buckets.empty(): + return "" + return iter(self.buckets.front().keys).next() diff --git a/Python/anagrams.py b/Python/anagrams.py index 7930db78c..7b4ff9628 100644 --- a/Python/anagrams.py +++ b/Python/anagrams.py @@ -1,4 +1,4 @@ -# Time: O(n) +# Time: O(n * glogg), g is the max size of groups. # Space: O(n) # # Given an array of strings, return all groups of strings that are anagrams. @@ -6,22 +6,22 @@ # Note: All inputs will be in lower-case. # -class Solution: - # @param strs, a list of strings - # @return a list of strings - def anagrams(self, strs): - anagrams_map, result = {}, [] +class Solution(object): + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + anagrams_map, result = collections.defaultdict(list), [] for s in strs: sorted_str = ("").join(sorted(s)) - if sorted_str in anagrams_map: - anagrams_map[sorted_str].append(s) - else: - anagrams_map[sorted_str] = [s] + anagrams_map[sorted_str].append(s) for anagram in anagrams_map.values(): - if len(anagram) > 1: - result += anagram + anagram.sort() + result.append(anagram) return result - + + if __name__ == "__main__": - result = Solution().anagrams(["cat", "dog", "act", "mac"]) - print result \ No newline at end of file + result = Solution().groupAnagrams(["cat", "dog", "act", "mac"]) + print result diff --git a/Python/android-unlock-patterns.py b/Python/android-unlock-patterns.py new file mode 100644 index 000000000..baed693d8 --- /dev/null +++ b/Python/android-unlock-patterns.py @@ -0,0 +1,180 @@ +# Time: O(9^2 * 2^9) +# Space: O(9 * 2^9) + +# DP solution. +class Solution(object): + def numberOfPatterns(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + def merge(used, i): + return used | (1 << i) + + def number_of_keys(i): + number = 0 + while i > 0: + i &= i - 1 + number += 1 + return number + + def contain(used, i): + return bool(used & (1 << i)) + + def convert(i, j): + return 3 * i + j + + # dp[i][j]: i is the set of the numbers in binary representation, + # dp[i][j] is the number of ways ending with the number j. + dp = [[0] * 9 for _ in xrange(1 << 9)] + for i in xrange(9): + dp[merge(0, i)][i] = 1 + + res = 0 + for used in xrange(len(dp)): + number = number_of_keys(used) + if number > n: + continue + + for i in xrange(9): + if not contain(used, i): + continue + + if m <= number <= n: + res += dp[used][i] + + x1, y1 = i / 3, i % 3 + for j in xrange(9): + if contain(used, j): + continue + + x2, y2 = j / 3, j % 3 + if ((x1 == x2 and abs(y1 - y2) == 2) or \ + (y1 == y2 and abs(x1 - x2) == 2) or \ + (abs(x1 - x2) == 2 and abs(y1 - y2) == 2)) and \ + not contain(used, convert((x1 + x2) / 2, (y1 + y2) / 2)): + continue + + dp[merge(used, j)][j] += dp[used][i] + + return res + + +# Time: O(9^2 * 2^9) +# Space: O(9 * 2^9) +# DP solution. +class Solution2(object): + def numberOfPatterns(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + def merge(used, i): + return used | (1 << i) + + def number_of_keys(i): + number = 0 + while i > 0: + i &= i - 1 + number += 1 + return number + + def exclude(used, i): + return used & ~(1 << i) + + def contain(used, i): + return bool(used & (1 << i)) + + def convert(i, j): + return 3 * i + j + + # dp[i][j]: i is the set of the numbers in binary representation, + # d[i][j] is the number of ways ending with the number j. + dp = [[0] * 9 for _ in xrange(1 << 9)] + for i in xrange(9): + dp[merge(0, i)][i] = 1 + + res = 0 + for used in xrange(len(dp)): + number = number_of_keys(used) + if number > n: + continue + + for i in xrange(9): + if not contain(used, i): + continue + + x1, y1 = i / 3, i % 3 + for j in xrange(9): + if i == j or not contain(used, j): + continue + + x2, y2 = j / 3, j % 3 + if ((x1 == x2 and abs(y1 - y2) == 2) or \ + (y1 == y2 and abs(x1 - x2) == 2) or \ + (abs(x1 - x2) == 2 and abs(y1 - y2) == 2)) and \ + not contain(used, convert((x1 + x2) / 2, (y1 + y2) / 2)): + continue + + dp[used][i] += dp[exclude(used, i)][j] + + if m <= number <= n: + res += dp[used][i] + + return res + + +# Time: O(9!) +# Space: O(9) +# Backtracking solution. (TLE) +class Solution_TLE(object): + def numberOfPatterns(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + def merge(used, i): + return used | (1 << i) + + def contain(used, i): + return bool(used & (1 << i)) + + def convert(i, j): + return 3 * i + j + + def numberOfPatternsHelper(m, n, level, used, i): + number = 0 + if level > n: + return number + + if m <= level <= n: + number += 1 + + x1, y1 = i / 3, i % 3 + for j in xrange(9): + if contain(used, j): + continue + + x2, y2 = j / 3, j % 3 + if ((x1 == x2 and abs(y1 - y2) == 2) or \ + (y1 == y2 and abs(x1 - x2) == 2) or \ + (abs(x1 - x2) == 2 and abs(y1 - y2) == 2)) and \ + not contain(used, convert((x1 + x2) / 2, (y1 + y2) / 2)): + continue + + number += numberOfPatternsHelper(m, n, level + 1, merge(used, j), j) + + return number + + + number = 0 + # 1, 3, 7, 9 + number += 4 * numberOfPatternsHelper(m, n, 1, merge(0, 0), 0) + # 2, 4, 6, 8 + number += 4 * numberOfPatternsHelper(m, n, 1, merge(0, 1), 1) + # 5 + number += numberOfPatternsHelper(m, n, 1, merge(0, 4), 4) + return number diff --git a/Python/arithmetic-slices-ii-subsequence.py b/Python/arithmetic-slices-ii-subsequence.py new file mode 100644 index 000000000..30418e704 --- /dev/null +++ b/Python/arithmetic-slices-ii-subsequence.py @@ -0,0 +1,60 @@ +# Time: O(n^2) +# Space: O(n * d) + +# A sequence of numbers is called arithmetic if it consists of at least three elements +# and if the difference between any two consecutive elements is the same. +# +# For example, these are arithmetic sequences: +# +# 1, 3, 5, 7, 9 +# 7, 7, 7, 7 +# 3, -1, -5, -9 +# The following sequence is not arithmetic. +# +# 1, 1, 2, 5, 7 +# +# A zero-indexed array A consisting of N numbers is given. +# A subsequence slice of that array is any sequence of integers (P0, P1, ..., Pk) +# such that 0 ≤ P0 < P1 < ... < Pk < N. +# +# A subsequence slice (P0, P1, ..., Pk) of array A is called arithmetic +# if the sequence A[P0], A[P1], ..., A[Pk-1], A[Pk] is arithmetic. In particular, this means that k >= 2. +# +# The function should return the number of arithmetic subsequence slices in the array A. +# +# The input contains N integers. Every integer is in the range of -2^31 and 2^31-1 and 0 <= N <= 1000. +# The output is guaranteed to be less than 2^31-1. +# +# +# Example: +# +# Input: [2, 4, 6, 8, 10] +# +# Output: 7 +# +# Explanation: +# All arithmetic subsequence slices are: +# [2,4,6] +# [4,6,8] +# [6,8,10] +# [2,4,6,8] +# [4,6,8,10] +# [2,4,6,8,10] +# [2,6,10] + +class Solution(object): + def numberOfArithmeticSlices(self, A): + """ + :type A: List[int] + :rtype: int + """ + result = 0 + dp = [collections.defaultdict(int) for i in xrange(len(A))] + for i in xrange(1, len(A)): + for j in xrange(i): + diff = A[i]-A[j] + dp[i][diff] += 1 + if diff in dp[j]: + dp[i][diff] += dp[j][diff] + result += dp[j][diff] + return result diff --git a/Python/arithmetic-slices.py b/Python/arithmetic-slices.py new file mode 100644 index 000000000..6bdbee58a --- /dev/null +++ b/Python/arithmetic-slices.py @@ -0,0 +1,44 @@ +# Time: O(n) +# Space: O(1) + +# A sequence of number is called arithmetic if it consists of at least three elements +# and if the difference between any two consecutive elements is the same. +# +# For example, these are arithmetic sequence: +# +# 1, 3, 5, 7, 9 +# 7, 7, 7, 7 +# 3, -1, -5, -9 +# The following sequence is not arithmetic. +# +# 1, 1, 2, 5, 7 +# +# A zero-indexed array A consisting of N numbers is given. A slice of that array is any pair +# of integers (P, Q) such that 0 <= P < Q < N. +# +# A slice (P, Q) of array A is called arithmetic if the sequence: +# A[P], A[p + 1], ..., A[Q - 1], A[Q] is arithmetic. In particular, this means that P + 1 < Q. +# +# The function should return the number of arithmetic slices in the array A. +# +# Example: +# +# A = [1, 2, 3, 4] +# +# return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself. + +class Solution(object): + def numberOfArithmeticSlices(self, A): + """ + :type A: List[int] + :rtype: int + """ + res, i = 0, 0 + while i+2 < len(A): + start = i + while i+2 < len(A) and A[i+2] + A[i] == 2*A[i+1]: + res += i - start + 1 + i += 1 + i += 1 + + return res diff --git a/Python/arranging-coins.py b/Python/arranging-coins.py new file mode 100644 index 000000000..f4e3de1df --- /dev/null +++ b/Python/arranging-coins.py @@ -0,0 +1,57 @@ +# Time: O(logn) +# Space: O(1) + +# You have a total of n coins that you want to form in a staircase shape, +# where every k-th row must have exactly k coins. +# +# Given n, find the total number of full staircase rows that can be formed. +# +# n is a non-negative integer and fits within the range of a 32-bit signed integer. +# +# Example 1: +# +# n = 5 +# +# The coins can form the following rows: +# ¤ +# ¤ ¤ +# ¤ ¤ +# +# Because the 3rd row is incomplete, we return 2. +# Example 2: +# +# n = 8 +# +# The coins can form the following rows: +# ¤ +# ¤ ¤ +# ¤ ¤ ¤ +# ¤ ¤ +# +# Because the 4th row is incomplete, we return 3. + +class Solution(object): + def arrangeCoins(self, n): + """ + :type n: int + :rtype: int + """ + return int((math.sqrt(8*n+1)-1) / 2) # sqrt is O(logn) time. + + +# Time: O(logn) +# Space: O(1) +class Solution2(object): + def arrangeCoins(self, n): + """ + :type n: int + :rtype: int + """ + left, right = 1, n + while left <= right: + mid = left + (right - left) / 2 + if 2 * n < mid * (mid+1): + right = mid - 1 + else: + left = mid + 1 + return left - 1 diff --git a/Python/array-nesting.py b/Python/array-nesting.py new file mode 100644 index 000000000..e2407e9b8 --- /dev/null +++ b/Python/array-nesting.py @@ -0,0 +1,46 @@ +# Time: O(n) +# Space: O(1) + +# A zero-indexed array A consisting of N different integers is given. +# The array contains all integers in the range [0, N - 1]. +# +# Sets S[K] for 0 <= K < N are defined as follows: +# +# S[K] = { A[K], A[A[K]], A[A[A[K]]], ... }. +# +# Sets S[K] are finite for each K and should NOT contain duplicates. +# +# Write a function that given an array A consisting of N integers, +# return the size of the largest set S[K] for this array. +# +# Example 1: +# Input: A = [5,4,0,3,1,6,2] +# Output: 4 +# Explanation: +# A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2. +# +# One of the longest S[K]: +# S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0} +# Note: +# N is an integer within the range [1, 20,000]. +# The elements of A are all distinct. +# Each element of array A is an integer within the range [0, N-1]. + +class Solution(object): + def arrayNesting(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result = 0 + for num in nums: + if num != None: + start, count = num, 0 + while nums[start] != None: + temp = start + start = nums[start] + nums[temp] = None + count += 1 + result = max(result, count) + return result + diff --git a/Python/array-partition-i.py b/Python/array-partition-i.py new file mode 100644 index 000000000..65e190c22 --- /dev/null +++ b/Python/array-partition-i.py @@ -0,0 +1,44 @@ +# Time: O(r), r is the range size of the integers +# Space: O(r) + +# Given an array of 2n integers, your task is to group these integers into n pairs of integer, +# say (a1, b1), (a2, b2), ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible. +# +# Example 1: +# Input: [1,4,3,2] +# +# Output: 4 +# Explanation: n is 2, and the maximum sum of pairs is 4. +# Note: +# n is a positive integer, which is in the range of [1, 10000]. +# All the integers in the array will be in the range of [-10000, 10000]. + +class Solution(object): + def arrayPairSum(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + LEFT, RIGHT = -10000, 10000 + lookup = [0] * (RIGHT-LEFT+1) + for num in nums: + lookup[num-LEFT] += 1 + r, result = 0, 0 + for i in xrange(LEFT, RIGHT+1): + result += (lookup[i-LEFT] + 1 - r) / 2 * i + r = (lookup[i-LEFT] + r) % 2 + return result + +# Time: O(nlogn) +# Space: O(1) +class Solution2(object): + def arrayPairSum(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + nums.sort() + result = 0 + for i in xrange(0, len(nums), 2): + result += nums[i] + return result diff --git a/Python/assign-cookies.py b/Python/assign-cookies.py new file mode 100644 index 000000000..839899646 --- /dev/null +++ b/Python/assign-cookies.py @@ -0,0 +1,50 @@ +# Time: O(nlogn) +# Space: O(1) + +# Assume you are an awesome parent and want to give your children some cookies. +# But, you should give each child at most one cookie. Each child i has a greed factor gi, +# which is the minimum size of a cookie that the child will be content with; +# and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, +# and the child i will be content. +# Your goal is to maximize the number of your content children and output the maximum number. +# +# Note: +# You may assume the greed factor is always positive. +# You cannot assign more than one cookie to one child. +# +# Example 1: +# Input: [1,2,3], [1,1] +# +# Output: 1 +# +# Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3. +# And even though you have 2 cookies, since their size is both 1, +# you could only make the child whose greed factor is 1 content. +# You need to output 1. +# Example 2: +# Input: [1,2], [1,2,3] +# +# Output: 2 +# +# Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2. +# You have 3 cookies and their sizes are big enough to gratify all of the children, +# You need to output 2. + +class Solution(object): + def findContentChildren(self, g, s): + """ + :type g: List[int] + :type s: List[int] + :rtype: int + """ + g.sort() + s.sort() + + result, i = 0, 0 + for j in xrange(len(s)): + if i == len(g): + break + if s[j] >= g[i]: + result += 1 + i += 1 + return result diff --git a/Python/asteroid-collision.py b/Python/asteroid-collision.py new file mode 100644 index 000000000..223daeaf9 --- /dev/null +++ b/Python/asteroid-collision.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(n) + +# We are given an array asteroids of integers representing asteroids in a row. +# +# For each asteroid, the absolute value represents its size, +# and the sign represents its direction (positive meaning right, negative meaning left). +# Each asteroid moves at the same speed. +# +# Find out the state of the asteroids after all collisions. +# If two asteroids meet, the smaller one will explode. If both are the same size, both will explode. +# Two asteroids moving in the same direction will never meet. +# +# Example 1: +# Input: +# asteroids = [5, 10, -5] +# Output: [5, 10] +# Explanation: +# The 10 and -5 collide resulting in 10. The 5 and 10 never collide. +# Example 2: +# Input: +# asteroids = [8, -8] +# Output: [] +# Explanation: +# The 8 and -8 collide exploding each other. +# Example 3: +# Input: +# asteroids = [10, 2, -5] +# Output: [10] +# Explanation: +# The 2 and -5 collide resulting in -5. The 10 and -5 collide resulting in 10. +# Example 4: +# Input: +# asteroids = [-2, -1, 1, 2] +# Output: [-2, -1, 1, 2] +# Explanation: +# The -2 and -1 are moving left, while the 1 and 2 are moving right. +# Asteroids moving the same direction never meet, so no asteroids will meet each other. +# +# Note: +# - The length of asteroids will be at most 10000. +# - Each asteroid will be a non-zero integer in the range [-1000, 1000]. + +class Solution(object): + def asteroidCollision(self, asteroids): + """ + :type asteroids: List[int] + :rtype: List[int] + """ + result = [] + for asteroid in asteroids: + while result and asteroid < 0 < result[-1]: + if result[-1] < -asteroid: + result.pop() + continue + elif result[-1] == -asteroid: + result.pop() + break + else: + result.append(asteroid) + return result diff --git a/Python/average-of-levels-in-binary-tree.py b/Python/average-of-levels-in-binary-tree.py new file mode 100644 index 000000000..572699d3c --- /dev/null +++ b/Python/average-of-levels-in-binary-tree.py @@ -0,0 +1,50 @@ +# Time: O(n) +# Space: O(h) + +# Given a non-empty binary tree, +# return the average value of the nodes on each level in the form of an array. +# +# Example 1: +# Input: +# 3 +# / \ +# 9 20 +# / \ +# 15 7 +# Output: [3, 14.5, 11] +# Explanation: +# The average value of nodes on level 0 is 3, +# on level 1 is 14.5, and on level 2 is 11. Hence return [3, 14.5, 11]. +# +# Note: +# The range of node's value is in the range of 32-bit signed integer. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def averageOfLevels(self, root): + """ + :type root: TreeNode + :rtype: List[float] + """ + result = [] + q = collections.deque([root]) + while q: + total, count = 0, 0 + next_q = collections.deque([]) + while q: + n = q.popleft() + total += n.val; + count += 1 + if n.left: + next_q.append(n.left) + if n.right: + next_q.append(n.right) + q, next_q = next_q, q + result.append(float(total) / count) + return result diff --git a/Python/balanced-binary-tree.py b/Python/balanced-binary-tree.py index 532657698..fbf1326ab 100644 --- a/Python/balanced-binary-tree.py +++ b/Python/balanced-binary-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, determine if it is height-balanced. # diff --git a/Python/base-7.py b/Python/base-7.py new file mode 100644 index 000000000..b6544bd02 --- /dev/null +++ b/Python/base-7.py @@ -0,0 +1,32 @@ +# Time: O(1) +# Space: O(1) + +# Given an integer, return its base 7 string representation. +# +# Example 1: +# Input: 100 +# Output: "202" +# Example 2: +# Input: -7 +# Output: "-10" +# Note: The input will be in range of [-1e7, 1e7]. + +class Solution(object): + def convertToBase7(self, num): + if num < 0: return '-' + self.convertToBase7(-num) + result = '' + while num: + result = str(num % 7) + result + num //= 7 + return result if result else '0' + + +class Solution2(object): + def convertToBase7(self, num): + """ + :type num: int + :rtype: str + """ + if num < 0: return '-' + self.convertToBase7(-num) + if num < 7: return str(num) + return self.convertToBase7(num // 7) + str(num % 7) diff --git a/Python/baseball-game.py b/Python/baseball-game.py new file mode 100644 index 000000000..ede8ff9d9 --- /dev/null +++ b/Python/baseball-game.py @@ -0,0 +1,63 @@ +# Time: O(n) +# Space: O(n) + +# You're now a baseball game point recorder. +# Given a list of strings, each string can be one of the 4 following types: +# +# 1. Integer (one round's score): Directly represents the number of points you get in this round. +# 2. "+" (one round's score): Represents that the points you get in this round are +# the sum of the last two valid round's points. +# 3. "D" (one round's score): Represents that the points you get in this round are +# the doubled data of the last valid round's points. +# 4. "C" (an operation, which isn't a round's score): Represents the last valid round's points +# you get were invalid and should be removed. +# +# Each round's operation is permanent and could have an impact on the round before and the round after. +# You need to return the sum of the points you could get in all the rounds. +# +# Example 1: +# +# Input: ["5","2","C","D","+"] +# Output: 30 +# Explanation: +# Round 1: You could get 5 points. The sum is: 5. +# Round 2: You could get 2 points. The sum is: 7. +# Operation 1: The round 2's data was invalid. The sum is: 5. +# Round 3: You could get 10 points (the round 2's data has been removed). The sum is: 15. +# Round 4: You could get 5 + 10 = 15 points. The sum is: 30. +# +# Example 2: +# +# Input: ["5","-2","4","C","D","9","+","+"] +# Output: 27 +# Explanation: +# Round 1: You could get 5 points. The sum is: 5. +# Round 2: You could get -2 points. The sum is: 3. +# Round 3: You could get 4 points. The sum is: 7. +# Operation 1: The round 3's data is invalid. The sum is: 3. +# Round 4: You could get -4 points (the round 3's data has been removed). The sum is: -1. +# Round 5: You could get 9 points. The sum is: 8. +# Round 6: You could get -4 + 9 = 5 points. The sum is 13. +# Round 7: You could get 9 + 5 = 14 points. The sum is 27. +# +# Note: +# The size of the input list will be between 1 and 1000. +# Every integer represented in the list will be between -30000 and 30000. + +class Solution(object): + def calPoints(self, ops): + """ + :type ops: List[str] + :rtype: int + """ + history = [] + for op in ops: + if op == '+': + history.append(history[-1] + history[-2]) + elif op == 'D': + history.append(history[-1] * 2) + elif op == 'C': + history.pop() + else: + history.append(int(op)) + return sum(history) diff --git a/Python/basic-calculator-ii.py b/Python/basic-calculator-ii.py new file mode 100644 index 000000000..4575b8a69 --- /dev/null +++ b/Python/basic-calculator-ii.py @@ -0,0 +1,57 @@ +# Time: O(n) +# Space: O(n) +# +# Implement a basic calculator to evaluate a simple expression string. +# +# The expression string contains only non-negative integers, +, -, *, / +# operators and empty spaces . The integer division should truncate toward zero. +# +# You may assume that the given expression is always valid. +# +# Some examples: +# "3+2*2" = 7 +# " 3/2 " = 1 +# " 3+5 / 2 " = 5 +# Note: Do not use the eval built-in library function. +# + +class Solution: + # @param {string} s + # @return {integer} + def calculate(self, s): + operands, operators = [], [] + operand = "" + for i in reversed(xrange(len(s))): + if s[i].isdigit(): + operand += s[i] + if i == 0 or not s[i-1].isdigit(): + operands.append(int(operand[::-1])) + operand = "" + elif s[i] == ')' or s[i] == '*' or s[i] == '/': + operators.append(s[i]) + elif s[i] == '+' or s[i] == '-': + while operators and \ + (operators[-1] == '*' or operators[-1] == '/'): + self.compute(operands, operators) + operators.append(s[i]) + elif s[i] == '(': + while operators[-1] != ')': + self.compute(operands, operators) + operators.pop() + + while operators: + self.compute(operands, operators) + + return operands[-1] + + def compute(self, operands, operators): + left, right = operands.pop(), operands.pop() + op = operators.pop() + if op == '+': + operands.append(left + right) + elif op == '-': + operands.append(left - right) + elif op == '*': + operands.append(left * right) + elif op == '/': + operands.append(left / right) diff --git a/Python/basic-calculator.py b/Python/basic-calculator.py new file mode 100644 index 000000000..ea4ca3245 --- /dev/null +++ b/Python/basic-calculator.py @@ -0,0 +1,47 @@ +# Time: O(n) +# Space: O(n) +# +# Implement a basic calculator to evaluate a simple expression string. +# +# The expression string may contain open ( and closing parentheses ), +# the plus + or minus sign -, non-negative integers and empty spaces . +# +# You may assume that the given expression is always valid. +# +# Some examples: +# "1 + 1" = 2 +# " 2-1 + 2 " = 3 +# "(1+(4+5+2)-3)+(6+8)" = 23 +# + +class Solution: + # @param {string} s + # @return {integer} + def calculate(self, s): + operands, operators = [], [] + operand = "" + for i in reversed(xrange(len(s))): + if s[i].isdigit(): + operand += s[i] + if i == 0 or not s[i-1].isdigit(): + operands.append(int(operand[::-1])) + operand = "" + elif s[i] == ')' or s[i] == '+' or s[i] == '-': + operators.append(s[i]) + elif s[i] == '(': + while operators[-1] != ')': + self.compute(operands, operators) + operators.pop() + + while operators: + self.compute(operands, operators) + + return operands[-1] + + def compute(self, operands, operators): + left, right = operands.pop(), operands.pop() + op = operators.pop() + if op == '+': + operands.append(left + right) + elif op == '-': + operands.append(left - right) diff --git a/Python/battleships-in-a-board.py b/Python/battleships-in-a-board.py new file mode 100644 index 000000000..9f9c49944 --- /dev/null +++ b/Python/battleships-in-a-board.py @@ -0,0 +1,43 @@ +# Time: O(m * n) +# Space: O(1) + +# Given an 2D board, count how many different battleships are in it. +# The battleships are represented with 'X's, empty slots are represented with '.'s. +# You may assume the following rules: +# +# You receive a valid board, made of only battleships or empty slots. +# Battleships can only be placed horizontally or vertically. In other words, +# they can only be made of the shape 1xN (1 row, N columns) or Nx1 (N rows, 1 column), +# where N can be of any size. +# At least one horizontal or vertical cell separates between two battleships - +# there are no adjacent battleships. +# +# Example: +# X..X +# ...X +# ...X +# In the above board there are 2 battleships. +# Invalid Example: +# ...X +# XXXX +# ...X +# This is not a valid board - as battleships will always have a cell separating between them. +# Your algorithm should not modify the value of the board. + + +class Solution(object): + def countBattleships(self, board): + """ + :type board: List[List[str]] + :rtype: int + """ + if not board or not board[0]: + return 0 + + cnt = 0 + for i in xrange(len(board)): + for j in xrange(len(board[0])): + cnt += int(board[i][j] == 'X' and \ + (i == 0 or board[i - 1][j] != 'X') and \ + (j == 0 or board[i][j - 1] != 'X')) + return cnt diff --git a/Python/beautiful-arrangement-ii.py b/Python/beautiful-arrangement-ii.py new file mode 100644 index 000000000..007a28eb6 --- /dev/null +++ b/Python/beautiful-arrangement-ii.py @@ -0,0 +1,45 @@ +# Time: O(n) +# Space: O(1) + +# Given two integers n and k, +# you need to construct a list which contains n different positive integers ranging +# from 1 to n and obeys the following requirement: +# Suppose this list is [a1, a2, a3, ... , an], +# then the list [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|] has exactly k distinct integers. +# +# If there are multiple answers, print any of them. +# +# Example 1: +# Input: n = 3, k = 1 +# Output: [1, 2, 3] +# Explanation: The [1, 2, 3] has three different positive integers ranging from 1 to 3, +# and the [1, 1] has exactly 1 distinct integer: 1. +# +# Example 2: +# Input: n = 3, k = 2 +# Output: [1, 3, 2] +# Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, +# and the [2, 1] has exactly 2 distinct integers: 1 and 2. +# +# Note: +# The n and k are in the range 1 <= k < n <= 10^4. + +class Solution(object): + def constructArray(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[int] + """ + result = [] + left, right = 1, n + while left <= right: + if k % 2: + result.append(left) + left += 1 + else: + result.append(right) + right -= 1 + if k > 1: + k -= 1 + return result diff --git a/Python/beautiful-arrangement.py b/Python/beautiful-arrangement.py new file mode 100644 index 000000000..383209c20 --- /dev/null +++ b/Python/beautiful-arrangement.py @@ -0,0 +1,48 @@ +# Time: O(n!) +# Space: O(n) + +# Suppose you have N integers from 1 to N. +# We define a beautiful arrangement as an array that is constructed by these N numbers successfully +# if one of the following is true for the ith position (1 <= i <= N) in this array: +# +# The number at the ith position is divisible by i. +# i is divisible by the number at the ith position. +# Now given N, how many beautiful arrangements can you construct? +# +# Example 1: +# Input: 2 +# Output: 2 +# Explanation: +# +# The first beautiful arrangement is [1, 2]: +# +# Number at the 1st position (i=1) is 1, and 1 is divisible by i (i=1). +# +# Number at the 2nd position (i=2) is 2, and 2 is divisible by i (i=2). +# +# The second beautiful arrangement is [2, 1]: +# +# Number at the 1st position (i=1) is 2, and 2 is divisible by i (i=1). +# +# Number at the 2nd position (i=2) is 1, and i (i=2) is divisible by 1. +# Note: +# N is a positive integer and will not exceed 15. + +class Solution(object): + def countArrangement(self, N): + """ + :type N: int + :rtype: int + """ + def countArrangementHelper(n, arrangement): + if n <= 0: + return 1 + count = 0 + for i in xrange(n): + if arrangement[i] % n == 0 or n % arrangement[i] == 0: + arrangement[i], arrangement[n-1] = arrangement[n-1], arrangement[i] + count += countArrangementHelper(n - 1, arrangement) + arrangement[i], arrangement[n-1] = arrangement[n-1], arrangement[i] + return count + + return countArrangementHelper(N, range(1, N+1)) diff --git a/Python/best-meeting-point.py b/Python/best-meeting-point.py new file mode 100644 index 000000000..52b481624 --- /dev/null +++ b/Python/best-meeting-point.py @@ -0,0 +1,42 @@ +# Time: O(m * n) +# Space: O(m + n) + +from random import randint + +class Solution(object): + def minTotalDistance(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + x = [i for i, row in enumerate(grid) for v in row if v == 1] + y = [j for row in grid for j, v in enumerate(row) if v == 1] + mid_x = self.findKthLargest(x, len(x) / 2 + 1) + mid_y = self.findKthLargest(y, len(y) / 2 + 1) + + return sum([abs(mid_x-i) + abs(mid_y-j) \ + for i, row in enumerate(grid) for j, v in enumerate(row) if v == 1]) + + def findKthLargest(self, nums, k): + left, right = 0, len(nums) - 1 + while left <= right: + pivot_idx = randint(left, right) + new_pivot_idx = self.PartitionAroundPivot(left, right, pivot_idx, nums) + if new_pivot_idx == k - 1: + return nums[new_pivot_idx] + elif new_pivot_idx > k - 1: + right = new_pivot_idx - 1 + else: # new_pivot_idx < k - 1. + left = new_pivot_idx + 1 + + def PartitionAroundPivot(self, left, right, pivot_idx, nums): + pivot_value = nums[pivot_idx] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i] > pivot_value: + nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] + new_pivot_idx += 1 + + nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] + return new_pivot_idx diff --git a/Python/best-time-to-buy-and-sell-stock-ii.py b/Python/best-time-to-buy-and-sell-stock-ii.py index 5cbdc9a23..133ed078a 100644 --- a/Python/best-time-to-buy-and-sell-stock-ii.py +++ b/Python/best-time-to-buy-and-sell-stock-ii.py @@ -9,7 +9,7 @@ # (ie, buy one and sell one share of the stock multiple times). # However, you may not engage in multiple transactions at the same time # (ie, you must sell the stock before you buy again). -# + class Solution: # @param prices, a list of integer @@ -20,7 +20,10 @@ def maxProfit(self, prices): profit += max(0, prices[i + 1] - prices[i]) return profit + def maxProfit2(self, prices): + return sum(map(lambda x: max(prices[x + 1] - prices[x], 0), range(len(prices[:-1])))) + + if __name__ == "__main__": result = Solution().maxProfit([3, 2, 1, 4, 2, 5, 6]) print result - diff --git a/Python/best-time-to-buy-and-sell-stock-iii.py b/Python/best-time-to-buy-and-sell-stock-iii.py index 7b08da290..114c1b321 100644 --- a/Python/best-time-to-buy-and-sell-stock-iii.py +++ b/Python/best-time-to-buy-and-sell-stock-iii.py @@ -12,7 +12,43 @@ # (ie, you must sell the stock before you buy again). # +# Time: O(n) +# Space: O(1) class Solution: + # @param prices, a list of integer + # @return an integer + def maxProfit(self, prices): + hold1, hold2 = float("-inf"), float("-inf") + release1, release2 = 0, 0 + for i in prices: + release2 = max(release2, hold2 + i) + hold2 = max(hold2, release1 - i) + release1 = max(release1, hold1 + i) + hold1 = max(hold1, -i); + return release2 + +# Time: O(k * n) +# Space: O(k) +class Solution2: + # @param prices, a list of integer + # @return an integer + def maxProfit(self, prices): + return self.maxAtMostKPairsProfit(prices, 2) + + def maxAtMostKPairsProfit(self, prices, k): + max_buy = [float("-inf") for _ in xrange(k + 1)] + max_sell = [0 for _ in xrange(k + 1)] + + for i in xrange(len(prices)): + for j in xrange(1, min(k, i/2+1) + 1): + max_buy[j] = max(max_buy[j], max_sell[j-1] - prices[i]) + max_sell[j] = max(max_sell[j], max_buy[j] + prices[i]) + + return max_sell[k] + +# Time: O(n) +# Space: O(n) +class Solution3: # @param prices, a list of integer # @return an integer def maxProfit(self, prices): diff --git a/Python/best-time-to-buy-and-sell-stock-iv.py b/Python/best-time-to-buy-and-sell-stock-iv.py new file mode 100644 index 000000000..0235f07df --- /dev/null +++ b/Python/best-time-to-buy-and-sell-stock-iv.py @@ -0,0 +1,38 @@ +# Time: O(k * n) +# Space: O(k) +# +# Say you have an array for which the ith element is the price of a given stock on day i. +# +# Design an algorithm to find the maximum profit. You may complete at most k transactions. +# +# Note: +# You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). +# + +class Solution: + # @return an integer as the maximum profit + def maxProfit(self, k, prices): + if k >= len(prices) / 2: + return self.maxAtMostNPairsProfit(prices) + + return self.maxAtMostKPairsProfit(prices, k) + + def maxAtMostNPairsProfit(self, prices): + profit = 0 + for i in xrange(len(prices) - 1): + profit += max(0, prices[i + 1] - prices[i]) + return profit + + def maxAtMostKPairsProfit(self, prices, k): + max_buy = [float("-inf") for _ in xrange(k + 1)] + max_sell = [0 for _ in xrange(k + 1)] + + for i in xrange(len(prices)): + for j in xrange(1, min(k, i/2+1) + 1): + max_buy[j] = max(max_buy[j], max_sell[j-1] - prices[i]) + max_sell[j] = max(max_sell[j], max_buy[j] + prices[i]) + + return max_sell[k] + +if __name__ == "__main__": + print Solution().maxAtMostKPairsProfit([1, 2, 3, 4], 2) diff --git a/Python/best-time-to-buy-and-sell-stock-with-cooldown.py b/Python/best-time-to-buy-and-sell-stock-with-cooldown.py new file mode 100644 index 000000000..2e95e742b --- /dev/null +++ b/Python/best-time-to-buy-and-sell-stock-with-cooldown.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space: O(1) + +# Say you have an array for which the ith element is the price of a given stock on day i. +# +# Design an algorithm to find the maximum profit. You may complete as +# many transactions as you like (ie, buy one and sell one share of the +# stock multiple times) with the following restrictions: +# +# You may not engage in multiple transactions at the same time +# (ie, you must sell the stock before you buy again). +# After you sell your stock, you cannot buy stock on next day. +# (ie, cooldown 1 day) +# Example: +# +# prices = [1, 2, 3, 0, 2] +# maxProfit = 3 +# transactions = [buy, sell, cooldown, buy, sell] +# + +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + if not prices: + return 0 + buy, sell, coolDown = [0] * 2, [0] * 2, [0] * 2 + buy[0] = -prices[0] + for i in xrange(1, len(prices)): + # Bought before or buy today. + buy[i % 2] = max(buy[(i - 1) % 2], coolDown[(i - 1) % 2] - prices[i]) + # Sell today. + sell[i % 2] = buy[(i - 1) % 2] + prices[i] + # Sold before yesterday or sold yesterday. + coolDown[i % 2] = max(coolDown[(i - 1) % 2], sell[(i - 1) % 2]) + return max(coolDown[(len(prices) - 1) % 2], sell[(len(prices) - 1) % 2]) diff --git a/Python/best-time-to-buy-and-sell-stock-with-transaction-fee.py b/Python/best-time-to-buy-and-sell-stock-with-transaction-fee.py new file mode 100644 index 000000000..7393b5b6e --- /dev/null +++ b/Python/best-time-to-buy-and-sell-stock-with-transaction-fee.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# Your are given an array of integers prices, +# for which the i-th element is the price of a given stock on day i; +# and a non-negative integer fee representing a transaction fee. +# +# You may complete as many transactions as you like, +# but you need to pay the transaction fee for each transaction. +# You may not buy more than 1 share of a stock at a time +# (ie. you must sell the stock share before you buy again.) +# +# Return the maximum profit you can make. +# +# Example 1: +# Input: prices = [1, 3, 2, 8, 4, 9], fee = 2 +# Output: 8 +# Explanation: The maximum profit can be achieved by: +# Buying at prices[0] = 1 +# Selling at prices[3] = 8 +# Buying at prices[4] = 4 +# Selling at prices[5] = 9 +# The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8. +# +# Note: +# - 0 < prices.length <= 50000. +# - 0 < prices[i] < 50000. +# - 0 <= fee < 50000. + +class Solution(object): + def maxProfit(self, prices, fee): + """ + :type prices: List[int] + :type fee: int + :rtype: int + """ + cash, hold = 0, -prices[0] + for i in xrange(1, len(prices)): + cash = max(cash, hold+prices[i]-fee) + hold = max(hold, cash-prices[i]) + return cash + diff --git a/Python/binary-number-with-alternating-bits.py b/Python/binary-number-with-alternating-bits.py new file mode 100644 index 000000000..ff066353a --- /dev/null +++ b/Python/binary-number-with-alternating-bits.py @@ -0,0 +1,41 @@ +# Time: O(1) +# Space: O(1) + +# Given a positive integer, check whether it has alternating bits: +# namely, if two adjacent bits will always have different values. +# +# Example 1: +# Input: 5 +# Output: True +# Explanation: +# The binary representation of 5 is: 101 +# +# Example 2: +# Input: 7 +# Output: False +# Explanation: +# The binary representation of 7 is: 111. +# +# Example 3: +# Input: 11 +# Output: False +# Explanation: +# The binary representation of 11 is: 1011. +# +# Example 4: +# Input: 10 +# Output: True +# Explanation: +# The binary representation of 10 is: 1010. + +class Solution(object): + def hasAlternatingBits(self, n): + """ + :type n: int + :rtype: bool + """ + n, curr = divmod(n, 2) + while n > 0: + if curr == n % 2: return False + n, curr = divmod(n, 2) + return True diff --git a/Python/binary-search-tree-iterator.py b/Python/binary-search-tree-iterator.py index c198f87ec..428c8d4a3 100644 --- a/Python/binary-search-tree-iterator.py +++ b/Python/binary-search-tree-iterator.py @@ -1,5 +1,5 @@ # Time: O(1) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Implement an iterator over a binary search tree (BST). # Your iterator will be initialized with the root node of a BST. @@ -47,4 +47,4 @@ def next(self): i, v = BSTIterator(root), [] while i.hasNext(): v.append(i.next()) - print v \ No newline at end of file + print v diff --git a/Python/binary-tree-inorder-traversal.py b/Python/binary-tree-inorder-traversal.py index 5972f569b..11448e3fa 100644 --- a/Python/binary-tree-inorder-traversal.py +++ b/Python/binary-tree-inorder-traversal.py @@ -22,59 +22,61 @@ def __init__(self, x): self.left = None self.right = None + # Morris Traversal Solution -class Solution: - # @param root, a tree node - # @return a list of integers +class Solution(object): def inorderTraversal(self, root): - result, prev, cur = [], None, root - while cur: - if cur.left is None: - result.append(cur.val) - prev = cur - cur = cur.right + """ + :type root: TreeNode + :rtype: List[int] + """ + result, curr = [], root + while curr: + if curr.left is None: + result.append(curr.val) + curr = curr.right else: - node = cur.left - while node.right and node.right != cur: + node = curr.left + while node.right and node.right != curr: node = node.right if node.right is None: - node.right = cur - cur = cur.left + node.right = curr + curr = curr.left else: - result.append(cur.val) + result.append(curr.val) node.right = None - prev = cur - cur = cur.right + curr = curr.right return result + # Time: O(n) -# Space: O(n) -# Stack Solution -class Solution2: - # @param root, a tree node - # @return a list of integers +# Space: O(h) +# Stack Solution +class Solution2(object): def inorderTraversal(self, root): - result, stack, current, last_traversed = [], [], root, None - while stack or current: - if current: - stack.append(current) - current = current.left + """ + :type root: TreeNode + :rtype: List[int] + """ + result, stack = [], [(root, False)] + while stack: + root, is_visited = stack.pop() + if root is None: + continue + if is_visited: + result.append(root.val) else: - parent = stack[-1] - if parent.right in (None, last_traversed): - if parent.right is None: - result.append(parent.val) - last_traversed= stack.pop() - else: - result.append(parent.val) - current = parent.right + stack.append((root.right, False)) + stack.append((root, True)) + stack.append((root.left, False)) return result + if __name__ == "__main__": root = TreeNode(1) root.right = TreeNode(2) root.right.left = TreeNode(3) result = Solution().inorderTraversal(root) - print result \ No newline at end of file + print result diff --git a/Python/binary-tree-level-order-traversal-ii.py b/Python/binary-tree-level-order-traversal-ii.py index 07e9995bc..a03432a5d 100644 --- a/Python/binary-tree-level-order-traversal-ii.py +++ b/Python/binary-tree-level-order-traversal-ii.py @@ -1,6 +1,6 @@ # Time: O(n) # Space: O(n) -# + # Given a binary tree, return the bottom-up level order traversal of its nodes' values. # (ie, from left to right, level by level from leaf to root). # @@ -17,20 +17,24 @@ # [9,20], # [3] # ] -# + # Definition for a binary tree node -class TreeNode: +class TreeNode(object): def __init__(self, x): self.val = x self.left = None self.right = None -class Solution: - # @param root, a tree node - # @return a list of lists of integers + +class Solution(object): def levelOrderBottom(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ if root is None: return [] + result, current = [], [root] while current: next_level, vals = [], [] @@ -41,8 +45,10 @@ def levelOrderBottom(self, root): if node.right: next_level.append(node.right) current = next_level - result.insert(0, vals) - return result + result.append(vals) + + return result[::-1] + if __name__ == "__main__": root = TreeNode(3) @@ -51,4 +57,4 @@ def levelOrderBottom(self, root): root.right.left = TreeNode(15) root.right.right = TreeNode(7) result = Solution().levelOrderBottom(root) - print result \ No newline at end of file + print result diff --git a/Python/binary-tree-longest-consecutive-sequence-ii.py b/Python/binary-tree-longest-consecutive-sequence-ii.py new file mode 100644 index 000000000..99c88f13c --- /dev/null +++ b/Python/binary-tree-longest-consecutive-sequence-ii.py @@ -0,0 +1,39 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestConsecutive(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def longestConsecutiveHelper(root): + if not root: + return 0, 0 + left_len = longestConsecutiveHelper(root.left) + right_len = longestConsecutiveHelper(root.right) + cur_inc_len, cur_dec_len = 1, 1 + if root.left: + if root.left.val == root.val + 1: + cur_inc_len = max(cur_inc_len, left_len[0] + 1) + elif root.left.val == root.val - 1: + cur_dec_len = max(cur_dec_len, left_len[1] + 1) + if root.right: + if root.right.val == root.val + 1: + cur_inc_len = max(cur_inc_len, right_len[0] + 1) + elif root.right.val == root.val - 1: + cur_dec_len = max(cur_dec_len, right_len[1] + 1) + self.max_len = max(self.max_len, cur_dec_len + cur_inc_len - 1) + return cur_inc_len, cur_dec_len + + self.max_len = 0 + longestConsecutiveHelper(root) + return self.max_len + diff --git a/Python/binary-tree-longest-consecutive-sequence.py b/Python/binary-tree-longest-consecutive-sequence.py new file mode 100644 index 000000000..769c417ee --- /dev/null +++ b/Python/binary-tree-longest-consecutive-sequence.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestConsecutive(self, root): + """ + :type root: TreeNode + :rtype: int + """ + self.max_len = 0 + + def longestConsecutiveHelper(root): + if not root: + return 0 + + left_len = longestConsecutiveHelper(root.left) + right_len = longestConsecutiveHelper(root.right) + + cur_len = 1 + if root.left and root.left.val == root.val + 1: + cur_len = max(cur_len, left_len + 1); + if root.right and root.right.val == root.val + 1: + cur_len = max(cur_len, right_len + 1) + + self.max_len = max(self.max_len, cur_len, left_len, right_len) + + return cur_len + + longestConsecutiveHelper(root) + return self.max_len diff --git a/Python/binary-tree-maximum-path-sum.py b/Python/binary-tree-maximum-path-sum.py index 2c2705aa1..d71f6eeba 100644 --- a/Python/binary-tree-maximum-path-sum.py +++ b/Python/binary-tree-maximum-path-sum.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, find the maximum path sum. # diff --git a/Python/binary-tree-paths.py b/Python/binary-tree-paths.py new file mode 100644 index 000000000..657e8d579 --- /dev/null +++ b/Python/binary-tree-paths.py @@ -0,0 +1,51 @@ +# Time: O(n * h) +# Space: O(h) +# +# Given a binary tree, return all root-to-leaf paths. +# +# For example, given the following binary tree: +# +# 1 +# / \ +# 2 3 +# \ +# 5 +# All root-to-leaf paths are: +# +# ["1->2->5", "1->3"] +# +# +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @return {string[]} + def binaryTreePaths(self, root): + result, path = [], [] + self.binaryTreePathsRecu(root, path, result) + return result + + def binaryTreePathsRecu(self, node, path, result): + if node is None: + return + + if node.left is node.right is None: + ans = "" + for n in path: + ans += str(n.val) + "->" + result.append(ans + str(node.val)) + + if node.left: + path.append(node) + self.binaryTreePathsRecu(node.left, path, result) + path.pop() + + if node.right: + path.append(node) + self.binaryTreePathsRecu(node.right, path, result) + path.pop() diff --git a/Python/binary-tree-postorder-traversal.py b/Python/binary-tree-postorder-traversal.py index aa93e11fc..c5a47b0c8 100644 --- a/Python/binary-tree-postorder-traversal.py +++ b/Python/binary-tree-postorder-traversal.py @@ -22,11 +22,14 @@ def __init__(self, x): self.left = None self.right = None + # Morris Traversal Solution -class Solution: - # @param root, a tree node - # @return a list of integers +class Solution(object): def postorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ dummy = TreeNode(0) dummy.left = root result, cur = [], dummy @@ -57,30 +60,33 @@ def traceBack(self, frm, to): result.reverse() return result + # Time: O(n) -# Space: O(n) +# Space: O(h) # Stack Solution -class Solution2: - # @param root, a tree node - # @return a list of integers +class Solution2(object): def postorderTraversal(self, root): - result, stack, current, last_traversed = [], [], root, None - while stack or current: - if current: - stack.append(current) - current = current.left + """ + :type root: TreeNode + :rtype: List[int] + """ + result, stack = [], [(root, False)] + while stack: + root, is_visited = stack.pop() + if root is None: + continue + if is_visited: + result.append(root.val) else: - parent = stack[-1] - if parent.right in (None, last_traversed): - result.append(parent.val) - last_traversed = stack.pop() - else: - current = parent.right + stack.append((root, True)) + stack.append((root.right, False)) + stack.append((root.left, False)) return result + if __name__ == "__main__": root = TreeNode(1) root.right = TreeNode(2) root.right.left = TreeNode(3) result = Solution().postorderTraversal(root) - print result \ No newline at end of file + print result diff --git a/Python/binary-tree-preorder-traversal.py b/Python/binary-tree-preorder-traversal.py index 2cf998dcd..2ba22d545 100644 --- a/Python/binary-tree-preorder-traversal.py +++ b/Python/binary-tree-preorder-traversal.py @@ -22,57 +22,61 @@ def __init__(self, x): self.left = None self.right = None + # Morris Traversal Solution -class Solution: - # @param root, a tree node - # @return a list of integers +class Solution(object): def preorderTraversal(self, root): - result, prev, cur = [], None, root - while cur: - if cur.left is None: - result.append(cur.val) - prev = cur - cur = cur.right + """ + :type root: TreeNode + :rtype: List[int] + """ + result, curr = [], root + while curr: + if curr.left is None: + result.append(curr.val) + curr = curr.right else: - node = cur.left - while node.right and node.right != cur: + node = curr.left + while node.right and node.right != curr: node = node.right if node.right is None: - result.append(cur.val) - node.right = cur - prev =cur - cur = cur.left + result.append(curr.val) + node.right = curr + curr = curr.left else: node.right = None - cur = cur.right + curr = curr.right return result + # Time: O(n) -# Space: O(n) +# Space: O(h) # Stack Solution -class Solution2: - # @param root, a tree node - # @return a list of integers +class Solution2(object): def preorderTraversal(self, root): - result, stack, current, last_traversed = [], [], root, None - while stack or current: - if current: - result.append(current.val) - stack.append(current) - current = current.left + """ + :type root: TreeNode + :rtype: List[int] + """ + result, stack = [], [(root, False)] + while stack: + root, is_visited = stack.pop() + if root is None: + continue + if is_visited: + result.append(root.val) else: - parent = stack[-1] - if parent.right in (None, last_traversed): - last_traversed = stack.pop() - else: - current = parent.right + stack.append((root.right, False)) + stack.append((root.left, False)) + stack.append((root, True)) return result + if __name__ == "__main__": root = TreeNode(1) root.right = TreeNode(2) root.right.left = TreeNode(3) result = Solution().preorderTraversal(root) - print result \ No newline at end of file + print result diff --git a/Python/binary-tree-right-side-view.py b/Python/binary-tree-right-side-view.py new file mode 100644 index 000000000..56d5e3db2 --- /dev/null +++ b/Python/binary-tree-right-side-view.py @@ -0,0 +1,73 @@ +# Time: O(n) +# Space: O(h) +# +# Given a binary tree, imagine yourself standing on the right side of it, +# return the values of the nodes you can see ordered from top to bottom. +# +# For example: +# Given the following binary tree, +# 1 <--- +# / \ +# 2 3 <--- +# \ \ +# 5 4 <--- +# You should return [1, 3, 4]. +# + +# Definition for a binary tree node +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + # @param root, a tree node + # @return a list of integers + def rightSideView(self, root): + result = [] + self.rightSideViewDFS(root, 1, result) + return result + + def rightSideViewDFS(self, node, depth, result): + if not node: + return + + if depth > len(result): + result.append(node.val) + + self.rightSideViewDFS(node.right, depth+1, result) + self.rightSideViewDFS(node.left, depth+1, result) + +# BFS solution +# Time: O(n) +# Space: O(n) +class Solution2: + # @param root, a tree node + # @return a list of integers + def rightSideView(self, root): + if root is None: + return [] + + result, current = [], [root] + while current: + next_level = [] + for i, node in enumerate(current): + if node.left: + next_level.append(node.left) + if node.right: + next_level.append(node.right) + if i == len(current) - 1: + result.append(node.val) + current = next_level + + return result + +if __name__ == "__main__": + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.right = TreeNode(5) + root.right.right = TreeNode(4) + result = Solution().rightSideView(root) + print result diff --git a/Python/binary-tree-tilt.py b/Python/binary-tree-tilt.py new file mode 100644 index 000000000..e1ed02783 --- /dev/null +++ b/Python/binary-tree-tilt.py @@ -0,0 +1,49 @@ +# Time: O(n) +# Space: O(n) + +# Given a binary tree, return the tilt of the whole tree. +# +# The tilt of a tree node is defined as the absolute difference +# between the sum of all left subtree node values and +# the sum of all right subtree node values. Null node has tilt 0. +# +# The tilt of the whole tree is defined as the sum of all nodes' tilt. +# +# Example: +# Input: +# 1 +# / \ +# 2 3 +# Output: 1 +# Explanation: +# Tilt of node 2 : 0 +# Tilt of node 3 : 0 +# Tilt of node 1 : |2-3| = 1 +# Tilt of binary tree : 0 + 0 + 1 = 1 +# Note: +# +# The sum of node values in any subtree won't exceed the range of 32-bit integer. + + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findTilt(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def postOrderTraverse(root, tilt): + if not root: + return 0, tilt + left, tilt = postOrderTraverse(root.left, tilt) + right, tilt = postOrderTraverse(root.right, tilt) + tilt += abs(left-right) + return left+right+root.val, tilt + + return postOrderTraverse(root, 0)[1] diff --git a/Python/binary-tree-vertical-order-traversal.py b/Python/binary-tree-vertical-order-traversal.py new file mode 100644 index 000000000..8dd332ee4 --- /dev/null +++ b/Python/binary-tree-vertical-order-traversal.py @@ -0,0 +1,26 @@ +# Time: O(n) +# Space: O(n) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# BFS + hash solution. +class Solution(object): + def verticalOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + """ + cols = collections.defaultdict(list) + queue = [(root, 0)] + for node, i in queue: + if node: + cols[i].append(node.val) + queue += (node.left, i - 1), (node.right, i + 1) + return [cols[i] for i in xrange(min(cols.keys()), max(cols.keys()) + 1)] \ + if cols else [] diff --git a/Python/binary-watch.py b/Python/binary-watch.py new file mode 100644 index 000000000..eab47e94b --- /dev/null +++ b/Python/binary-watch.py @@ -0,0 +1,45 @@ +# Time: O(1) +# Space: O(1) + +# A binary watch has 4 LEDs on the top which represent the hours (0-11), +# and the 6 LEDs on the bottom represent the minutes (0-59). +# +# Each LED represents a zero or one, with the least significant bit on the right. +# +# For example, the above binary watch reads "3:25". +# +# Given a non-negative integer n which represents the number of LEDs that are currently on, +# return all possible times the watch could represent. +# +# Example: +# +# Input: n = 1 +# Return: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"] +# Note: +# The order of output does not matter. +# The hour must not contain a leading zero, for example "01:00" is not valid, it should be "1:00". + + +class Solution(object): + def readBinaryWatch(self, num): + """ + :type num: int + :rtype: List[str] + """ + def bit_count(bits): + count = 0 + while bits: + bits &= bits-1 + count += 1 + return count + + return ['%d:%02d' % (h, m) + for h in xrange(12) for m in xrange(60) + if bit_count(h) + bit_count(m) == num] + + def readBinaryWatch2(self, num): + """ + :type num: int + :rtype: List[str] + """ + return ['{0}:{1}'.format(str(h), str(m).zfill(2)) for h in range(12) for m in range(60) if (bin(h) + bin(m)).count('1') == num] diff --git a/Python/bitwise-and-of-numbers-range.py b/Python/bitwise-and-of-numbers-range.py new file mode 100644 index 000000000..369a5a803 --- /dev/null +++ b/Python/bitwise-and-of-numbers-range.py @@ -0,0 +1,31 @@ +# Time: O(1) +# Space: O(1) +# +# Given a range [m, n] where 0 <= m <= n <= 2147483647, +# return the bitwise AND of all numbers in this range, inclusive. +# +# For example, given the range [5, 7], you should return 4. +# + +class Solution: + # @param m, an integer + # @param n, an integer + # @return an integer + def rangeBitwiseAnd(self, m, n): + while m < n: + n &= n - 1 + return n + +class Solution2: + # @param m, an integer + # @param n, an integer + # @return an integer + def rangeBitwiseAnd(self, m, n): + i, diff = 0, n-m + while diff: + diff >>= 1 + i += 1 + return n&m >> i << i + +if __name__ == '__main__': + print Solution().rangeBitwiseAnd(5, 7) diff --git a/Python/bomb-enemy.py b/Python/bomb-enemy.py new file mode 100644 index 000000000..7da26b0b3 --- /dev/null +++ b/Python/bomb-enemy.py @@ -0,0 +1,39 @@ +# Time: O(m * n) +# Space: O(m * n) + +class Solution(object): + def maxKilledEnemies(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + result = 0 + if not grid or not grid[0]: + return result + + down = [[0 for _ in xrange(len(grid[0]))] for _ in xrange(len(grid))] + right = [[0 for _ in xrange(len(grid[0]))] for _ in xrange(len(grid))] + for i in reversed(xrange(len(grid))): + for j in reversed(xrange(len(grid[0]))): + if grid[i][j] != 'W': + if i + 1 < len(grid): + down[i][j] = down[i + 1][j] + if j + 1 < len(grid[0]): + right[i][j] = right[i][j + 1] + if grid[i][j] == 'E': + down[i][j] += 1 + right[i][j] += 1 + + up = [0 for _ in xrange(len(grid[0]))] + for i in xrange(len(grid)): + left = 0 + for j in xrange(len(grid[0])): + if grid[i][j] == 'W': + up[j], left = 0, 0 + elif grid[i][j] == 'E': + up[j] += 1 + left += 1 + else: + result = max(result, left + up[j] + right[i][j] + down[i][j]) + + return result diff --git a/Python/boundary-of-binary-tree.py b/Python/boundary-of-binary-tree.py new file mode 100644 index 000000000..ad7a6a6b3 --- /dev/null +++ b/Python/boundary-of-binary-tree.py @@ -0,0 +1,52 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def boundaryOfBinaryTree(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + def leftBoundary(root, nodes): + if not root or (not root.left and not root.right): + return + nodes.append(root.val) + if not root.left: + leftBoundary(root.right, nodes) + else: + leftBoundary(root.left, nodes) + + def rightBoundary(root, nodes): + if not root or (not root.left and not root.right): + return + if not root.right: + rightBoundary(root.left, nodes) + else: + rightBoundary(root.right, nodes) + nodes.append(root.val) + + def leaves(root, nodes): + if not root: + return + if not root.left and not root.right: + nodes.append(root.val) + return + leaves(root.left, nodes) + leaves(root.right, nodes) + + if not root: + return [] + + nodes = [root.val] + leftBoundary(root.left, nodes) + leaves(root.left, nodes) + leaves(root.right, nodes) + rightBoundary(root.right, nodes) + return nodes diff --git a/Python/brick-wall.py b/Python/brick-wall.py new file mode 100644 index 000000000..47ea1c230 --- /dev/null +++ b/Python/brick-wall.py @@ -0,0 +1,47 @@ +# Time: O(n), n is the total number of the bricks +# Space: O(m), m is the total number different widths + +# There is a brick wall in front of you. The wall is rectangular and has several rows of bricks. +# The bricks have the same height but different width. You want to draw a vertical line from +# the top to the bottom and cross the least bricks. +# +# The brick wall is represented by a list of rows. Each row is a list of integers representing the +# width of each brick in this row from left to right. +# +# If your line go through the edge of a brick, then the brick is not considered as crossed. +# You need to find out how to draw the line to cross the least bricks and return the number of crossed bricks. +# +# You cannot draw a line just along one of the two vertical edges of the wall, +# in which case the line will obviously cross no bricks. +# +# Example: +# Input: +# [[1,2,2,1], +# [3,1,2], +# [1,3,2], +# [2,4], +# [3,1,2], +# [1,3,1,1]] +# Output: 2 +# +# Note: +# The width sum of bricks in different rows are the same and won't exceed INT_MAX. +# The number of bricks in each row is in range [1,10,000]. +# The height of wall is in range [1,10,000]. +# Total number of bricks of the wall won't exceed 20,000. + +class Solution(object): + def leastBricks(self, wall): + """ + :type wall: List[List[int]] + :rtype: int + """ + widths = collections.defaultdict(int) + result = len(wall) + for row in wall: + width = 0 + for i in xrange(len(row)-1): + width += row[i] + widths[width] += 1 + result = min(result, len(wall) - widths[width]); + return result diff --git a/Python/bulb-switcher-ii.py b/Python/bulb-switcher-ii.py new file mode 100644 index 000000000..3ce93572a --- /dev/null +++ b/Python/bulb-switcher-ii.py @@ -0,0 +1,40 @@ +# Time: O(1) +# Space: O(1) + +# There is a room with n lights which are turned on initially and 4 buttons on the wall. +# After performing exactly m unknown operations towards buttons, +# you need to return how many different kinds of status of the n lights could be. +# +# Suppose n lights are labeled as number [1, 2, 3 ..., n], function of these 4 buttons are given below: +# 1. Flip all the lights. +# 3. Flip lights with even numbers. +# 3. Flip lights with odd numbers. +# 4. Flip lights with (3k + 1) numbers, k = 0, 1, 2, ... +# +# Example 1: +# Input: n = 1, m = 1. +# Output: 2 +# Explanation: Status can be: [on], [off] +# Example 2: +# Input: n = 2, m = 1. +# Output: 3 +# Explanation: Status can be: [on, off], [off, on], [off, off] +# Example 3: +# Input: n = 3, m = 1. +# Output: 4 +# Explanation: Status can be: [off, on, off], [on, off, on], [off, off, off], [off, on, on]. +# Note: n and m both fit in range [0, 1000]. + +class Solution(object): + def flipLights(self, n, m): + """ + :type n: int + :type m: int + :rtype: int + """ + if m == 0: return 1 + if n == 1: return 2 + if m == 1 and n == 2: return 3 + if m == 1 or n == 2: return 4 + if m == 2: return 7 + return 8 diff --git a/Python/bulb-switcher.py b/Python/bulb-switcher.py new file mode 100644 index 000000000..a63b6c39e --- /dev/null +++ b/Python/bulb-switcher.py @@ -0,0 +1,32 @@ +# Time: O(1) +# Space: O(1) + +# There are n bulbs that are initially off. +# You first turn on all the bulbs. Then, +# you turn off every second bulb. On the +# third round, you toggle every third bulb +# (turning on if it's off or turning off if +# it's on). For the nth round, you only +# toggle the last bulb. Find how many bulbs +# are on after n rounds. +# +# Example: +# +# Given n = 3. +# +# At first, the three bulbs are [off, off, off]. +# After first round, the three bulbs are [on, on, on]. +# After second round, the three bulbs are [on, off, on]. +# After third round, the three bulbs are [on, off, off]. +# +# So you should return 1, because there is +# only one bulb is on. + +class Solution(object): + def bulbSwitch(self, n): + """ + type n: int + rtype: int + """ + # The number of full squares. + return int(math.sqrt(n)) diff --git a/Python/bulls-and-cows.py b/Python/bulls-and-cows.py new file mode 100644 index 000000000..b0c8849f4 --- /dev/null +++ b/Python/bulls-and-cows.py @@ -0,0 +1,77 @@ +# Time: O(n) +# Space: O(10) = O(1) + +# You are playing the following Bulls and Cows game with your friend: +# You write a 4-digit secret number and ask your friend to guess it, +# each time your friend guesses a number, you give a hint, the hint +# tells your friend how many digits are in the correct positions +# (called "bulls") and how many digits are in the wrong positions +# (called "cows"), your friend will use those hints to find out the +# secret number. +# +# For example: +# +# Secret number: 1807 +# Friend's guess: 7810 +# Hint: 1 bull and 3 cows. (The bull is 8, the cows are 0, 1 and 7.) +# According to Wikipedia: "Bulls and Cows (also known as Cows and Bulls +# or Pigs and Bulls or Bulls and Cleots) is an old code-breaking mind or +# paper and pencil game for two or more players, predating the similar +# commercially marketed board game Mastermind. The numerical version of +# the game is usually played with 4 digits, but can also be played with +# 3 or any other number of digits." +# +# Write a function to return a hint according to the secret number and +# friend's guess, use A to indicate the bulls and B to indicate the cows, +# in the above example, your function should return 1A3B. +# +# You may assume that the secret number and your friend's guess only contain +# digits, and their lengths are always equal. +# + +# One pass solution. +from collections import defaultdict +from itertools import izip + +class Solution(object): + def getHint(self, secret, guess): + """ + :type secret: str + :type guess: str + :rtype: str + """ + A, B = 0, 0 + s_lookup, g_lookup = defaultdict(int), defaultdict(int) + for s, g in izip(secret, guess): + if s == g: + A += 1 + else: + if s_lookup[g]: + s_lookup[g] -= 1 + B += 1 + else: + g_lookup[g] += 1 + if g_lookup[s]: + g_lookup[s] -= 1 + B += 1 + else: + s_lookup[s] += 1 + + return "%dA%dB" % (A, B) + + +# Two pass solution. +from collections import Counter +from itertools import imap + +class Solution2(object): + def getHint(self, secret, guess): + """ + :type secret: str + :type guess: str + :rtype: str + """ + A = sum(imap(operator.eq, secret, guess)) + B = sum((Counter(secret) & Counter(guess)).values()) - A + return "%dA%dB" % (A, B) + diff --git a/Python/burst-balloons.py b/Python/burst-balloons.py new file mode 100644 index 000000000..acdd5c15e --- /dev/null +++ b/Python/burst-balloons.py @@ -0,0 +1,51 @@ +# Time: O(n^3) +# Space: O(n^2) + +# Given n balloons, indexed from 0 to n-1. +# Each balloon is painted with a number on it +# represented by array nums. +# You are asked to burst all the balloons. +# If the you burst balloon i you will get +# nums[left] * nums[i] * nums[right] coins. +# Here left and right are adjacent indices of i. +# After the burst, the left and right then +# becomes adjacent. +# +# Find the maximum coins you can collect by +# bursting the balloons wisely. +# +# Note: +# (1) You may imagine nums[-1] = nums[n] = 1. +# They are not real therefore you can not burst them. +# (2) 0 <= n <= 500, 0 <= nums[i] <= 100 +# +# Example: +# +# Given [3, 1, 5, 8] +# +# Return 167 +# +# nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> [] +# coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167 +# + +class Solution(object): + def maxCoins(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + coins = [1] + [i for i in nums if i > 0] + [1] + n = len(coins) + max_coins = [[0 for _ in xrange(n)] for _ in xrange(n)] + + for k in xrange(2, n): + for left in xrange(n - k): + right = left + k + for i in xrange(left + 1, right): + max_coins[left][right] = max(max_coins[left][right], \ + coins[left] * coins[i] * coins[right] + \ + max_coins[left][i] + max_coins[i][right]) + + return max_coins[0][-1] + diff --git a/Python/can-i-win.py b/Python/can-i-win.py new file mode 100644 index 000000000..1877b04e9 --- /dev/null +++ b/Python/can-i-win.py @@ -0,0 +1,60 @@ +# Time: O(n!) +# Space: O(n) + +# In the "100 game," two players take turns adding, to a running total, any integer from 1..10. +# The player who first causes the running total to reach or exceed 100 wins. +# +# What if we change the game so that players cannot re-use integers? +# +# For example, two players might take turns drawing from a common pool of numbers of 1..15 +# without replacement until they reach a total >= 100. +# +# Given an integer maxChoosableInteger and another integer desiredTotal, +# determine if the first player to move can force a win, assuming both players play optimally. +# +# You can always assume that maxChoosableInteger will not be larger than 20 and +# desiredTotal will not be larger than 300. +# +# Example +# +# Input: +# maxChoosableInteger = 10 +# desiredTotal = 11 +# +# Output: +# false +# +# Explanation: +# No matter which integer the first player choose, the first player will lose. +# The first player can choose an integer from 1 up to 10. +# If the first player choose 1, the second player can only choose integers from 2 up to 10. +# The second player will win by choosing 10 and get a total = 11, which is >= desiredTotal. +# Same with other integers chosen by the first player, the second player will always win. + +# Memoization solution. +class Solution(object): + def canIWin(self, maxChoosableInteger, desiredTotal): + """ + :type maxChoosableInteger: int + :type desiredTotal: int + :rtype: bool + """ + def canIWinHelper(maxChoosableInteger, desiredTotal, visited, lookup): + if visited in lookup: + return lookup[visited] + + mask = 1 + for i in xrange(maxChoosableInteger): + if visited & mask == 0: + if i + 1 >= desiredTotal or \ + not canIWinHelper(maxChoosableInteger, desiredTotal - (i + 1), visited | mask, lookup): + lookup[visited] = True + return True + mask <<= 1 + lookup[visited] = False + return False + + if (1 + maxChoosableInteger) * (maxChoosableInteger / 2) < desiredTotal: + return False + + return canIWinHelper(maxChoosableInteger, desiredTotal, 0, {}) diff --git a/Python/can-place-flowers.py b/Python/can-place-flowers.py new file mode 100644 index 000000000..343a031c2 --- /dev/null +++ b/Python/can-place-flowers.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(1) + +# Suppose you have a long flowerbed in which some of the plots are planted and some are not. +# However, flowers cannot be planted in adjacent plots - they would compete for water +# and both would die. +# +# Given a flowerbed (represented as an array containing 0 and 1, +# where 0 means empty and 1 means not empty), and a number n, +# return if n new flowers can be planted in it without violating the no-adjacent-flowers rule. +# +# Example 1: +# Input: flowerbed = [1,0,0,0,1], n = 1 +# Output: True +# Example 2: +# Input: flowerbed = [1,0,0,0,1], n = 2 +# Output: False +# Note: +# The input array won't violate no-adjacent-flowers rule. +# The input array size is in the range of [1, 20000]. +# n is a non-negative integer which won't exceed the input array size. + +class Solution(object): + def canPlaceFlowers(self, flowerbed, n): + """ + :type flowerbed: List[int] + :type n: int + :rtype: bool + """ + for i in xrange(len(flowerbed)): + if flowerbed[i] == 0 and (i == 0 or flowerbed[i-1] == 0) and \ + (i == len(flowerbed)-1 or flowerbed[i+1] == 0): + flowerbed[i] = 1 + n -= 1 + if n <= 0: + return True + return False diff --git a/Python/candy-crush.py b/Python/candy-crush.py new file mode 100644 index 000000000..782f4af05 --- /dev/null +++ b/Python/candy-crush.py @@ -0,0 +1,71 @@ +# Time: O((R * C)^2) +# Space: O(1) + +# This question is about implementing a basic elimination algorithm for Candy Crush. +# +# Given a 2D integer array board representing the grid of candy, +# different positive integers board[i][j] represent different types of candies. +# A value of board[i][j] = 0 represents that the cell at position (i, j) is empty. +# The given board represents the state of the game following the player's move. +# Now, you need to restore the board to a stable state by crushing candies according to the following rules: +# +# If three or more candies of the same type are adjacent vertically or horizontally, +# "crush" them all at the same time - these positions become empty. +# +# After crushing all candies simultaneously, +# if an empty space on the board has candies on top of itself, +# then these candies will drop until they hit a candy or bottom at the same time. +# (No new candies will drop outside the top boundary.) +# +# After the above steps, there may exist more candies that can be crushed. +# If so, you need to repeat the above steps. +# If there does not exist more candies that can be crushed (ie. the board is stable), +# then return the current board. +# You need to perform the above rules until the board becomes stable, then return the current board. +# +# Example 1: +# Input: +# board = +# [[110,5,112,113,114],[210,211,5,213,214],[310,311,3,313,314],[410,411,412,5,414],[5,1,512,3,3],[610,4,1,613,614],[710,1,2,713,714],[810,1,2,1,1],[1,1,2,2,2],[4,1,4,4,1014]] +# Output: +# [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[110,0,0,0,114],[210,0,0,0,214],[310,0,0,113,314],[410,0,0,213,414],[610,211,112,313,614],[710,311,412,613,714],[810,411,512,713,1014]] + +# Note: +# The length of board will be in the range [3, 50]. +# The length of board[i] will be in the range [3, 50]. +# Each board[i][j] will initially start as an integer in the range [1, 2000]. + +class Solution(object): + def candyCrush(self, board): + """ + :type board: List[List[int]] + :rtype: List[List[int]] + """ + R, C = len(board), len(board[0]) + changed = True + + while changed: + changed = False + + for r in xrange(R): + for c in xrange(C-2): + if abs(board[r][c]) == abs(board[r][c+1]) == abs(board[r][c+2]) != 0: + board[r][c] = board[r][c+1] = board[r][c+2] = -abs(board[r][c]) + changed = True + + for r in xrange(R-2): + for c in xrange(C): + if abs(board[r][c]) == abs(board[r+1][c]) == abs(board[r+2][c]) != 0: + board[r][c] = board[r+1][c] = board[r+2][c] = -abs(board[r][c]) + changed = True + + for c in xrange(C): + i = R-1 + for r in reversed(xrange(R)): + if board[r][c] > 0: + board[i][c] = board[r][c] + i -= 1 + for r in reversed(xrange(i+1)): + board[r][c] = 0 + + return board diff --git a/Python/cherry-pickup.py b/Python/cherry-pickup.py new file mode 100644 index 000000000..4764f990d --- /dev/null +++ b/Python/cherry-pickup.py @@ -0,0 +1,63 @@ +# Time: O(n^3) +# Space: O(n^2) + +# In a N x N grid representing a field of cherries, each cell is one of three possible integers. +# +# 0 means the cell is empty, so you can pass through; +# 1 means the cell contains a cherry, that you can pick up and pass through; +# -1 means the cell contains a thorn that blocks your way. +# Your task is to collect maximum number of cherries possible by following the rules below: +# +# Starting at the position (0, 0) and reaching (N-1, N-1) by moving right +# or down through valid path cells (cells with value 0 or 1); +# +# After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells; +# When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0); +# If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected. +# Example 1: +# Input: grid = +# [[0, 1, -1], +# [1, 0, -1], +# [1, 1, 1]] +# Output: 5 +# Explanation: +# The player started at (0, 0) and went down, down, right right to reach (2, 2). +# 4 cherries were picked up during this single trip, and the matrix becomes [[0,1,-1],[0,0,-1],[0,0,0]]. +# Then, the player went left, up, up, left to return home, picking up one more cherry. +# The total number of cherries picked up is 5, and this is the maximum possible. +# +# Note: +# - grid is an N by N 2D array, with 1 <= N <= 50. +# - Each grid[i][j] is an integer in the set {-1, 0, 1}. +# - It is guaranteed that grid[0][0] and grid[N-1][N-1] are not -1. + +class Solution(object): + def cherryPickup(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + # dp holds the max # of cherries two k-length paths can pickup. + # The two k-length paths arrive at (i, k - i) and (j, k - j), + # respectively. + n = len(grid) + dp = [[-1 for _ in xrange(n)] for _ in xrange(n)] + dp[0][0] = grid[0][0] + max_len = 2 * (n-1) + directions = [(0, 0), (-1, 0), (0, -1), (-1, -1)] + for k in xrange(1, max_len+1): + for i in reversed(xrange(max(0, k-n+1), min(k+1, n))): # 0 <= i < n, 0 <= k-i < n + for j in reversed(xrange(i, min(k+1, n))): # i <= j < n, 0 <= k-j < n + if grid[i][k-i] == -1 or grid[j][k-j] == -1: + dp[i][j] = -1 + continue + cnt = grid[i][k-i] + if i != j: + cnt += grid[j][k-j] + max_cnt = -1 + for direction in directions: + ii, jj = i+direction[0], j+direction[1] + if ii >= 0 and jj >= 0 and dp[ii][jj] >= 0: + max_cnt = max(max_cnt, dp[ii][jj]+cnt) + dp[i][j] = max_cnt + return max(dp[n-1][n-1], 0) diff --git a/Python/circular-array-loop.py b/Python/circular-array-loop.py new file mode 100644 index 000000000..f1b9e10e4 --- /dev/null +++ b/Python/circular-array-loop.py @@ -0,0 +1,51 @@ +# Time: O(n) +# Space: O(1) + +# You are given an array of positive and negative integers. +# If a number n at an index is positive, then move forward n steps. +# Conversely, if it's negative (-n), move backward n steps. +# Assume the first element of the array is forward next to the last element, +# and the last element is backward next to the first element. +# Determine if there is a loop in this array. +# A loop starts and ends at a particular index with more than 1 element along the loop. +# The loop must be "forward" or "backward'. +# +# Example 1: Given the array [2, -1, 1, 2, 2], there is a loop, from index 0 -> 2 -> 3 -> 0. +# +# Example 2: Given the array [-1, 2], there is no loop. +# +# Note: The given array is guaranteed to contain no element "0". +# +# Can you do it in O(n) time complexity and O(1) space complexity? + +class Solution(object): + def circularArrayLoop(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + def next_index(nums, i): + return (i + nums[i]) % len(nums) + + for i in xrange(len(nums)): + if nums[i] == 0: + continue + + slow, fast = i, i + while nums[next_index(nums, slow)] * nums[i] > 0 and \ + nums[next_index(nums, fast)] * nums[i] > 0 and \ + nums[next_index(nums, next_index(nums, fast))] * nums[i] > 0: + slow = next_index(nums, slow) + fast = next_index(nums, next_index(nums, fast)) + if slow == fast: + if slow == next_index(nums, slow): + break + return True + + slow, val = i, nums[i] + while nums[slow] * val > 0: + tmp = next_index(nums, slow) + nums[slow] = 0 + slow = tmp + + return False diff --git a/Python/climbing-stairs.py b/Python/climbing-stairs.py index 1c8df918d..6511a1dee 100644 --- a/Python/climbing-stairs.py +++ b/Python/climbing-stairs.py @@ -5,17 +5,28 @@ # # Each time you can either climb 1 or 2 steps. # In how many distinct ways can you climb to the top? -# + class Solution: - # @param n, an integer - # @return an integer + """ + :type n: int + :rtype: int + """ def climbStairs(self, n): prev, current = 0, 1 for i in xrange(n): prev, current = current, prev + current, return current + # Time: O(2^n) + # Space: O(n) + def climbStairs1(self, n): + if n == 1: + return 1 + if n == 2: + return 2 + return self.climbStairs(n - 1) + self.climbStairs(n - 2) + if __name__ == "__main__": result = Solution().climbStairs(2) print result diff --git a/Python/closest-binary-search-tree-value-ii.py b/Python/closest-binary-search-tree-value-ii.py new file mode 100644 index 000000000..4672e0cc6 --- /dev/null +++ b/Python/closest-binary-search-tree-value-ii.py @@ -0,0 +1,124 @@ +# Time: O(h + k) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def closestKValues(self, root, target, k): + """ + :type root: TreeNode + :type target: float + :type k: int + :rtype: List[int] + """ + # Helper to make a stack to the next node. + def nextNode(stack, child1, child2): + if stack: + if child2(stack): + stack.append(child2(stack)) + while child1(stack): + stack.append(child1(stack)) + else: + child = stack.pop() + while stack and child is child2(stack): + child = stack.pop() + + # The forward or backward iterator. + backward = lambda stack: stack[-1].left + forward = lambda stack: stack[-1].right + + # Build the stack to the closest node. + stack = [] + while root: + stack.append(root) + root = root.left if target < root.val else root.right + dist = lambda node: abs(node.val - target) + forward_stack = stack[:stack.index(min(stack, key=dist))+1] + + # Get the stack to the next smaller node. + backward_stack = list(forward_stack) + nextNode(backward_stack, backward, forward) + + # Get the closest k values by advancing the iterators of the stacks. + result = [] + for _ in xrange(k): + if forward_stack and \ + (not backward_stack or dist(forward_stack[-1]) < dist(backward_stack[-1])): + result.append(forward_stack[-1].val) + nextNode(forward_stack, forward, backward) + elif backward_stack and \ + (not forward_stack or dist(backward_stack[-1]) <= dist(forward_stack[-1])): + result.append(backward_stack[-1].val) + nextNode(backward_stack, backward, forward) + return result + + +class Solution2(object): + def closestKValues(self, root, target, k): + """ + :type root: TreeNode + :type target: float + :type k: int + :rtype: List[int] + """ + # Helper class to make a stack to the next node. + class BSTIterator: + # @param root, a binary search tree's root node + def __init__(self, stack, child1, child2): + self.stack = list(stack) + self.cur = self.stack.pop() + self.child1 = child1 + self.child2 = child2 + + # @return an integer, the next node + def next(self): + node = None + if self.cur and self.child1(self.cur): + self.stack.append(self.cur) + node = self.child1(self.cur) + while self.child2(node): + self.stack.append(node) + node = self.child2(node) + elif self.stack: + prev = self.cur + node = self.stack.pop() + while node: + if self.child2(node) is prev: + break + else: + prev = node + node = self.stack.pop() if self.stack else None + self.cur = node + return node + + # Build the stack to the closet node. + stack = [] + while root: + stack.append(root) + root = root.left if target < root.val else root.right + dist = lambda node: abs(node.val - target) if node else float("inf") + stack = stack[:stack.index(min(stack, key=dist))+1] + + # The forward or backward iterator. + backward = lambda node: node.left + forward = lambda node: node.right + smaller_it, larger_it = BSTIterator(stack, backward, forward), BSTIterator(stack, forward, backward) + smaller_node, larger_node = smaller_it.next(), larger_it.next() + + # Get the closest k values by advancing the iterators of the stacks. + result = [stack[-1].val] + for _ in xrange(k - 1): + if dist(smaller_node) < dist(larger_node): + result.append(smaller_node.val) + smaller_node = smaller_it.next() + else: + result.append(larger_node.val) + larger_node = larger_it.next() + return result + + diff --git a/Python/closest-binary-search-tree-value.py b/Python/closest-binary-search-tree-value.py new file mode 100644 index 000000000..15d5a9cfc --- /dev/null +++ b/Python/closest-binary-search-tree-value.py @@ -0,0 +1,30 @@ +# Time: O(h) +# Space: O(1) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def closestValue(self, root, target): + """ + :type root: TreeNode + :type target: float + :rtype: int + """ + gap = float("inf") + closest = float("inf") + while root: + if abs(root.val - target) < gap: + gap = abs(root.val - target) + closest = root + if target == root.val: + break + elif target < root.val: + root = root.left + else: + root = root.right + return closest.val diff --git a/Python/closest-leaf-in-a-binary-tree.py b/Python/closest-leaf-in-a-binary-tree.py new file mode 100644 index 000000000..839133c9f --- /dev/null +++ b/Python/closest-leaf-in-a-binary-tree.py @@ -0,0 +1,97 @@ +# Time: O(n) +# Space: O(n) + +# Given a binary tree where every node has a unique value, and a target key k, +# find the value of the closest leaf node to target k in the tree. +# +# Here, closest to a leaf means the least number of edges travelled on the binary tree to reach +# any leaf of the tree. Also, a node is called a leaf if it has no children. +# +# In the following examples, the input tree is represented in flattened form row by row. +# The actual root tree given will be a TreeNode object. +# +# Example 1: +# +# Input: +# root = [1, 3, 2], k = 1 +# Diagram of binary tree: +# 1 +# / \ +# 3 2 +# +# Output: 2 (or 3) +# +# Explanation: Either 2 or 3 is the closest leaf node to the target of 1. +# Example 2: +# +# Input: +# root = [1], k = 1 +# Output: 1 +# +# Explanation: The closest leaf node is the root node itself. +# Example 3: +# +# Input: +# root = [1,2,3,4,null,null,null,5,null,6], k = 2 +# Diagram of binary tree: +# 1 +# / \ +# 2 3 +# / +# 4 +# / +# 5 +# / +# 6 +# +# Output: 3 +# Explanation: The leaf node with value 3 (and not the leaf node with value 6) is closest to the node with value 2. +# Note: +# - root represents a binary tree with at least 1 node and at most 1000 nodes. +# - Every node has a unique node.val in range [1, 1000]. +# - There exists some node in the given binary tree for which node.val == k. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findClosestLeaf(self, root, k): + """ + :type root: TreeNode + :type k: int + :rtype: int + """ + def traverse(node, neighbors, leaves): + if not node: + return + if not node.left and not node.right: + leaves.add(node.val) + return + if node.left: + neighbors[node.val].append(node.left.val) + neighbors[node.left.val].append(node.val) + traverse(node.left, neighbors, leaves) + if node.right: + neighbors[node.val].append(node.right.val) + neighbors[node.right.val].append(node.val) + traverse(node.right, neighbors, leaves) + + neighbors, leaves = collections.defaultdict(list), set() + traverse(root, neighbors, leaves) + q, lookup = [k], set([k]) + while q: + next_q = [] + for u in q: + if u in leaves: + return u + for v in neighbors[u]: + if v in lookup: + continue + lookup.add(v) + next_q.append(v) + q = next_q + return 0 diff --git a/Python/coin-change-2.py b/Python/coin-change-2.py new file mode 100644 index 000000000..d65707685 --- /dev/null +++ b/Python/coin-change-2.py @@ -0,0 +1,45 @@ +# Time: O(n * m) +# Space: O(m) + +# You are given coins of different denominations and a total amount of money. +# Write a function to compute the number of combinations that make up that amount. +# You may assume that you have infinite number of each kind of coin. +# +# Note: You can assume that +# +# 0 <= amount <= 5000 +# 1 <= coin <= 5000 +# the number of coins is less than 500 +# the answer is guaranteed to fit into signed 32-bit integer +# Example 1: +# +# Input: amount = 5, coins = [1, 2, 5] +# Output: 4 +# Explanation: there are four ways to make up the amount: +# 5=5 +# 5=2+2+1 +# 5=2+1+1+1 +# 5=1+1+1+1+1 +# Example 2: +# +# Input: amount = 3, coins = [2] +# Output: 0 +# Explanation: the amount of 3 cannot be made up just with coins of 2. +# Example 3: +# +# Input: amount = 10, coins = [10] +# Output: 1 + +class Solution(object): + def change(self, amount, coins): + """ + :type amount: int + :type coins: List[int] + :rtype: int + """ + dp = [0] * (amount+1) + dp[0] = 1; + for coin in coins: + for i in xrange(coin, amount+1): + dp[i] += dp[i-coin] + return dp[amount] diff --git a/Python/coin-change.py b/Python/coin-change.py new file mode 100644 index 000000000..f762c382a --- /dev/null +++ b/Python/coin-change.py @@ -0,0 +1,38 @@ +# Time: O(n * k), n is the number of coins, k is the amount of money +# Space: O(k) +# +# You are given coins of different denominations and +# a total amount of money amount. Write a function to +# compute the fewest number of coins that you need to +# make up that amount. If that amount of money cannot +# be made up by any combination of the coins, return -1. +# +# Example 1: +# coins = [1, 2, 5], amount = 11 +# return 3 (11 = 5 + 5 + 1) +# +# Example 2: +# coins = [2], amount = 3 +# return -1. +# +# Note: +# You may assume that you have an infinite number of each kind of coin. + +# DP solution. (1680ms) +class Solution(object): + def coinChange(self, coins, amount): + """ + :type coins: List[int] + :type amount: int + :rtype: int + """ + INF = 0x7fffffff # Using float("inf") would be slower. + amounts = [INF] * (amount + 1) + amounts[0] = 0 + for i in xrange(amount + 1): + if amounts[i] != INF: + for coin in coins: + if i + coin <= amount: + amounts[i + coin] = min(amounts[i + coin], amounts[i] + 1) + return amounts[amount] if amounts[amount] != INF else -1 + diff --git a/Python/coin-path.py b/Python/coin-path.py new file mode 100644 index 000000000..6d43de5c4 --- /dev/null +++ b/Python/coin-path.py @@ -0,0 +1,30 @@ +# Time: O(n * B) +# Space: O(n) + +class Solution(object): + def cheapestJump(self, A, B): + """ + :type A: List[int] + :type B: int + :rtype: List[int] + """ + result = [] + if not A or A[-1] == -1: + return result + n = len(A) + dp, next_pos = [float("inf")] * n, [-1] * n + dp[n-1] = A[n-1] + for i in reversed(xrange(n-1)): + if A[i] == -1: + continue + for j in xrange(i+1, min(i+B+1,n)): + if A[i] + dp[j] < dp[i]: + dp[i] = A[i] + dp[j] + next_pos[i] = j + if dp[0] == float("inf"): + return result + k = 0 + while k != -1: + result.append(k+1) + k = next_pos[k] + return result diff --git a/Python/combination-sum-ii.py b/Python/combination-sum-ii.py index 592f55544..d11d74295 100644 --- a/Python/combination-sum-ii.py +++ b/Python/combination-sum-ii.py @@ -1,5 +1,5 @@ -# Time: O(n! / m!(n-m)!) -# Space: O(m) +# Time: O(k * C(n, k)) +# Space: O(k) # # Given a collection of candidate numbers (C) and a target number (T), # find all unique combinations in C where the candidate numbers sums to T. @@ -29,11 +29,13 @@ def combinationSum2(self, candidates, target): def combinationSumRecu(self, candidates, result, start, intermediate, target): if target == 0: - result.append(intermediate) + result.append(list(intermediate)) prev = 0 while start < len(candidates) and candidates[start] <= target: if prev != candidates[start]: - self.combinationSumRecu(candidates, result, start + 1, intermediate + [candidates[start]], target - candidates[start]) + intermediate.append(candidates[start]) + self.combinationSumRecu(candidates, result, start + 1, intermediate, target - candidates[start]) + intermediate.pop() prev = candidates[start] start += 1 diff --git a/Python/combination-sum-iii.py b/Python/combination-sum-iii.py new file mode 100644 index 000000000..ddc4ba260 --- /dev/null +++ b/Python/combination-sum-iii.py @@ -0,0 +1,45 @@ +# Time: O(k * C(n, k)) +# Space: O(k) +# +# Find all possible combinations of k numbers that add up to a number n, +# given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers. +# +# Ensure that numbers within the set are sorted in ascending order. +# +# +# Example 1: +# +# Input: k = 3, n = 7 +# +# Output: +# +# [[1,2,4]] +# +# Example 2: +# +# Input: k = 3, n = 9 +# +# Output: +# +# [[1,2,6], [1,3,5], [2,3,4]] +# + +class Solution: + # @param {integer} k + # @param {integer} n + # @return {integer[][]} + def combinationSum3(self, k, n): + result = [] + self.combinationSumRecu(result, [], 1, k, n) + return result + + def combinationSumRecu(self, result, intermediate, start, k, target): + if k == 0 and target == 0: + result.append(list(intermediate)) + elif k < 0: + return + while start < 10 and start * k + k * (k - 1) / 2 <= target: + intermediate.append(start) + self.combinationSumRecu(result, intermediate, start + 1, k - 1, target - start) + intermediate.pop() + start += 1 diff --git a/Python/combination-sum-iv.py b/Python/combination-sum-iv.py new file mode 100644 index 000000000..1b24689b1 --- /dev/null +++ b/Python/combination-sum-iv.py @@ -0,0 +1,47 @@ +# Time: O(nlon + n * t), t is the value of target. +# Space: O(t) + +# Given an integer array with all positive numbers and no duplicates, +# find the number of possible combinations that add up to a positive integer target. +# +# Example: +# +# nums = [1, 2, 3] +# target = 4 +# +# The possible combination ways are: +# (1, 1, 1, 1) +# (1, 1, 2) +# (1, 2, 1) +# (1, 3) +# (2, 1, 1) +# (2, 2) +# (3, 1) +# +# Note that different sequences are counted as different combinations. +# +# Therefore the output is 7. +# Follow up: +# What if negative numbers are allowed in the given array? +# How does it change the problem? +# What limitation we need to add to the question to allow negative numbers? + +class Solution(object): + def combinationSum4(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + dp = [0] * (target+1) + dp[0] = 1 + nums.sort() + + for i in xrange(1, target+1): + for j in xrange(len(nums)): + if nums[j] <= i: + dp[i] += dp[i - nums[j]] + else: + break + + return dp[target] diff --git a/Python/combination-sum.py b/Python/combination-sum.py index 6d5edd50b..ce0d14f11 100644 --- a/Python/combination-sum.py +++ b/Python/combination-sum.py @@ -1,5 +1,5 @@ -# Time: O(n^m) -# Space: O(m) +# Time: O(k * n^k) +# Space: O(k) # # Given a set of candidate numbers (C) and a target number (T), # find all unique combinations in C where the candidate numbers sums to T. @@ -27,9 +27,11 @@ def combinationSum(self, candidates, target): def combinationSumRecu(self, candidates, result, start, intermediate, target): if target == 0: - result.append(intermediate) + result.append(list(intermediate)) while start < len(candidates) and candidates[start] <= target: - self.combinationSumRecu(candidates, result, start, intermediate + [candidates[start]], target - candidates[start]) + intermediate.append(candidates[start]) + self.combinationSumRecu(candidates, result, start, intermediate, target - candidates[start]) + intermediate.pop() start += 1 if __name__ == "__main__": diff --git a/Python/compare-version-numbers.py b/Python/compare-version-numbers.py index a59d88c29..4b67b70e4 100644 --- a/Python/compare-version-numbers.py +++ b/Python/compare-version-numbers.py @@ -1,25 +1,60 @@ # Time: O(n) # Space: O(1) -# + # Compare two version numbers version1 and version1. -# If version1 > version2 return 1, if version1 < version2 return -1, otherwise return 0. +# If version1 > version2 return 1, if version1 < version2 +# return -1, otherwise return 0. # -# You may assume that the version strings are non-empty and contain only digits and the . character. -# The . character does not represent a decimal point and is used to separate number sequences. -# For instance, 2.5 is not "two and a half" or "half way to version three", it is the fifth second-level revision of the second first-level revision. +# You may assume that the version strings are non-empty and +# contain only digits and the . character. +# The . character does not represent a decimal point and +# is used to separate number sequences. +# For instance, 2.5 is not "two and a half" or "half way to +# version three", it is the fifth second-level revision of +# the second first-level revision. # # Here is an example of version numbers ordering: # # 0.1 < 1.1 < 1.2 < 13.37 # +import itertools + + +class Solution(object): + def compareVersion(self, version1, version2): + """ + :type version1: str + :type version2: str + :rtype: int + """ + n1, n2 = len(version1), len(version2) + i, j = 0, 0 + while i < n1 or j < n2: + v1, v2 = 0, 0 + while i < n1 and version1[i] != '.': + v1 = v1 * 10 + int(version1[i]) + i += 1 + while j < n2 and version2[j] != '.': + v2 = v2 * 10 + int(version2[j]) + j += 1 + if v1 != v2: + return 1 if v1 > v2 else -1 + i += 1 + j += 1 + + return 0 # Time: O(n) -# Space: O(n), this could be enhanced to O(1) by better but trivial string parsing -class Solution: - # @param a, a string - # @param b, a string - # @return a boolean +# Space: O(n) + + +class Solution2(object): def compareVersion(self, version1, version2): + """ + :type version1: str + :type version2: str + :rtype: int + """ v1, v2 = version1.split("."), version2.split(".") if len(v1) > len(v2): @@ -38,7 +73,32 @@ def compareVersion(self, version1, version2): return 0 + def compareVersion2(self, version1, version2): + """ + :type version1: str + :type version2: str + :rtype: int + """ + v1 = [int(x) for x in version1.split('.')] + v2 = [int(x) for x in version2.split('.')] + while len(v1) != len(v2): + if len(v1) > len(v2): + v2.append(0) + else: + v1.append(0) + return cmp(v1, v2) + + def compareVersion3(self, version1, version2): + splits = (map(int, v.split('.')) for v in (version1, version2)) + return cmp(*zip(*itertools.izip_longest(*splits, fillvalue=0))) + + def compareVersion4(self, version1, version2): + main1, _, rest1 = ('0' + version1).partition('.') + main2, _, rest2 = ('0' + version2).partition('.') + return cmp(int(main1), int(main2)) or len(rest1 + rest2) and self.compareVersion4(rest1, rest2) + + if __name__ == "__main__": print Solution().compareVersion("21.0", "121.1.0") print Solution().compareVersion("01", "1") - print Solution().compareVersion("1", "1.0") \ No newline at end of file + print Solution().compareVersion("1", "1.0") diff --git a/Python/complex-number-multiplication.py b/Python/complex-number-multiplication.py new file mode 100644 index 000000000..63fc97772 --- /dev/null +++ b/Python/complex-number-multiplication.py @@ -0,0 +1,32 @@ +# Time: O(1) +# Space: O(1) + +# Given two strings representing two complex numbers. +# +# You need to return a string representing their multiplication. Note i2 = -1 according to the definition. +# +# Example 1: +# Input: "1+1i", "1+1i" +# Output: "0+2i" +# Explanation: (1 + i) * (1 + i) = 1 + i2 + 2 * i = 2i, and you need convert it to the form of 0+2i. +# Example 2: +# Input: "1+-1i", "1+-1i" +# Output: "0+-2i" +# Explanation: (1 - i) * (1 - i) = 1 + i2 - 2 * i = -2i, and you need convert it to the form of 0+-2i. +# Note: +# +# The input strings will not have extra blank. +# The input strings will be given in the form of a+bi, +# where the integer a and b will both belong to the range of [-100, 100]. +# And the output should be also in this form. + +class Solution(object): + def complexNumberMultiply(self, a, b): + """ + :type a: str + :type b: str + :rtype: str + """ + ra, ia = map(int, a[:-1].split('+')) + rb, ib = map(int, b[:-1].split('+')) + return '%d+%di' % (ra * rb - ia * ib, ra * ib + ia * rb) diff --git a/Python/concatenated-words.py b/Python/concatenated-words.py new file mode 100644 index 000000000..8d89f5e36 --- /dev/null +++ b/Python/concatenated-words.py @@ -0,0 +1,47 @@ +# Time: O(n * l^2) +# Space: O(n * l) + +# Given a list of words, please write a program that returns +# all concatenated words in the given list of words. +# +# A concatenated word is defined as a string that is comprised entirely of +# at least two shorter words in the given array. +# +# Example: +# Input: ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"] +# +# Output: ["catsdogcats","dogcatsdog","ratcatdogcat"] +# +# Explanation: "catsdogcats" can be concatenated by "cats", "dog" and "cats"; +# "dogcatsdog" can be concatenated by "dog", "cats" and "dog"; +# "ratcatdogcat" can be concatenated by "rat", "cat", "dog" and "cat". +# Note: +# The number of elements of the given array will not exceed 10,000 +# The length sum of elements in the given array will not exceed 600,000. +# All the input string will only include lower case letters. +# The returned elements order does not matter. + +class Solution(object): + def findAllConcatenatedWordsInADict(self, words): + """ + :type words: List[str] + :rtype: List[str] + """ + lookup = set(words) + result = [] + for word in words: + dp = [False] * (len(word)+1) + dp[0] = True + for i in xrange(len(word)): + if not dp[i]: + continue + + for j in xrange(i+1, len(word)+1): + if j - i < len(word) and word[i:j] in lookup: + dp[j] = True + + if dp[len(word)]: + result.append(word) + break + + return result diff --git a/Python/construct-binary-tree-from-string.py b/Python/construct-binary-tree-from-string.py new file mode 100644 index 000000000..c7bcaafab --- /dev/null +++ b/Python/construct-binary-tree-from-string.py @@ -0,0 +1,32 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def str2tree(self, s): + """ + :type s: str + :rtype: TreeNode + """ + def str2treeHelper(s, i): + start = i + if s[i] == '-': i += 1 + while i < len(s) and s[i].isdigit(): i += 1 + node = TreeNode(int(s[start:i])) + if i < len(s) and s[i] == '(': + i += 1 + node.left, i = str2treeHelper(s, i) + i += 1 + if i < len(s) and s[i] == '(': + i += 1 + node.right, i = str2treeHelper(s, i) + i += 1 + return node, i + + return str2treeHelper(s, 0)[0] if s else None diff --git a/Python/construct-string-from-binary-tree.py b/Python/construct-string-from-binary-tree.py new file mode 100644 index 000000000..8bba46ba5 --- /dev/null +++ b/Python/construct-string-from-binary-tree.py @@ -0,0 +1,58 @@ +# Time: O(n) +# Space: O(h) + +# You need to construct a string consists of parenthesis and integers from a binary tree with +# the preorder traversing way. +# +# The null node needs to be represented by empty parenthesis pair "()". +# And you need to omit all the empty parenthesis pairs that don't affect +# the one-to-one mapping relationship between the string and the original binary tree. +# +# Example 1: +# Input: Binary tree: [1,2,3,4] +# 1 +# / \ +# 2 3 +# / +# 4 +# +# Output: "1(2(4))(3)" +# +# Explanation: Originallay it needs to be "1(2(4)())(3()())", +# but you need to omit all the unnecessary empty parenthesis pairs. +# And it will be "1(2(4))(3)". +# Example 2: +# Input: Binary tree: [1,2,3,null,4] +# 1 +# / \ +# 2 3 +# \ +# 4 +# +# Output: "1(2()(4))(3)" +# +# Explanation: Almost the same as the first example, +# except we can't omit the first parenthesis pair to break the one-to-one mapping relationship +# between the input and the output. + + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def tree2str(self, t): + """ + :type t: TreeNode + :rtype: str + """ + if not t: return "" + s = str(t.val) + if t.left or t.right: + s += "(" + self.tree2str(t.left) + ")" + if t.right: + s += "(" + self.tree2str(t.right) + ")" + return s diff --git a/Python/construct-the-rectangle.py b/Python/construct-the-rectangle.py new file mode 100644 index 000000000..54a412741 --- /dev/null +++ b/Python/construct-the-rectangle.py @@ -0,0 +1,34 @@ +# Time: O(1) +# Space: O(1) + +# For a web developer, it is very important to know how to design a web page's size. +# So, given a specific rectangular web page’s area, +# your job by now is to design a rectangular web page, whose length L +# and width W satisfy the following requirements: +# +# 1. The area of the rectangular web page you designed must equal to the given target area. +# +# 2. The width W should not be larger than the length L, which means L >= W. +# +# 3. The difference between length L and width W should be as small as possible. +# You need to output the length L and the width W of the web page you designed in sequence. +# Example: +# Input: 4 +# Output: [2, 2] +# Explanation: The target area is 4, and all the possible ways to construct it are [1,4], [2,2], [4,1]. +# But according to requirement 2, [1,4] is illegal; according to requirement 3, +# [4,1] is not optimal compared to [2,2]. So the length L is 2, and the width W is 2. +# Note: +# The given area won't exceed 10,000,000 and is a positive integer +# The web page's width and length you designed must be positive integers. + +class Solution(object): + def constructRectangle(self, area): + """ + :type area: int + :rtype: List[int] + """ + w = int(math.sqrt(area)) + while area % w: + w -= 1 + return [area // w, w] diff --git a/Python/contain-virus.py b/Python/contain-virus.py new file mode 100644 index 000000000..abf74ca92 --- /dev/null +++ b/Python/contain-virus.py @@ -0,0 +1,116 @@ +# Time: O((m * n)^(4/3)), days = O((m * n)^(1/3)) +# Space: O(m * n) + +# A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls. +# +# The world is modeled as a 2-D array of cells, +# where 0 represents uninfected cells, +# and 1 represents cells contaminated with the virus. +# A wall (and only one wall) can be installed between any two 4-directionally adjacent cells, +# on the shared boundary. +# +# Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. +# Resources are limited. +# Each day, you can install walls around only one region -- +# the affected area (continuous block of infected cells) that +# threatens the most uninfected cells the following night. +# There will never be a tie. +# +# Can you save the day? If so, what is the number of walls required? +# If not, and the world becomes fully infected, return the number of walls used. +# +# Example 1: +# Input: grid = +# [[0,1,0,0,0,0,0,1], +# [0,1,0,0,0,0,0,1], +# [0,0,0,0,0,0,0,1], +# [0,0,0,0,0,0,0,0]] +# Output: 10 +# Explanation: +# There are 2 contaminated regions. +# On the first day, add 5 walls to quarantine the viral region on the left. The board after the virus spreads is: +# +# [[0,1,0,0,0,0,1,1], +# [0,1,0,0,0,0,1,1], +# [0,0,0,0,0,0,1,1], +# [0,0,0,0,0,0,0,1]] +# +# On the second day, add 5 walls to quarantine the viral region on the right. The virus is fully contained. +# +# Example 2: +# Input: grid = +# [[1,1,1], +# [1,0,1], +# [1,1,1]] +# Output: 4 +# Explanation: Even though there is only one cell saved, there are 4 walls built. +# Notice that walls are only built on the shared boundary of two different cells. +# +# Example 3: +# Input: grid = +# [[1,1,1,0,0,0,0,0,0], +# [1,0,1,0,1,1,1,1,1], +# [1,1,1,0,0,0,0,0,0]] +# Output: 13 +# +# Explanation: The region on the left only builds two new walls. +# Note: +# - The number of rows and columns of grid will each be in the range [1, 50]. +# - Each grid[i][j] will be either 0 or 1. +# - Throughout the described process, there is always a contiguous viral region +# that will infect strictly more uncontaminated squares in the next round. + +class Solution(object): + def containVirus(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + directions = [(0, 1), (0, -1), (-1, 0), (1, 0)] + + def dfs(grid, r, c, lookup, regions, frontiers, perimeters): + if (r, c) in lookup: + return + lookup.add((r, c)) + regions[-1].add((r, c)) + for d in directions: + nr, nc = r+d[0], c+d[1] + if not (0 <= nr < len(grid) and \ + 0 <= nc < len(grid[r])): + continue + if grid[nr][nc] == 1: + dfs(grid, nr, nc, lookup, regions, frontiers, perimeters) + elif grid[nr][nc] == 0: + frontiers[-1].add((nr, nc)) + perimeters[-1] += 1 + + result = 0 + while True: + lookup, regions, frontiers, perimeters = set(), [], [], [] + for r, row in enumerate(grid): + for c, val in enumerate(row): + if val == 1 and (r, c) not in lookup: + regions.append(set()) + frontiers.append(set()) + perimeters.append(0) + dfs(grid, r, c, lookup, regions, frontiers, perimeters) + + if not regions: break + + triage_idx = frontiers.index(max(frontiers, key = len)) + for i, region in enumerate(regions): + if i == triage_idx: + result += perimeters[i] + for r, c in region: + grid[r][c] = -1 + continue + for r, c in region: + for d in directions: + nr, nc = r+d[0], c+d[1] + if not (0 <= nr < len(grid) and \ + 0 <= nc < len(grid[r])): + continue + if grid[nr][nc] == 0: + grid[nr][nc] = 1 + + return result diff --git a/Python/contains-duplicate-ii.py b/Python/contains-duplicate-ii.py new file mode 100644 index 000000000..451a6bdde --- /dev/null +++ b/Python/contains-duplicate-ii.py @@ -0,0 +1,24 @@ +# Time: O(n) +# Space: O(n) +# +# Given an array of integers and an integer k, return true if +# and only if there are two distinct indices i and j in the array +# such that nums[i] = nums[j] and the difference between i and j is at most k. +# + +class Solution: + # @param {integer[]} nums + # @param {integer} k + # @return {boolean} + def containsNearbyDuplicate(self, nums, k): + lookup = {} + for i, num in enumerate(nums): + if num not in lookup: + lookup[num] = i + else: + # It the value occurs before, check the difference. + if i - lookup[num] <= k: + return True + # Update the index of the value. + lookup[num] = i + return False diff --git a/Python/contains-duplicate-iii.py b/Python/contains-duplicate-iii.py new file mode 100644 index 000000000..42841b948 --- /dev/null +++ b/Python/contains-duplicate-iii.py @@ -0,0 +1,34 @@ +# Time: O(n * t) +# Space: O(max(k, t)) +# +# Given an array of integers, find out whether there +# are two distinct inwindowes i and j in the array such +# that the difference between nums[i] and nums[j] is +# at most t and the difference between i and j is at +# most k. +# + +# This is not the best solution +# since there is no built-in bst structure in Python. +# The better solution could be found in C++ solution. +class Solution: + # @param {integer[]} nums + # @param {integer} k + # @param {integer} t + # @return {boolean} + def containsNearbyAlmostDuplicate(self, nums, k, t): + if k < 0 or t < 0: + return False + window = collections.OrderedDict() + for n in nums: + # Make sure window size + if len(window) > k: + window.popitem(False) + + bucket = n if not t else n // t + # At most 2t items. + for m in (window.get(bucket - 1), window.get(bucket), window.get(bucket + 1)): + if m is not None and abs(n - m) <= t: + return True + window[bucket] = n + return False diff --git a/Python/contains-duplicate.py b/Python/contains-duplicate.py new file mode 100644 index 000000000..16c26a3c3 --- /dev/null +++ b/Python/contains-duplicate.py @@ -0,0 +1,13 @@ +# Time: O(n) +# Space: O(n) +# +# Given an array of integers, find if the array contains any duplicates. +# Your function should return true if any value appears at least twice in the array, +# and it should return false if every element is distinct. +# + +class Solution: + # @param {integer[]} nums + # @return {boolean} + def containsDuplicate(self, nums): + return len(nums) > len(set(nums)) diff --git a/Python/contiguous-array.py b/Python/contiguous-array.py new file mode 100644 index 000000000..f16e9147d --- /dev/null +++ b/Python/contiguous-array.py @@ -0,0 +1,31 @@ +# Time: O(n) +# Space: O(n) + +# Given a binary array, find the maximum length of a contiguous subarray with equal number of 0 and 1. +# +# Example 1: +# Input: [0,1] +# Output: 2 +# Explanation: [0, 1] is the longest contiguous subarray with equal number of 0 and 1. +# Example 2: +# Input: [0,1,0] +# Output: 2 +# Explanation: [0, 1] (or [1, 0]) is a longest contiguous subarray with equal number of 0 and 1. +# Note: The length of the given binary array will not exceed 50,000. + +class Solution(object): + def findMaxLength(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result, count = 0, 0 + lookup = {0: -1} + for i, num in enumerate(nums): + count += 1 if num == 1 else -1 + if count in lookup: + result = max(result, i - lookup[count]) + else: + lookup[count] = i + + return result diff --git a/Python/continuous-subarray-sum.py b/Python/continuous-subarray-sum.py new file mode 100644 index 000000000..b9991538f --- /dev/null +++ b/Python/continuous-subarray-sum.py @@ -0,0 +1,40 @@ +# Time: O(n) +# Space: O(k) + +# Given a list of non-negative numbers and a target integer k, +# write a function to check if the array has a continuous subarray +# of size at least 2 that sums up to the multiple of k, that is, +# sums up to n*k where n is also an integer. +# +# Example 1: +# Input: [23, 2, 4, 6, 7], k=6 +# Output: True +# Explanation: Because [2, 4] is a continuous subarray of size 2 and sums up to 6. +# Example 2: +# Input: [23, 2, 6, 4, 7], k=6 +# Output: True +# Explanation: Because [23, 2, 6, 4, 7] is an continuous subarray of size 5 and sums up to 42. +# Note: +# The length of the array won't exceed 10,000. +# You may assume the sum of all the numbers is in the range of a signed 32-bit integer. + +class Solution(object): + def checkSubarraySum(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + count = 0 + lookup = {0: -1} + for i, num in enumerate(nums): + count += num + if k: + count %= k + if count in lookup: + if i - lookup[count] > 1: + return True + else: + lookup[count] = i + + return False diff --git a/Python/convert-a-number-to-hexadecimal.py b/Python/convert-a-number-to-hexadecimal.py new file mode 100644 index 000000000..49617b167 --- /dev/null +++ b/Python/convert-a-number-to-hexadecimal.py @@ -0,0 +1,56 @@ +# Time: O(logn) +# Space: O(1) + +# Given an integer, write an algorithm to convert it to hexadecimal. +# For negative integer, two’s complement method is used. +# +# IMPORTANT: +# You must not use any method provided by the library which converts/formats +# the number to hex directly. Such solution will result in disqualification of +# all your submissions to this problem. Users may report such solutions after the +# contest ends and we reserve the right of final decision and interpretation +# in the case of reported solutions. +# +# Note: +# +# All letters in hexadecimal (a-f) must be in lowercase. +# The hexadecimal string must not contain extra leading 0s. If the number is zero, +# it is represented by a single zero character '0'; otherwise, +# the first character in the hexadecimal string will not be the zero character. +# The given number is guaranteed to fit within the range of a 32-bit signed integer. +# You must not use any method provided by the library which converts/formats the number to hex directly. +# Example 1: +# +# Input: +# 26 +# +# Output: +# "1a" +# Example 2: +# +# Input: +# -1 +# +# Output: +# "ffffffff" + +class Solution(object): + def toHex(self, num): + """ + :type num: int + :rtype: str + """ + if not num: + return "0" + + result = [] + while num and len(result) != 8: + h = num & 15 + if h < 10: + result.append(str(chr(ord('0') + h))) + else: + result.append(str(chr(ord('a') + h-10))) + num >>= 4 + result.reverse() + + return "".join(result) diff --git a/Python/convert-bst-to-greater-tree.py b/Python/convert-bst-to-greater-tree.py new file mode 100644 index 000000000..c0ff15309 --- /dev/null +++ b/Python/convert-bst-to-greater-tree.py @@ -0,0 +1,47 @@ +# Time: O(n) +# Space: O(h) + +# Given a Binary Search Tree (BST), +# convert it to a Greater Tree such that every key of +# the original BST is changed to the original key plus sum of +# all keys greater than the original key in BST. +# +# Example: +# +# Input: The root of a Binary Search Tree like this: +# 5 +# / \ +# 2 13 +# +# Output: The root of a Greater Tree like this: +# 18 +# / \ +# 20 13 + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def convertBST(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + def convertBSTHelper(root, cur_sum): + if not root: + return cur_sum + + if root.right: + cur_sum = convertBSTHelper(root.right, cur_sum) + cur_sum += root.val + root.val = cur_sum; + if root.left: + cur_sum = convertBSTHelper(root.left, cur_sum) + return cur_sum + + convertBSTHelper(root, 0) + return root diff --git a/Python/convert-sorted-array-to-binary-search-tree.py b/Python/convert-sorted-array-to-binary-search-tree.py index 946a2a163..ca9e1314d 100644 --- a/Python/convert-sorted-array-to-binary-search-tree.py +++ b/Python/convert-sorted-array-to-binary-search-tree.py @@ -17,10 +17,27 @@ class Solution: def sortedArrayToBST(self, num): return self.sortedArrayToBSTRecu(num, 0, len(num)) + @staticmethod + def perfect_tree_pivot(n): + """ + Find the point to partition n keys for a perfect binary search tree + """ + x = 1 + # find a power of 2 <= n//2 + # while x <= n//2: # this loop could probably be written more elegantly :) + # x *= 2 + x = 1 << (n.bit_length() - 1) # use the left bit shift, same as multiplying x by 2**n-1 + + if x // 2 - 1 <= (n - x): + return x - 1 # case 1: the left subtree of the root is perfect and the right subtree has less nodes + else: + return n - x // 2 # case 2 == n - (x//2 - 1) - 1 : the left subtree of the root + # has more nodes and the right subtree is perfect. + def sortedArrayToBSTRecu(self, num, start, end): if start == end: return None - mid = start + (end - start) / 2 + mid = start + self.perfect_tree_pivot(end - start) node = TreeNode(num[mid]) node.left = self.sortedArrayToBSTRecu(num, start, mid) node.right = self.sortedArrayToBSTRecu(num, mid + 1, end) diff --git a/Python/convex-polygon.py b/Python/convex-polygon.py new file mode 100644 index 000000000..27286efd6 --- /dev/null +++ b/Python/convex-polygon.py @@ -0,0 +1,22 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def isConvex(self, points): + """ + :type points: List[List[int]] + :rtype: bool + """ + def det(A): + return A[0][0]*A[1][1] - A[0][1]*A[1][0] + + n, prev, curr = len(points), 0, None + for i in xrange(len(points)): + A = [[points[(i+j) % n][0] - points[i][0], points[(i+j) % n][1] - points[i][1]] for j in (1, 2)] + curr = det(A) + if curr: + if curr * prev < 0: + return False + prev = curr + return True + diff --git a/Python/count-and-say.py b/Python/count-and-say.py index 5b55c29a4..f1b27c374 100644 --- a/Python/count-and-say.py +++ b/Python/count-and-say.py @@ -1,5 +1,5 @@ -# Time: O(n^2) -# Space: O(n) +# Time: O(n * 2^n) +# Space: O(2^n) # # The count-and-say sequence is the sequence of integers beginning as follows: # 1, 11, 21, 1211, 111221, ... @@ -27,7 +27,7 @@ def getNext(self, seq): while i < len(seq) - 1 and seq[i] == seq[i + 1]: cnt += 1 i += 1 - next_seq += "{}{}".format(cnt, seq[i]) + next_seq += str(cnt) + seq[i] i += 1 return next_seq diff --git a/Python/count-binary-substrings.py b/Python/count-binary-substrings.py new file mode 100644 index 000000000..f282b349a --- /dev/null +++ b/Python/count-binary-substrings.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# Give a string s, count the number of non-empty (contiguous) substrings +# that have the same number of 0's and 1's, and all the 0's and all the 1's +# in these substrings are grouped consecutively. +# +# Substrings that occur multiple times are counted the number of times they occur. +# +# Example 1: +# Input: "00110011" +# Output: 6 +# Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: +# "0011", "01", "1100", "10", "0011", and "01". +# +# Notice that some of these substrings repeat and are counted the number of times they occur. +# +# Also, "00110011" is not a valid substring because all the 0's (and 1's) are not grouped together. +# Example 2: +# Input: "10101" +# Output: 4 +# Explanation: There are 4 substrings: "10", "01", "10", "01" that have equal number of consecutive 1's and 0's. +# +# Note: +# s.length will be between 1 and 50,000. +# s will only consist of "0" or "1" characters. + +class Solution(object): + def countBinarySubstrings(self, s): + """ + :type s: str + :rtype: int + """ + result, prev, curr = 0, 0, 1 + for i in xrange(1, len(s)): + if s[i-1] != s[i]: + result += min(prev, curr) + prev, curr = curr, 1 + else: + curr += 1 + result += min(prev, curr) + return result diff --git a/Python/count-complete-tree-nodes.py b/Python/count-complete-tree-nodes.py new file mode 100644 index 000000000..24695387b --- /dev/null +++ b/Python/count-complete-tree-nodes.py @@ -0,0 +1,56 @@ +# Time: O(h * logn) = O((logn)^2) +# Space: O(1) + +# Given a complete binary tree, count the number of nodes. +# +# In a complete binary tree every level, except possibly the last, +# is completely filled, and all nodes in the last level are as far +# left as possible. It can have between 1 and 2h nodes inclusive at +# the last level h. +# + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @return {integer} + def countNodes(self, root): + if root is None: + return 0 + + node, level = root, 0 + while node.left is not None: + node = node.left + level += 1 + + # Binary search. + left, right = 2 ** level, 2 ** (level + 1) + while left < right: + mid = left + (right - left) / 2 + if not self.exist(root, mid): + right = mid + else: + left = mid + 1 + + return left - 1 + + # Check if the nth node exist. + def exist(self, root, n): + k = 1 + while k <= n: + k <<= 1 + k >>= 2 + + node = root + while k > 0: + if (n & k) == 0: + node = node.left + else: + node = node.right + k >>= 1 + return node is not None diff --git a/Python/count-different-palindromic-subsequences.py b/Python/count-different-palindromic-subsequences.py new file mode 100644 index 000000000..e0b4e7452 --- /dev/null +++ b/Python/count-different-palindromic-subsequences.py @@ -0,0 +1,69 @@ +# Time: O(n^2) +# Space: O(n^2) + +# Given a string S, find the number of different non-empty palindromic subsequences in S, +# and return that number modulo 10^9 + 7. +# +# A subsequence of a string S is obtained by deleting 0 or more characters from S. +# +# A sequence is palindromic if it is equal to the sequence reversed. +# +# Two sequences A_1, A_2, ... and B_1, B_2, ... are different if there is some i for which A_i != B_i. +# +# Example 1: +# Input: +# S = 'bccb' +# Output: 6 +# Explanation: +# The 6 different non-empty palindromic subsequences are 'b', 'c', 'bb', 'cc', 'bcb', 'bccb'. +# Note that 'bcb' is counted only once, even though it occurs twice. +# +# Example 2: +# Input: +# S = 'abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba' +# Output: 104860361 +# +# Explanation: +# There are 3104860382 different non-empty palindromic subsequences, which is 104860361 modulo 10^9 + 7. +# Note: +# - The length of S will be in the range [1, 1000]. +# - Each character S[i] will be in the set {'a', 'b', 'c', 'd'}. + +class Solution(object): + def countPalindromicSubsequences(self, S): + """ + :type S: str + :rtype: int + """ + def dp(i, j, prv, nxt, lookup): + if lookup[i][j] is not None: + return lookup[i][j] + result = 1 + if i <= j: + for x in xrange(4): + i0 = nxt[i][x] + j0 = prv[j][x] + if i <= i0 <= j: + result = (result + 1) % P + if None < i0 < j0: + result = (result + dp(i0+1, j0-1, prv, nxt, lookup)) % P + result %= P + lookup[i][j] = result + return result + + prv = [None] * len(S) + nxt = [None] * len(S) + + last = [None] * 4 + for i in xrange(len(S)): + last[ord(S[i])-ord('a')] = i + prv[i] = tuple(last) + + last = [None] * 4 + for i in reversed(xrange(len(S))): + last[ord(S[i])-ord('a')] = i + nxt[i] = tuple(last) + + P = 10**9 + 7 + lookup = [[None] * len(S) for _ in xrange(len(S))] + return dp(0, len(S)-1, prv, nxt, lookup) - 1 diff --git a/Python/count-numbers-with-unique-digits.py b/Python/count-numbers-with-unique-digits.py new file mode 100644 index 000000000..68812f89e --- /dev/null +++ b/Python/count-numbers-with-unique-digits.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(1) + +# Given an integer n, count all numbers with unique digits, x, where 0 <= x <= 10n. +# +# Example: +# Given n = 2, return 91. (The answer should be the total numbers in the range of 0 <= x <= 100, +# excluding [11,22,33,44,55,66,77,88,99,100]) +# +# Hint: +# 1. A direct way is to use the backtracking approach. +# 2. Backtracking should contains three states which are (the current number, +# number of steps to get that number and a bitmask which represent which +# number is marked as visited so far in the current number). +# Start with state (0,0,0) and count all valid number till we reach +# number of steps equals to 10n. +# 3. This problem can also be solved using a dynamic programming approach and +# some knowledge of combinatorics. +# 4. Let f(k) = count of numbers with unique digits with length equals k. +# 5. f(1) = 10, ..., f(k) = 9 * 9 * 8 * ... (9 - k + 2) +# [The first factor is 9 because a number cannot start with 0]. + +class Solution(object): + def countNumbersWithUniqueDigits(self, n): + """ + :type n: int + :rtype: int + """ + if n == 0: + return 1 + count, fk = 10, 9 + for k in xrange(2, n+1): + fk *= 10 - (k-1) + count += fk + return count diff --git a/Python/count-of-range-sum.py b/Python/count-of-range-sum.py new file mode 100644 index 000000000..eb87af804 --- /dev/null +++ b/Python/count-of-range-sum.py @@ -0,0 +1,97 @@ +# Time: O(nlogn) +# Space: O(n) + +# Given an integer array nums, return the number of range +# sums that lie in [lower, upper] inclusive. +# Range sum S(i, j) is defined as the sum of the elements +# in nums between indices i and j (i <= j), inclusive. +# +# Note: +# A naive algorithm of O(n^2) is trivial. You MUST do better than that. +# +# Example: +# Given nums = [-2, 5, -1], lower = -2, upper = 2, +# Return 3. +# The three ranges are : [0, 0], [2, 2], [0, 2] and +# their respective sums are: -2, -1, 2. + +# Divide and Conquer solution. +class Solution(object): + def countRangeSum(self, nums, lower, upper): + """ + :type nums: List[int] + :type lower: int + :type upper: int + :rtype: int + """ + def countAndMergeSort(sums, start, end, lower, upper): + if end - start <= 1: # The size of range [start, end) less than 2 is always with count 0. + return 0 + mid = start + (end - start) / 2 + count = countAndMergeSort(sums, start, mid, lower, upper) + \ + countAndMergeSort(sums, mid, end, lower, upper) + j, k, r = mid, mid, mid + tmp = [] + for i in xrange(start, mid): + # Count the number of range sums that lie in [lower, upper]. + while k < end and sums[k] - sums[i] < lower: + k += 1 + while j < end and sums[j] - sums[i] <= upper: + j += 1 + count += j - k + + # Merge the two sorted arrays into tmp. + while r < end and sums[r] < sums[i]: + tmp.append(sums[r]) + r += 1 + tmp.append(sums[i]) + # Copy tmp back to sums. + sums[start:start+len(tmp)] = tmp + return count + + sums = [0] * (len(nums) + 1) + for i in xrange(len(nums)): + sums[i + 1] = sums[i] + nums[i] + return countAndMergeSort(sums, 0, len(sums), lower, upper) + + +# Divide and Conquer solution. +class Solution2(object): + def countRangeSum(self, nums, lower, upper): + """ + :type nums: List[int] + :type lower: int + :type upper: int + :rtype: int + """ + def countAndMergeSort(sums, start, end, lower, upper): + if end - start <= 0: # The size of range [start, end] less than 2 is always with count 0. + return 0 + + mid = start + (end - start) / 2 + count = countAndMergeSort(sums, start, mid, lower, upper) + \ + countAndMergeSort(sums, mid + 1, end, lower, upper) + j, k, r = mid + 1, mid + 1, mid + 1 + tmp = [] + for i in xrange(start, mid + 1): + # Count the number of range sums that lie in [lower, upper]. + while k <= end and sums[k] - sums[i] < lower: + k += 1 + while j <= end and sums[j] - sums[i] <= upper: + j += 1 + count += j - k + + # Merge the two sorted arrays into tmp. + while r <= end and sums[r] < sums[i]: + tmp.append(sums[r]) + r += 1 + tmp.append(sums[i]) + + # Copy tmp back to sums + sums[start:start+len(tmp)] = tmp + return count + + sums = [0] * (len(nums) + 1) + for i in xrange(len(nums)): + sums[i + 1] = sums[i] + nums[i] + return countAndMergeSort(sums, 0, len(sums) - 1, lower, upper) diff --git a/Python/count-of-smaller-numbers-after-self.py b/Python/count-of-smaller-numbers-after-self.py new file mode 100644 index 000000000..7011fa583 --- /dev/null +++ b/Python/count-of-smaller-numbers-after-self.py @@ -0,0 +1,164 @@ +# Time: O(nlogn) +# Space: O(n) + +# You are given an integer array nums and you have to +# return a new counts array. The counts array has the +# property where counts[i] is the number of smaller +# elements to the right of nums[i]. +# +# Example: +# +# Given nums = [5, 2, 6, 1] +# +# To the right of 5 there are 2 smaller elements (2 and 1). +# To the right of 2 there is only 1 smaller element (1). +# To the right of 6 there is 1 smaller element (1). +# To the right of 1 there is 0 smaller element. +# Return the array [2, 1, 1, 0]. + +# Divide and Conquer solution. +class Solution(object): + def countSmaller(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + def countAndMergeSort(num_idxs, start, end, counts): + if end - start <= 0: # The size of range [start, end] less than 2 is always with count 0. + return 0 + + mid = start + (end - start) / 2 + countAndMergeSort(num_idxs, start, mid, counts) + countAndMergeSort(num_idxs, mid + 1, end, counts) + r = mid + 1 + tmp = [] + for i in xrange(start, mid + 1): + # Merge the two sorted arrays into tmp. + while r <= end and num_idxs[r][0] < num_idxs[i][0]: + tmp.append(num_idxs[r]) + r += 1 + tmp.append(num_idxs[i]) + counts[num_idxs[i][1]] += r - (mid + 1) + + # Copy tmp back to num_idxs + num_idxs[start:start+len(tmp)] = tmp + + num_idxs = [] + counts = [0] * len(nums) + for i, num in enumerate(nums): + num_idxs.append((num, i)) + countAndMergeSort(num_idxs, 0, len(num_idxs) - 1, counts) + return counts + +# Time: O(nlogn) +# Space: O(n) +# BIT solution. +class Solution2(object): + def countSmaller(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + def binarySearch(A, target, compare): + start, end = 0, len(A) - 1 + while start <= end: + mid = start + (end - start) / 2 + if compare(target, A[mid]): + end = mid - 1 + else: + start = mid + 1 + return start + + class BIT(object): + def __init__(self, n): + self.__bit = [0] * n + + def add(self, i, val): + while i < len(self.__bit): + self.__bit[i] += val + i += (i & -i) + + def query(self, i): + ret = 0 + while i > 0: + ret += self.__bit[i] + i -= (i & -i) + return ret + + # Get the place (position in the ascending order) of each number. + sorted_nums, places = sorted(nums), [0] * len(nums) + for i, num in enumerate(nums): + places[i] = binarySearch(sorted_nums, num, lambda x, y: x <= y) + + # Count the smaller elements after the number. + ans, bit= [0] * len(nums), BIT(len(nums) + 1) + for i in reversed(xrange(len(nums))): + ans[i] = bit.query(places[i]) + bit.add(places[i] + 1, 1) + return ans + +# Time: O(nlogn) +# Space: O(n) +# BST solution. +class Solution3(object): + def countSmaller(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + res = [0] * len(nums) + bst = self.BST() + # Insert into BST and get left count. + for i in reversed(xrange(len(nums))): + bst.insertNode(nums[i]) + res[i] = bst.query(nums[i]) + + return res + + class BST(object): + class BSTreeNode(object): + def __init__(self, val): + self.val = val + self.count = 0 + self.left = self.right = None + + def __init__(self): + self.root = None + + # Insert node into BST. + def insertNode(self, val): + node = self.BSTreeNode(val) + if not self.root: + self.root = node + return + curr = self.root + while curr: + # Insert left if smaller. + if node.val < curr.val: + curr.count += 1 # Increase the number of left children. + if curr.left: + curr = curr.left; + else: + curr.left = node; + break + else: # Insert right if larger or equal. + if curr.right: + curr = curr.right + else: + curr.right = node + break + + # Query the smaller count of the value. + def query(self, val): + count = 0 + curr = self.root + while curr: + # Insert left. + if val < curr.val: + curr = curr.left + elif val > curr.val: + count += 1 + curr.count # Count the number of the smaller nodes. + curr = curr.right + else: # Equal. + return count + curr.count + return 0 diff --git a/Python/count-primes.py b/Python/count-primes.py new file mode 100644 index 000000000..46ad88ddf --- /dev/null +++ b/Python/count-primes.py @@ -0,0 +1,48 @@ +# Time: O(n) +# Space: O(n) + +# Description: +# +# Count the number of prime numbers less than a non-negative number, n +# +# Hint: The number n could be in the order of 100,000 to 5,000,000. + + +class Solution: + # @param {integer} n + # @return {integer} + def countPrimes(self, n): + if n <= 2: + return 0 + + is_prime = [True] * n + num = n / 2 + for i in xrange(3, n, 2): + if i * i >= n: + break + + if not is_prime[i]: + continue + + for j in xrange(i*i, n, 2*i): + if not is_prime[j]: + continue + + num -= 1 + is_prime[j] = False + + return num + + def countPrimes2(self, n): + """ + :type n: int + :rtype: int + """ + if n < 3: + return 0 + primes = [True] * n + primes[0] = primes[1] = False + for i in range(2, int(n ** 0.5) + 1): + if primes[i]: + primes[i * i: n: i] = [False] * len(primes[i * i: n: i]) + return sum(primes) diff --git a/Python/count-the-repetitions.py b/Python/count-the-repetitions.py new file mode 100644 index 000000000..eeaee7b70 --- /dev/null +++ b/Python/count-the-repetitions.py @@ -0,0 +1,51 @@ +# Time: O(s1 * min(s2, n1)) +# Space: O(s2) + +# Define S = [s,n] as the string S which consists of n connected strings s. +# For example, ["abc", 3] ="abcabcabc". +# +# On the other hand, we define that string s1 can be obtained from string s2 +# if we can remove some characters from s2 such that it becomes s1. +# For example, “abc” can be obtained from “abdbec” based on our definition, but it can not be obtained from “acbbe”. +# +# You are given two non-empty strings s1 and s2 (each at most 100 characters long) +# and two integers 0 ≤ n1 ≤ 106 and 1 ≤ n2 ≤ 106. Now consider the strings S1 and S2, +# where S1=[s1,n1] and S2=[s2,n2]. Find the maximum integer M such that [S2,M] can be obtained from S1. +# +# Example: +# +# Input: +# s1="acb", n1=4 +# s2="ab", n2=2 +# +# Return: +# 2 + +class Solution(object): + def getMaxRepetitions(self, s1, n1, s2, n2): + """ + :type s1: str + :type n1: int + :type s2: str + :type n2: int + :rtype: int + """ + repeat_count = [0] * (len(s2)+1) + lookup = {} + j, count = 0, 0 + for k in xrange(1, n1+1): + for i in xrange(len(s1)): + if s1[i] == s2[j]: + j = (j + 1) % len(s2) + count += (j == 0) + + if j in lookup: # cyclic + i = lookup[j] + prefix_count = repeat_count[i] + pattern_count = (count - repeat_count[i]) * ((n1 - i) // (k - i)) + suffix_count = repeat_count[i + (n1 - i) % (k - i)] - repeat_count[i] + return (prefix_count + pattern_count + suffix_count) / n2 + lookup[j] = k + repeat_count[k] = count + + return repeat_count[n1] / n2 # not cyclic iff n1 <= s2 diff --git a/Python/count-univalue-subtrees.py b/Python/count-univalue-subtrees.py new file mode 100644 index 000000000..a393f4304 --- /dev/null +++ b/Python/count-univalue-subtrees.py @@ -0,0 +1,32 @@ +# Time: O(n) +# Space: O(h) +# +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @return {integer} + def countUnivalSubtrees(self, root): + [is_uni, count] = self.isUnivalSubtrees(root, 0); + return count; + + def isUnivalSubtrees(self, root, count): + if not root: + return [True, count] + + [left, count] = self.isUnivalSubtrees(root.left, count) + [right, count] = self.isUnivalSubtrees(root.right, count) + if self.isSame(root, root.left, left) and \ + self.isSame(root, root.right, right): + count += 1 + return [True, count] + + return [False, count] + + def isSame(self, root, child, is_uni): + return not child or (is_uni and root.val == child.val) diff --git a/Python/counting-bits.py b/Python/counting-bits.py new file mode 100644 index 000000000..6ef845380 --- /dev/null +++ b/Python/counting-bits.py @@ -0,0 +1,55 @@ +# Time: O(n) +# Space: O(n) + +# Given a non negative integer number num. For every numbers i +# in the range 0 <= i <= num calculate the number +# of 1's in their binary representation and return them as an array. +# +# Example: +# For num = 5 you should return [0,1,1,2,1,2]. +# +# Follow up: +# +# It is very easy to come up with a solution with run +# time O(n*sizeof(integer)). But can you do it in +# linear time O(n) /possibly in a single pass? +# Space complexity should be O(n). +# Can you do it like a boss? Do it without using +# any builtin function like __builtin_popcount in c++ or +# in any other language. +# Hint: +# +# 1. You should make use of what you have produced already. +# 2. Divide the numbers in ranges like [2-3], [4-7], [8-15] +# and so on. And try to generate new range from previous. +# 3. Or does the odd/even status of the number help you in +# calculating the number of 1s? + + +class Solution(object): + def countBits(self, num): + """ + :type num: int + :rtype: List[int] + """ + res = [0] + for i in xrange(1, num + 1): + # Number of 1's in i = (i & 1) + number of 1's in (i / 2). + res.append((i & 1) + res[i >> 1]) + return res + + def countBits2(self, num): + """ + :type num: int + :rtype: List[int] + """ + s = [0] + while len(s) <= num: + s.extend(map(lambda x: x + 1, s)) + return s[:num + 1] + + +if __name__ == '__main__': + s = Solution() + r = s.countBits2(5) + print r diff --git a/Python/course-schedule-ii.py b/Python/course-schedule-ii.py new file mode 100644 index 000000000..c7e9c290b --- /dev/null +++ b/Python/course-schedule-ii.py @@ -0,0 +1,74 @@ +# Time: O(|V| + |E|) +# Space: O(|E|) + +# There are a total of n courses you have to take, labeled from 0 to n - 1. +# +# Some courses may have prerequisites, for example to take course 0 you have to first take course 1, +# which is expressed as a pair: [0,1] +# +# Given the total number of courses and a list of prerequisite pairs, return the ordering of courses +# you should take to finish all courses. +# +# There may be multiple correct orders, you just need to return one of them. If it is impossible +# to finish all courses, return an empty array. +# +# For example: +# +# 2, [[1,0]] +# There are a total of 2 courses to take. To take course 1 you should have finished course 0. +# So the correct course order is [0,1] +# +# 4, [[1,0],[2,0],[3,1],[3,2]] +# There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. +# Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. +# Another correct ordering is[0,2,1,3]. +# +# Note: +# The input prerequisites is a graph represented by a list of edges, not adjacency matrices. +# Read more about how a graph is represented. +# +# Hints: +# This problem is equivalent to finding the topological order in a directed graph. +# If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses. +# Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining +# the basic concepts of Topological Sort. +# Topological sort could also be done via BFS. +# + +class Solution(object): + def findOrder(self, numCourses, prerequisites): + """ + :type numCourses: int + :type prerequisites: List[List[int]] + :rtype: List[int] + """ + res, zero_in_degree_queue, in_degree, out_degree = [], collections.deque(), {}, {} + + for i, j in prerequisites: + if i not in in_degree: + in_degree[i] = set() + if j not in out_degree: + out_degree[j] = set() + in_degree[i].add(j) + out_degree[j].add(i) + + for i in xrange(numCourses): + if i not in in_degree: + zero_in_degree_queue.append(i) + + while zero_in_degree_queue: + prerequisite = zero_in_degree_queue.popleft() + res.append(prerequisite) + + if prerequisite in out_degree: + for course in out_degree[prerequisite]: + in_degree[course].discard(prerequisite) + if not in_degree[course]: + zero_in_degree_queue.append(course) + + del out_degree[prerequisite] + + if out_degree: + return [] + + return res diff --git a/Python/course-schedule-iii.py b/Python/course-schedule-iii.py new file mode 100644 index 000000000..af874fc69 --- /dev/null +++ b/Python/course-schedule-iii.py @@ -0,0 +1,42 @@ +# Time: O(nlogn) +# Space: O(k), k is the number of courses you can take + +# There are n different online courses numbered from 1 to n. +# Each course has some duration(course length) t and closed on dth day. +# A course should be taken continuously for t days and must be finished before or on the dth day. +# You will start at the 1st day. +# +# Given n online courses represented by pairs (t,d), your task is to find the maximal number of courses that can be taken. +# +# Example: +# Input: [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]] +# Output: 3 +# Explanation: +# There're totally 4 courses, but you can take 3 courses at most: +# First, take the 1st course, it costs 100 days so you will finish it on the 100th day, +# and ready to take the next course on the 101st day. +# Second, take the 3rd course, it costs 1000 days so you will finish it on the 1100th day, +# and ready to take the next course on the 1101st day. +# Third, take the 2nd course, it costs 200 days so you will finish it on the 1300th day. +# The 4th course cannot be taken now, since you will finish it on the 3300th day, +# which exceeds the closed date. +# +# Note: +# The integer 1 <= d, t, n <= 10,000. +# You can't take two courses simultaneously. + +class Solution(object): + def scheduleCourse(self, courses): + """ + :type courses: List[List[int]] + :rtype: int + """ + courses.sort(key=lambda(t, end): end) + max_heap = [] + now = 0 + for t, end in courses: + now += t + heapq.heappush(max_heap, -t) + if now > end: + now += heapq.heappop(max_heap) + return len(max_heap) diff --git a/Python/course-schedule.py b/Python/course-schedule.py new file mode 100644 index 000000000..158d6a9d0 --- /dev/null +++ b/Python/course-schedule.py @@ -0,0 +1,72 @@ +# Time: O(|V| + |E|) +# Space: O(|E|) +# +# There are a total of n courses you have to take, labeled from 0 to n - 1. +# +# Some courses may have prerequisites, for example to take course 0 +# you have to first take course 1, which is expressed as a pair: [0,1] +# +# Given the total number of courses and a list of prerequisite pairs, +# is it possible for you to finish all courses? +# +# For example: +# +# 2, [[1,0]] +# There are a total of 2 courses to take. To take course 1 +# you should have finished course 0. So it is possible. +# +# 2, [[1,0],[0,1]] +# There are a total of 2 courses to take. To take course 1 you should have +# finished course 0, and to take course 0 you should also have finished course 1. So it is impossible. +# +# click to show more hints. +# +# Hints: +# This problem is equivalent to finding if a cycle exists in a directed graph. +# If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses. +# There are several ways to represent a graph. For example, the input prerequisites is a graph represented by +# a list of edges. Is this graph representation appropriate? +# Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts +# of Topological Sort. +# Topological sort could also be done via BFS. +# +class Solution(object): + def canFinish(self, numCourses, prerequisites): + """ + :type numCourses: int + :type prerequisites: List[List[int]] + :rtype: bool + """ + zero_in_degree_queue, in_degree, out_degree = collections.deque(), {}, {} + + for i, j in prerequisites: + if i not in in_degree: + in_degree[i] = set() + if j not in out_degree: + out_degree[j] = set() + in_degree[i].add(j) + out_degree[j].add(i) + + for i in xrange(numCourses): + if i not in in_degree: + zero_in_degree_queue.append(i) + + while zero_in_degree_queue: + prerequisite = zero_in_degree_queue.popleft() + + if prerequisite in out_degree: + for course in out_degree[prerequisite]: + in_degree[course].discard(prerequisite) + if not in_degree[course]: + zero_in_degree_queue.append(course) + + del out_degree[prerequisite] + + if out_degree: + return False + + return True + + +if __name__ == "__main__": + print Solution().canFinish(1, []) diff --git a/Python/create-maximum-number.py b/Python/create-maximum-number.py new file mode 100644 index 000000000..af1d98541 --- /dev/null +++ b/Python/create-maximum-number.py @@ -0,0 +1,71 @@ +# Time: O(k * (m + n + k)) ~ O(k * (m + n + k^2)) +# Space: O(m + n + k^2) +# +# Given two arrays of length m and n with digits 0-9 representing two numbers. +# Create the maximum number of length k <= m + n from digits of the two. +# The relative order of the digits from the same array must be preserved. +# Return an array of the k digits. You should try to optimize your time +# and space complexity. +# +# Example 1: +# nums1 = [3, 4, 6, 5] +# nums2 = [9, 1, 2, 5, 8, 3] +# k = 5 +# return [9, 8, 6, 5, 3] +# +# Example 2: +# nums1 = [6, 7] +# nums2 = [6, 0, 4] +# k = 5 +# return [6, 7, 6, 0, 4] +# +# Example 3: +# nums1 = [3, 9] +# nums2 = [8, 9] +# k = 3 +# return [9, 8, 9] +# + +# DP + Greedy solution. (280ms) +class Solution(object): + def maxNumber(self, nums1, nums2, k): + """ + :type nums1: List[int] + :type nums2: List[int] + :type k: int + :rtype: List[int] + """ + def get_max_digits(nums, start, end, max_digits): + max_digits[end] = max_digit(nums, end) + for i in reversed(xrange(start, end)): + max_digits[i] = delete_digit(max_digits[i + 1]) + + def max_digit(nums, k): + drop = len(nums) - k + res = [] + for num in nums: + while drop and res and res[-1] < num: + res.pop() + drop -= 1 + res.append(num) + return res[:k] + + def delete_digit(nums): + res = list(nums) + for i in xrange(len(res)): + if i == len(res) - 1 or res[i] < res[i + 1]: + res = res[:i] + res[i+1:] + break + return res + + def merge(a, b): + return [max(a, b).pop(0) for _ in xrange(len(a)+len(b))] + + m, n = len(nums1), len(nums2) + + max_digits1, max_digits2 = [[] for _ in xrange(k + 1)], [[] for _ in xrange(k + 1)] + get_max_digits(nums1, max(0, k - n), min(k, m), max_digits1) + get_max_digits(nums2, max(0, k - m), min(k, n), max_digits2) + + return max(merge(max_digits1[i], max_digits2[k-i]) \ + for i in xrange(max(0, k - n), min(k, m) + 1)) diff --git a/Python/cut-off-trees-for-golf-event.py b/Python/cut-off-trees-for-golf-event.py new file mode 100644 index 000000000..b71b21091 --- /dev/null +++ b/Python/cut-off-trees-for-golf-event.py @@ -0,0 +1,147 @@ +# Time: O(t * (logt + m * n)), t is the number of trees +# Space: O(t + m * n) + +# You are asked to cut off trees in a forest for a golf event. +# The forest is represented as a non-negative 2D map, in this map: +# +# 0 represents the obstacle can't be reached. +# 1 represents the ground can be walked through. +# The place with number bigger than 1 represents a tree can be walked through, +# and this positive number represents the tree's height. +# +# You are asked to cut off all the trees in this forest in the order of tree's height - +# always cut off the tree with lowest height first. And after cutting, the original place +# has the tree will become a grass (value 1). +# +# You will start from the point (0, 0) +# and you should output the minimum steps you need to walk to cut off all the trees. +# If you can't cut off all the trees, output -1 in that situation. +# +# You are guaranteed that no two trees have the same height and there is at least one tree needs to be cut off. +# +# Example 1: +# Input: +# [ +# [1,2,3], +# [0,0,4], +# [7,6,5] +# ] +# Output: 6 +# Example 2: +# Input: +# [ +# [1,2,3], +# [0,0,0], +# [7,6,5] +# ] +# Output: -1 +# Example 3: +# Input: +# [ +# [2,3,4], +# [0,0,5], +# [8,7,6] +# ] +# Output: 6 +# Explanation: You started from the point (0,0) and you can cut off the tree +# in (0,0) directly without walking. +# Hint: size of the given matrix will not exceed 50x50. + +# Solution Reference: +# 1. https://discuss.leetcode.com/topic/103532/my-python-solution-inspired-by-a-algorithm/2 +# 2. https://discuss.leetcode.com/topic/103562/python-solution-based-on-wufangjie-s-hadlock-s-algorithm +# 3. https://en.wikipedia.org/wiki/A*_search_algorithm +# 4. https://cg2010studio.files.wordpress.com/2011/12/dijkstra-vs-a-star.png +class Solution(object): + def cutOffTree(self, forest): + """ + :type forest: List[List[int]] + :rtype: int + """ + def dot(p1, p2): + return p1[0]*p2[0]+p1[1]*p2[1] + + def minStep(p1, p2): + min_steps = abs(p1[0]-p2[0])+abs(p1[1]-p2[1]) + closer, detour = [p1], [] + lookup = set() + while True: + if not closer: # cannot find a path in the closer expansions + if not detour: # no other possible path + return -1 + # try other possible paths in detour expansions with extra 2-step cost + min_steps += 2 + closer, detour = detour, closer + i, j = closer.pop() + if (i, j) == p2: + return min_steps + if (i, j) not in lookup: + lookup.add((i, j)) + for I, J in (i+1, j), (i-1, j), (i, j+1), (i, j-1): + if 0 <= I < m and 0 <= J < n and forest[I][J] and (I, J) not in lookup: + is_closer = dot((I-i, J-j), (p2[0]-i, p2[1]-j)) > 0 + (closer if is_closer else detour).append((I, J)) + return min_steps + + m, n = len(forest), len(forest[0]) + min_heap = [] + for i in xrange(m): + for j in xrange(n): + if forest[i][j] > 1: + heapq.heappush(min_heap, (forest[i][j], (i, j))) + + start = (0, 0) + result = 0 + while min_heap: + tree = heapq.heappop(min_heap) + step = minStep(start, tree[1]) + if step < 0: + return -1 + result += step + start = tree[1] + return result + + +# Time: O(t * (logt + m * n)), t is the number of trees +# Space: O(t + m * n) +class Solution_TLE(object): + def cutOffTree(self, forest): + """ + :type forest: List[List[int]] + :rtype: int + """ + def minStep(p1, p2): + min_steps = 0 + lookup = {p1} + q = collections.deque([p1]) + while q: + size = len(q) + for _ in xrange(size): + (i, j) = q.popleft() + if (i, j) == p2: + return min_steps + for i, j in (i+1, j), (i-1, j), (i, j+1), (i, j-1): + if not (0 <= i < m and 0 <= j < n and forest[i][j] and (i, j) not in lookup): + continue + q.append((i, j)) + lookup.add((i, j)) + min_steps += 1 + return -1 + + m, n = len(forest), len(forest[0]) + min_heap = [] + for i in xrange(m): + for j in xrange(n): + if forest[i][j] > 1: + heapq.heappush(min_heap, (forest[i][j], (i, j))) + + start = (0, 0) + result = 0 + while min_heap: + tree = heapq.heappop(min_heap) + step = minStep(start, tree[1]) + if step < 0: + return -1 + result += step + start = tree[1] + return result diff --git a/Python/daily-temperatures.py b/Python/daily-temperatures.py new file mode 100644 index 000000000..841982d81 --- /dev/null +++ b/Python/daily-temperatures.py @@ -0,0 +1,28 @@ +# Time: O(n) +# Space: O(n) + +# Given a list of daily temperatures, produce a list that, +# for each day in the input, tells you how many days you would have to wait until +# a warmer temperature. If there is no future day for which this is possible, put 0 instead. +# +# For example, given the list temperatures = [73, 74, 75, 71, 69, 72, 76, 73], +# your output should be [1, 1, 4, 2, 1, 1, 0, 0]. +# +# Note: The length of temperatures will be in the range [1, 30000]. +# Each temperature will be an integer in the range [30, 100]. + +class Solution(object): + def dailyTemperatures(self, temperatures): + """ + :type temperatures: List[int] + :rtype: List[int] + """ + result = [0] * len(temperatures) + stk = [] + for i in xrange(len(temperatures)): + while stk and \ + temperatures[stk[-1]] < temperatures[i]: + idx = stk.pop() + result[idx] = i-idx + stk.append(i) + return result diff --git a/Python/data-stream-as-disjoint-intervals.py b/Python/data-stream-as-disjoint-intervals.py new file mode 100644 index 000000000..48b6188a8 --- /dev/null +++ b/Python/data-stream-as-disjoint-intervals.py @@ -0,0 +1,70 @@ +# Time: addNum: O(n), getIntervals: O(n), n is the number of disjoint intervals. +# Space: O(n) + +# Given a data stream input of non-negative integers a1, a2, ..., an, ..., +# summarize the numbers seen so far as a list of disjoint intervals. +# +# For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, +# ..., then the summary will be: +# +# [1, 1] +# [1, 1], [3, 3] +# [1, 1], [3, 3], [7, 7] +# [1, 3], [7, 7] +# [1, 3], [6, 7] +# +# Follow up: +# What if there are lots of merges and the number of disjoint intervals +# are small compared to the data stream's size? + +# Definition for an interval. +# class Interval(object): +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class SummaryRanges(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.__intervals = [] + + def addNum(self, val): + """ + :type val: int + :rtype: void + """ + def upper_bound(nums, target): + left, right = 0, len(nums) - 1 + while left <= right: + mid = left + (right - left) / 2 + if nums[mid].start > target: + right = mid - 1 + else: + left = mid + 1 + return left + + i = upper_bound(self.__intervals, val) + start, end = val, val + if i != 0 and self.__intervals[i-1].end + 1 >= val: + i -= 1 + while i != len(self.__intervals) and \ + end + 1 >= self.__intervals[i].start: + start = min(start, self.__intervals[i].start) + end = max(end, self.__intervals[i].end); + del self.__intervals[i] + self.__intervals.insert(i, Interval(start, end)) + + def getIntervals(self): + """ + :rtype: List[Interval] + """ + return self.__intervals + + +# Your SummaryRanges object will be instantiated and called as such: +# obj = SummaryRanges() +# obj.addNum(val) +# param_2 = obj.getIntervals() diff --git a/Python/decode-string.py b/Python/decode-string.py new file mode 100644 index 000000000..ab0256f17 --- /dev/null +++ b/Python/decode-string.py @@ -0,0 +1,47 @@ +# Time: O(n) +# Space: O(h), h is the depth of the recursion + +# Given an encoded string, return it's decoded string. +# +# The encoding rule is: k[encoded_string], +# where the encoded_string inside the square brackets is +# being repeated exactly k times. Note that k is guaranteed +# to be a positive integer. +# +# You may assume that the input string is always valid; +# No extra white spaces, square brackets are well-formed, etc. +# +# Furthermore, you may assume that the original data does not +# contain any digits and that digits are only for those repeat numbers, k. +# For example, there won't be input like 3a or 2[4]. +# +# Examples: +# +# s = "3[a]2[bc]", return "aaabcbc". +# s = "3[a2[c]]", return "accaccacc". +# s = "2[abc]3[cd]ef", return "abcabccdcdcdef". + +class Solution(object): + def decodeString(self, s): + """ + :type s: str + :rtype: str + """ + curr, nums, strs = [], [], [] + n = 0 + + for c in s: + if c.isdigit(): + n = n * 10 + ord(c) - ord('0') + elif c == '[': + nums.append(n) + n = 0 + strs.append(curr) + curr = [] + elif c == ']': + strs[-1].extend(curr * nums.pop()) + curr = strs.pop() + else: + curr.append(c) + + return "".join(strs[-1]) if strs else "".join(curr) diff --git a/Python/decode-ways-ii.py b/Python/decode-ways-ii.py new file mode 100644 index 000000000..f628b3f00 --- /dev/null +++ b/Python/decode-ways-ii.py @@ -0,0 +1,55 @@ +# Time: O(n) +# Space: O(1) + +# A message containing letters from A-Z is being encoded to numbers using the following mapping way: +# +# 'A' -> 1 +# 'B' -> 2 +# ... +# 'Z' -> 26 +# Beyond that, now the encoded string can also contain the character '*', +# which can be treated as one of the numbers from 1 to 9. +# +# Given the encoded message containing digits and the character '*', return the total number of ways to decode it. +# +# Also, since the answer may be very large, you should return the output mod 109 + 7. +# +# Example 1: +# Input: "*" +# Output: 9 +# Explanation: The encoded message can be decoded to the string: "A", "B", "C", "D", "E", "F", "G", "H", "I". +# Example 2: +# Input: "1*" +# Output: 9 + 9 = 18 +# Note: +# The length of the input string will fit in range [1, 105]. +# The input string will only contain the character '*' and digits '0' - '9'. + +class Solution(object): + def numDecodings(self, s): + """ + :type s: str + :rtype: int + """ + M, W = 1000000007, 3 + dp = [0] * W + dp[0] = 1 + dp[1] = 9 if s[0] == '*' else dp[0] if s[0] != '0' else 0 + for i in xrange(1, len(s)): + if s[i] == '*': + dp[(i + 1) % W] = 9 * dp[i % W] + if s[i - 1] == '1': + dp[(i + 1) % W] = (dp[(i + 1) % W] + 9 * dp[(i - 1) % W]) % M + elif s[i - 1] == '2': + dp[(i + 1) % W] = (dp[(i + 1) % W] + 6 * dp[(i - 1) % W]) % M + elif s[i - 1] == '*': + dp[(i + 1) % W] = (dp[(i + 1) % W] + 15 * dp[(i - 1) % W]) % M + else: + dp[(i + 1) % W] = dp[i % W] if s[i] != '0' else 0 + if s[i - 1] == '1': + dp[(i + 1) % W] = (dp[(i + 1) % W] + dp[(i - 1) % W]) % M + elif s[i - 1] == '2' and s[i] <= '6': + dp[(i + 1) % W] = (dp[(i + 1) % W] + dp[(i - 1) % W]) % M + elif s[i - 1] == '*': + dp[(i + 1) % W] = (dp[(i + 1) % W] + (2 if s[i] <= '6' else 1) * dp[(i - 1) % W]) % M + return dp[len(s) % W] diff --git a/Python/decode-ways.py b/Python/decode-ways.py index 6b84185bc..2f474480b 100644 --- a/Python/decode-ways.py +++ b/Python/decode-ways.py @@ -15,22 +15,25 @@ # The number of ways decoding "12" is 2. # -class Solution: - # @param s, a string - # @return an integer +class Solution(object): def numDecodings(self, s): + """ + :type s: str + :rtype: int + """ if len(s) == 0 or s[0] == '0': return 0 prev, prev_prev = 1, 0 - for i in range(len(s)): - current = 0 + for i in xrange(len(s)): + cur = 0 if s[i] != '0': - current = prev + cur = prev if i > 0 and (s[i - 1] == '1' or (s[i - 1] == '2' and s[i] <= '6')): - current += prev_prev - prev, prev_prev = current, prev + cur += prev_prev + prev, prev_prev = cur, prev return prev - + + if __name__ == "__main__": for i in ["0", "10", "10", "103", "1032", "10323"]: - print Solution().numDecodings(i) \ No newline at end of file + print Solution().numDecodings(i) diff --git a/Python/degree-of-an-array.py b/Python/degree-of-an-array.py new file mode 100644 index 000000000..567caa282 --- /dev/null +++ b/Python/degree-of-an-array.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(n) + +# Given a non-empty array of non-negative integers nums, +# the degree of this array is defined as the maximum frequency of any one of its elements. +# +# Your task is to find the smallest possible length of a (contiguous) subarray of nums, +# that has the same degree as nums. +# +# Example 1: +# Input: [1, 2, 2, 3, 1] +# Output: 2 +# Explanation: +# The input array has a degree of 2 because both elements 1 and 2 appear twice. +# Of the subarrays that have the same degree: +# [1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2] +# The shortest length is 2. So return 2. +# +# Example 2: +# Input: [1,2,2,3,1,4,2] +# Output: 6 +# Note: +# +# nums.length will be between 1 and 50,000. +# nums[i] will be an integer between 0 and 49,999. + +class Solution(object): + def findShortestSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + counts = collections.Counter(nums) + left, right = {}, {} + for i, num in enumerate(nums): + left.setdefault(num, i) + right[num] = i + degree = max(counts.values()) + return min(right[num]-left[num]+1 \ + for num in counts.keys() \ + if counts[num] == degree) + diff --git a/Python/delete-and-earn.py b/Python/delete-and-earn.py new file mode 100644 index 000000000..4327d0d2b --- /dev/null +++ b/Python/delete-and-earn.py @@ -0,0 +1,44 @@ +# Time: O(n) +# Space: O(1) + +# Given an array nums of integers, you can perform operations on the array. +# +# In each operation, you pick any nums[i] and delete it to earn nums[i] points. +# After, you must delete every element equal to nums[i] - 1 or nums[i] + 1. +# +# You start with 0 points. +# Return the maximum number of points you can earn by applying such operations. +# +# Example 1: +# Input: nums = [3, 4, 2] +# Output: 6 +# Explanation: +# Delete 4 to earn 4 points, consequently 3 is also deleted. +# Then, delete 2 to earn 2 points. 6 total points are earned. +# +# Example 2: +# Input: nums = [2, 2, 3, 3, 3, 4] +# Output: 9 +# Explanation: +# Delete 3 to earn 3 points, deleting both 2's and the 4. +# Then, delete 3 again to earn 3 points, and 3 again to earn 3 points. +# 9 total points are earned. +# +# Note: +# - The length of nums is at most 20000. +# - Each element nums[i] is an integer in the range [1, 10000]. + +class Solution(object): + def deleteAndEarn(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + vals = [0] * 10001 + for num in nums: + vals[num] += num + val_i, val_i_1 = vals[0], 0 + for i in xrange(1, len(vals)): + val_i_1, val_i_2 = val_i, val_i_1 + val_i = max(vals[i] + val_i_2, val_i_1) + return val_i diff --git a/Python/delete-node-in-a-bst.py b/Python/delete-node-in-a-bst.py new file mode 100644 index 000000000..04dd96f59 --- /dev/null +++ b/Python/delete-node-in-a-bst.py @@ -0,0 +1,42 @@ +# Time: O(h) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def deleteNode(self, root, key): + """ + :type root: TreeNode + :type key: int + :rtype: TreeNode + """ + if not root: + return root + + if root.val > key: + root.left = deleteNode(root.left, key) + elif root.val < key: + root.right = deleteNode(root.right, key) + else: + if not root.left: + right = root.right + del root + return right + elif not root.right: + left = root.left + del root + return left + else: + successor = root.right + while successor.left: + successor = successor.left + + root.val = successor.val + root.right = deleteNode(root.right, successor.val) + + return root diff --git a/Python/delete-node-in-a-linked-list.py b/Python/delete-node-in-a-linked-list.py new file mode 100644 index 000000000..9c3cce66b --- /dev/null +++ b/Python/delete-node-in-a-linked-list.py @@ -0,0 +1,24 @@ +# Time: O(1) +# Space: O(1) +# +# Write a function to delete a node (except the tail) in a singly linked list, +# given only access to that node. +# +# Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node +# with value 3, the linked list should become 1 -> 2 -> 4 after calling your function. +# +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + # @param {ListNode} node + # @return {void} Do not return anything, modify node in-place instead. + def deleteNode(self, node): + if node and node.next: + node_to_delete = node.next + node.val = node_to_delete.val + node.next = node_to_delete.next + del node_to_delete diff --git a/Python/delete-operation-for-two-strings.py b/Python/delete-operation-for-two-strings.py new file mode 100644 index 000000000..557948096 --- /dev/null +++ b/Python/delete-operation-for-two-strings.py @@ -0,0 +1,30 @@ +# Time: O(m * n) +# Space: O(n) + +# Given two words word1 and word2, +# find the minimum number of steps required to make word1 and word2 the same, +# where in each step you can delete one character in either string. +# +# Example 1: +# Input: "sea", "eat" +# Output: 2 +# Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea". +# Note: +# The length of given words won't exceed 500. +# Characters in given words can only be lower-case letters. + +class Solution(object): + def minDistance(self, word1, word2): + """ + :type word1: str + :type word2: str + :rtype: int + """ + m, n = len(word1), len(word2) + dp = [[0] * (n+1) for _ in xrange(2)] + for i in xrange(m): + for j in xrange(n): + dp[(i+1)%2][j+1] = max(dp[i%2][j+1], \ + dp[(i+1)%2][j], \ + dp[i%2][j] + (word1[i] == word2[j])) + return m + n - 2*dp[m%2][n] diff --git a/Python/design-compressed-string-iterator.py b/Python/design-compressed-string-iterator.py new file mode 100644 index 000000000..162840d79 --- /dev/null +++ b/Python/design-compressed-string-iterator.py @@ -0,0 +1,38 @@ +# Time: O(1) +# Space: O(1) + +class StringIterator(object): + + def __init__(self, compressedString): + """ + :type compressedString: str + """ + self.__result = re.findall(r"([a-zA-Z])(\d+)", compressedString) + self.__index, self.__num, self.__ch = 0, 0, ' ' + + def next(self): + """ + :rtype: str + """ + if not self.hasNext(): + return ' ' + if self.__num == 0: + self.__ch = self.__result[self.__index][0] + self.__num = int(self.__result[self.__index][1]) + self.__index += 1 + self.__num -= 1 + return self.__ch + + + def hasNext(self): + """ + :rtype: bool + """ + return self.__index != len(self.__result) or self.__num != 0 + + + +# Your StringIterator object will be instantiated and called as such: +# obj = StringIterator(compressedString) +# param_1 = obj.next() +# param_2 = obj.hasNext() diff --git a/Python/design-excel-sum-formula.py b/Python/design-excel-sum-formula.py new file mode 100644 index 000000000..24a1b47ca --- /dev/null +++ b/Python/design-excel-sum-formula.py @@ -0,0 +1,90 @@ +# Time: set: O((r * c)^2) +# get: O(1) +# sum: O((r * c)^2) +# Space: O(r * c) + +class Excel(object): + + def __init__(self, H, W): + """ + :type H: int + :type W: str + """ + self.__exl = [[0 for _ in xrange(ord(W)-ord('A')+1)] \ + for _ in xrange(H+1)] + self.__fward = collections.defaultdict(lambda : collections.defaultdict(int)) + self.__bward = collections.defaultdict(set) + + + def set(self, r, c, v): + """ + :type r: int + :type c: str + :type v: int + :rtype: void + """ + self.__reset_dependency(r, c); + self.__update_others(r, c, v); + + + def get(self, r, c): + """ + :type r: int + :type c: str + :rtype: int + """ + return self.__exl[r][ord(c) - ord('A')] + + + def sum(self, r, c, strs): + """ + :type r: int + :type c: str + :type strs: List[str] + :rtype: int + """ + self.__reset_dependency(r, c) + result = self.__calc_and_update_dependency(r, c, strs) + self.__update_others(r, c, result) + return result + + + def __reset_dependency(self, r, c): + key = (r, c) + if key in self.__bward.keys(): + for k in self.__bward[key]: + self.__fward[k].pop(key, None) + self.__bward[key] = set() + + + def __calc_and_update_dependency(self, r, c, strs): + result = 0 + for s in strs: + s, e = s.split(':')[0], s.split(':')[1] if ':' in s else s + left, right, top, bottom = ord(s[0])-ord('A'), ord(e[0])-ord('A'), int(s[1:]), int(e[1:]) + for i in xrange(top, bottom+1): + for j in xrange(left, right+1): + result += self.__exl[i][j] + self.__fward[(i, chr(ord('A')+j))][(r, c)] += 1 + self.__bward[(r, c)].add((i, chr(ord('A')+j))) + return result + + + def __update_others(self, r, c, v): + prev = self.__exl[r][ord(c)-ord('A')] + self.__exl[r][ord(c)-ord('A')] = v + q = collections.deque() + q.append(((r, c), v-prev)) + while q: + key, diff = q.popleft() + if key in self.__fward: + for k, count in self.__fward[key].iteritems(): + q.append((k, diff*count)) + self.__exl[k[0]][ord(k[1])-ord('A')] += diff*count + + +# Your Excel object will be instantiated and called as such: +# obj = Excel(H, W) +# obj.set(r,c,v) +# param_2 = obj.get(r,c) +# param_3 = obj.sum(r,c,strs) diff --git a/Python/design-hit-counter.py b/Python/design-hit-counter.py new file mode 100644 index 000000000..f5ad39b18 --- /dev/null +++ b/Python/design-hit-counter.py @@ -0,0 +1,44 @@ +# Time: O(1), amortized +# Space: O(k), k is the count of seconds. + +from collections import deque + +class HitCounter(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.__k = 300 + self.__dq = deque() + self.__count = 0 + + def hit(self, timestamp): + """ + Record a hit. + @param timestamp - The current timestamp (in seconds granularity). + :type timestamp: int + :rtype: void + """ + self.getHits(timestamp) + if self.__dq and self.__dq[-1][0] == timestamp: + self.__dq[-1][1] += 1 + else: + self.__dq.append([timestamp, 1]) + self.__count += 1 + + def getHits(self, timestamp): + """ + Return the number of hits in the past 5 minutes. + @param timestamp - The current timestamp (in seconds granularity). + :type timestamp: int + :rtype: int + """ + while self.__dq and self.__dq[0][0] <= timestamp - self.__k: + self.__count -= self.__dq.popleft()[1] + return self.__count + +# Your HitCounter object will be instantiated and called as such: +# obj = HitCounter() +# obj.hit(timestamp) +# param_2 = obj.getHits(timestamp) diff --git a/Python/design-in-memory-file-system.py b/Python/design-in-memory-file-system.py new file mode 100644 index 000000000..ae5ee030c --- /dev/null +++ b/Python/design-in-memory-file-system.py @@ -0,0 +1,122 @@ +# Time: ls: O(l + klogk), l is the path length, k is the number of entries in the last level directory +# mkdir: O(l) +# addContentToFile: O(l + c), c is the content size +# readContentFromFile: O(l + c) +# Space: O(n + s), n is the number of dir/file nodes, s is the total content size. + +# Design an in-memory file system to simulate the following functions: +# +# ls: Given a path in string format. If it is a file path, +# return a list that only contains this file's name. +# If it is a directory path, return the list of file and directory names in this directory. +# Your output (file and directory names together) should in lexicographic order. +# +# mkdir: Given a directory path that does not exist, +# you should make a new directory according to the path. +# If the middle directories in the path don't exist either, +# you should create them as well. This function has void return type. +# +# addContentToFile: Given a file path and file content in string format. +# If the file doesn't exist, you need to create that file containing given content. +# If the file already exists, you need to append given content to original content. +# This function has void return type. +# +# readContentFromFile: Given a file path, return its content in string format. +# +# Example: +# Input: +# ["FileSystem","ls","mkdir","addContentToFile","ls","readContentFromFile"] +# [[],["/"],["/a/b/c"],["/a/b/c/d","hello"],["/"],["/a/b/c/d"]] +# Output: +# [null,[],null,null,["a"],"hello"] +# +# Note: +# 1. You can assume all file or directory paths are absolute paths +# which begin with / and do not end with / except that the path is just "/". +# 2. You can assume that all operations will be passed valid parameters and +# users will not attempt to retrieve file content or list a directory or file that does not exist. +# 3. You can assume that all directory names and file names only contain lower-case letters, +# and same names won't exist in the same directory. + + +class TrieNode(object): + + def __init__(self): + self.is_file = False + self.children = {} + self.content = "" + +class FileSystem(object): + + def __init__(self): + self.__root = TrieNode() + + + def ls(self, path): + """ + :type path: str + :rtype: List[str] + """ + curr = self.__getNode(path) + + if curr.is_file: + return [self.__split(path, '/')[-1]] + + return sorted(curr.children.keys()) + + + def mkdir(self, path): + """ + :type path: str + :rtype: void + """ + curr = self.__putNode(path) + curr.is_file = False + + + def addContentToFile(self, filePath, content): + """ + :type filePath: str + :type content: str + :rtype: void + """ + curr = self.__putNode(filePath) + curr.is_file = True + curr.content += content + + + def readContentFromFile(self, filePath): + """ + :type filePath: str + :rtype: str + """ + return self.__getNode(filePath).content + + + def __getNode(self, path): + curr = self.__root + for s in self.__split(path, '/'): + curr = curr.children[s] + return curr + + + def __putNode(self, path): + curr = self.__root + for s in self.__split(path, '/'): + if s not in curr.children: + curr.children[s] = TrieNode() + curr = curr.children[s] + return curr + + + def __split(self, path, delim): + if path == '/': + return [] + return path.split('/')[1:] + +# Your FileSystem object will be instantiated and called as such: +# obj = FileSystem() +# param_1 = obj.ls(path) +# obj.mkdir(path) +# obj.addContentToFile(filePath,content) +# param_4 = obj.readContentFromFile(filePath) diff --git a/Python/design-log-storage-system.py b/Python/design-log-storage-system.py new file mode 100644 index 000000000..976a44f50 --- /dev/null +++ b/Python/design-log-storage-system.py @@ -0,0 +1,40 @@ +# Time: put: O(1) +# retrieve: O(n + dlogd), n is the size of the total logs +# , d is the size of the found logs +# Space: O(n) + +class LogSystem(object): + + def __init__(self): + self.__logs = [] + self.__granularity = {'Year': 4, 'Month': 7, 'Day': 10, \ + 'Hour': 13, 'Minute': 16, 'Second': 19} + + + def put(self, id, timestamp): + """ + :type id: int + :type timestamp: str + :rtype: void + """ + self.__logs.append((id, timestamp)) + + + def retrieve(self, s, e, gra): + """ + :type s: str + :type e: str + :type gra: str + :rtype: List[int] + """ + i = self.__granularity[gra] + begin = s[:i] + end = e[:i] + return sorted(id for id, timestamp in self.__logs \ + if begin <= timestamp[:i] <= end) + + +# Your LogSystem object will be instantiated and called as such: +# obj = LogSystem() +# obj.put(id,timestamp) +# param_2 = obj.retrieve(s,e,gra) diff --git a/Python/design-phone-directory.py b/Python/design-phone-directory.py new file mode 100644 index 000000000..d0c2af2a1 --- /dev/null +++ b/Python/design-phone-directory.py @@ -0,0 +1,61 @@ +# init: Time: O(n), Space: O(n) +# get: Time: O(1), Space: O(1) +# check: Time: O(1), Space: O(1) +# release: Time: O(1), Space: O(1) + +class PhoneDirectory(object): + + def __init__(self, maxNumbers): + """ + Initialize your data structure here + @param maxNumbers - The maximum numbers that can be stored in the phone directory. + :type maxNumbers: int + """ + self.__curr = 0 + self.__numbers = range(maxNumbers) + self.__used = [False] * maxNumbers + + + def get(self): + """ + Provide a number which is not assigned to anyone. + @return - Return an available number. Return -1 if none is available. + :rtype: int + """ + if self.__curr == len(self.__numbers): + return -1 + number = self.__numbers[self.__curr] + self.__curr += 1 + self.__used[number] = True + return number + + + def check(self, number): + """ + Check if a number is available or not. + :type number: int + :rtype: bool + """ + return 0 <= number < len(self.__numbers) and \ + not self.__used[number] + + + def release(self, number): + """ + Recycle or release a number. + :type number: int + :rtype: void + """ + if not 0 <= number < len(self.__numbers) or \ + not self.__used[number]: + return + self.__used[number] = False + self.__curr -= 1 + self.__numbers[self.__curr] = number + + +# Your PhoneDirectory object will be instantiated and called as such: +# obj = PhoneDirectory(maxNumbers) +# param_1 = obj.get() +# param_2 = obj.check(number) +# obj.release(number) diff --git a/Python/design-search-autocomplete-system.py b/Python/design-search-autocomplete-system.py new file mode 100644 index 000000000..f7a4d04b7 --- /dev/null +++ b/Python/design-search-autocomplete-system.py @@ -0,0 +1,75 @@ +# Time: O(p^2), p is the length of the prefix +# Space: O(p * t + s), t is the number of nodes of trie +# , s is the size of the sentences + +class TrieNode(object): + + def __init__(self): + self.__TOP_COUNT = 3 + self.infos = [] + self.leaves = {} + + + def insert(self, s, times): + cur = self + cur.add_info(s, times) + for c in s: + if c not in cur.leaves: + cur.leaves[c] = TrieNode() + cur = cur.leaves[c] + cur.add_info(s, times) + + + def add_info(self, s, times): + for p in self.infos: + if p[1] == s: + p[0] = -times + break + else: + self.infos.append([-times, s]) + self.infos.sort() + if len(self.infos) > self.__TOP_COUNT: + self.infos.pop() + + +class AutocompleteSystem(object): + + def __init__(self, sentences, times): + """ + :type sentences: List[str] + :type times: List[int] + """ + self.__trie = TrieNode() + self.__cur_node = self.__trie + self.__search = [] + self.__sentence_to_count = collections.defaultdict(int) + for sentence, count in zip(sentences, times): + self.__sentence_to_count[sentence] = count + self.__trie.insert(sentence, count) + + + def input(self, c): + """ + :type c: str + :rtype: List[str] + """ + result = [] + if c == '#': + self.__sentence_to_count["".join(self.__search)] += 1 + self.__trie.insert("".join(self.__search), self.__sentence_to_count["".join(self.__search)]) + self.__cur_node = self.__trie + self.__search = [] + else: + self.__search.append(c) + if self.__cur_node: + if c not in self.__cur_node.leaves: + self.__cur_node = None + return [] + self.__cur_node = self.__cur_node.leaves[c] + result = [p[1] for p in self.__cur_node.infos] + return result + + +# Your AutocompleteSystem object will be instantiated and called as such: +# obj = AutocompleteSystem(sentences, times) +# param_1 = obj.input(c) diff --git a/Python/design-snake-game.py b/Python/design-snake-game.py new file mode 100644 index 000000000..134dbcae3 --- /dev/null +++ b/Python/design-snake-game.py @@ -0,0 +1,63 @@ +# Time: O(1) per move +# Space: O(s), s is the current length of the snake. + +from collections import deque + +class SnakeGame(object): + + def __init__(self, width,height,food): + """ + Initialize your data structure here. + @param width - screen width + @param height - screen height + @param food - A list of food positions + E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. + :type width: int + :type height: int + :type food: List[List[int]] + """ + self.__width = width + self.__height = height + self.__score = 0 + self.__food = deque(food) + self.__snake = deque([(0, 0)]) + self.__direction = {"U":(-1, 0), "L":(0, -1), "R":(0, 1), "D":(1, 0)}; + self.__lookup = collections.defaultdict(int) + self.__lookup[(0, 0)] += 1 + + def move(self, direction): + """ + Moves the snake. + @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + @return The game's score after the move. Return -1 if game over. + Game over when snake crosses the screen boundary or bites its body. + :type direction: str + :rtype: int + """ + def valid(x, y): + return 0 <= x < self.__height and \ + 0 <= y < self.__width and \ + (x, y) not in self.__lookup + d = self.__direction[direction] + x, y = self.__snake[-1][0] + d[0], self.__snake[-1][1] + d[1] + + tail = self.__snake[-1] + self.__lookup[self.__snake[0]] -= 1 + if self.__lookup[self.__snake[0]] == 0: + self.__lookup.pop(self.__snake[0]) + self.__snake.popleft() + if not valid(x, y): + return -1 + elif self.__food and (self.__food[0][0], self.__food[0][1]) == (x, y): + self.__score += 1 + self.__food.popleft() + self.__snake.appendleft(tail) + self.__lookup[tail] += 1 + self.__snake += (x, y), + self.__lookup[(x, y)] += 1 + return self.__score + + +# Your SnakeGame object will be instantiated and called as such: +# obj = SnakeGame(width, height, food) +# param_1 = obj.move(direction) diff --git a/Python/design-tic-tac-toe.py b/Python/design-tic-tac-toe.py new file mode 100644 index 000000000..6d40a6f2d --- /dev/null +++ b/Python/design-tic-tac-toe.py @@ -0,0 +1,50 @@ +# Time: O(1), per move. +# Space: O(n^2) + +class TicTacToe(object): + + def __init__(self, n): + """ + Initialize your data structure here. + :type n: int + """ + self.__rows = [[0, 0] for _ in xrange(n)] + self.__cols = [[0, 0] for _ in xrange(n)] + self.__diagonal = [0, 0] + self.__anti_diagonal = [0, 0] + + + def move(self, row, col, player): + """ + Player {player} makes a move at ({row}, {col}). + @param row The row of the board. + @param col The column of the board. + @param player The player, can be either 1 or 2. + @return The current winning condition, can be either: + 0: No one wins. + 1: Player 1 wins. + 2: Player 2 wins. + :type row: int + :type col: int + :type player: int + :rtype: int + """ + i = player - 1 + self.__rows[row][i] += 1 + self.__cols[col][i] += 1 + if row == col: + self.__diagonal[i] += 1 + if col == len(self.__rows) - row - 1: + self.__anti_diagonal[i] += 1 + if any([self.__rows[row][i] == len(self.__rows), \ + self.__cols[col][i] == len(self.__cols), \ + self.__diagonal[i] == len(self.__rows), \ + self.__anti_diagonal[i] == len(self.__cols)]): + return player + + return 0 + + +# Your TicTacToe object will be instantiated and called as such: +# obj = TicTacToe(n) +# param_1 = obj.move(row,col,player) diff --git a/Python/design-twitter.py b/Python/design-twitter.py new file mode 100644 index 000000000..8fe5ee95a --- /dev/null +++ b/Python/design-twitter.py @@ -0,0 +1,111 @@ +# Time: O(klogu), k is most recently number of tweets, +# u is the number of the user's following. +# Space: O(t + f), t is the total number of tweets, +# f is the total number of followings. + +# Design a simplified version of Twitter where users can post tweets, +# follow/unfollow another user and is able to see the 10 most recent +# tweets in the user's news feed. Your design should support the following methods: +# +# postTweet(userId, tweetId): Compose a new tweet. +# getNewsFeed(userId): Retrieve the 10 most recent tweet ids in the user's +# news feed. Each item in the news feed must be posted by users who the user followed +# or by the user herself. Tweets must be ordered from most recent to least recent. +# follow(followerId, followeeId): Follower follows a followee. +# unfollow(followerId, followeeId): Follower unfollows a followee. +# Example: +# +# Twitter twitter = new Twitter(); +# +# // User 1 posts a new tweet (id = 5). +# twitter.postTweet(1, 5); +# +# // User 1's news feed should return a list with 1 tweet id -> [5]. +# twitter.getNewsFeed(1); +# +# // User 1 follows user 2. +# twitter.follow(1, 2); +# +# // User 2 posts a new tweet (id = 6). +# twitter.postTweet(2, 6); +# +# // User 1's news feed should return a list with 2 tweet ids -> [6, 5]. +# // Tweet id 6 should precede tweet id 5 because it is posted after tweet id 5. +# twitter.getNewsFeed(1); +# +# // User 1 unfollows user 2. +# twitter.unfollow(1, 2); +# +# // User 1's news feed should return a list with 1 tweet id -> [5], +# // since user 1 is no longer following user 2. +# twitter.getNewsFeed(1); + +class Twitter(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.__number_of_most_recent_tweets = 10 + self.__followings = collections.defaultdict(set) + self.__messages = collections.defaultdict(list) + self.__time = 0 + + def postTweet(self, userId, tweetId): + """ + Compose a new tweet. + :type userId: int + :type tweetId: int + :rtype: void + """ + self.__time += 1 + self.__messages[userId].append((self.__time, tweetId)) + + def getNewsFeed(self, userId): + """ + Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. + :type userId: int + :rtype: List[int] + """ + max_heap = [] + if self.__messages[userId]: + heapq.heappush(max_heap, (-self.__messages[userId][-1][0], userId, 0)) + for uid in self.__followings[userId]: + if self.__messages[uid]: + heapq.heappush(max_heap, (-self.__messages[uid][-1][0], uid, 0)) + + result = [] + while max_heap and len(result) < self.__number_of_most_recent_tweets: + t, uid, curr = heapq.heappop(max_heap) + nxt = curr + 1; + if nxt != len(self.__messages[uid]): + heapq.heappush(max_heap, (-self.__messages[uid][-(nxt+1)][0], uid, nxt)) + result.append(self.__messages[uid][-(curr+1)][1]); + return result + + def follow(self, followerId, followeeId): + """ + Follower follows a followee. If the operation is invalid, it should be a no-op. + :type followerId: int + :type followeeId: int + :rtype: void + """ + if followerId != followeeId: + self.__followings[followerId].add(followeeId) + + def unfollow(self, followerId, followeeId): + """ + Follower unfollows a followee. If the operation is invalid, it should be a no-op. + :type followerId: int + :type followeeId: int + :rtype: void + """ + self.__followings[followerId].discard(followeeId) + + +# Your Twitter object will be instantiated and called as such: +# obj = Twitter() +# obj.postTweet(userId,tweetId) +# param_2 = obj.getNewsFeed(userId) +# obj.follow(followerId,followeeId) +# obj.unfollow(followerId,followeeId) diff --git a/Python/detect-capital.py b/Python/detect-capital.py new file mode 100644 index 000000000..c0949a7e5 --- /dev/null +++ b/Python/detect-capital.py @@ -0,0 +1,24 @@ +# Time: O(l) +# Space: O(1) + +# We define the usage of capitals in a word to be right when one of the following cases holds: +# +# All letters in this word are capitals, like "USA". +# All letters in this word are not capitals, like "leetcode". +# Only the first letter in this word is capital if it has more than one letter, like "Google". +# Otherwise, we define that this word doesn't use capitals in a right way. +# Example 1: +# Input: "USA" +# Output: True +# Example 2: +# Input: "FlaG" +# Output: False +# Note: The input will be a non-empty word consisting of uppercase and lowercase latin letters. + +class Solution(object): + def detectCapitalUse(self, word): + """ + :type word: str + :rtype: bool + """ + return word.isupper() or word.islower() or word.istitle() diff --git a/Python/diagonal-traverse.py b/Python/diagonal-traverse.py new file mode 100644 index 000000000..8410476a4 --- /dev/null +++ b/Python/diagonal-traverse.py @@ -0,0 +1,55 @@ +# Time: O(m * n) +# Space: O(1) + +# Given a matrix of M x N elements (M rows, N columns), +# return all elements of the matrix in diagonal order as shown in the below image. +# +# Example: +# Input: +# [ +# [ 1, 2, 3 ], +# [ 4, 5, 6 ], +# [ 7, 8, 9 ] +# ] +# Output: [1,2,4,7,5,3,6,8,9] +# Explanation: +# +# Note: +# The total number of elements of the given matrix will not exceed 10,000. +# Show Company Tags + +class Solution(object): + def findDiagonalOrder(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: List[int] + """ + if not matrix or not matrix[0]: + return [] + + result = [] + row, col, d = 0, 0, 0 + dirs = [(-1, 1), (1, -1)] + + for i in xrange(len(matrix) * len(matrix[0])): + result.append(matrix[row][col]) + row += dirs[d][0] + col += dirs[d][1] + + if row >= len(matrix): + row = len(matrix) - 1 + col += 2 + d = 1 - d + elif col >= len(matrix[0]): + col = len(matrix[0]) - 1 + row += 2 + d = 1 - d + elif row < 0: + row = 0 + d = 1 - d + elif col < 0: + col = 0 + d = 1 - d + + return result + diff --git a/Python/diameter-of-binary-tree.py b/Python/diameter-of-binary-tree.py new file mode 100644 index 000000000..736e93b3b --- /dev/null +++ b/Python/diameter-of-binary-tree.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space: O(h) + +# Given a binary tree, you need to compute the length of the diameter of the tree. +# The diameter of a binary tree is the length of the longest path between +# any two nodes in a tree. This path may or may not pass through the root. +# +# Example: +# Given a binary tree +# 1 +# / \ +# 2 3 +# / \ +# 4 5 +# Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3]. +# +# Note: The length of path between two nodes is represented by the number of edges between them. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def diameterOfBinaryTree(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def depth(root, diameter): + if not root: return 0, diameter + left, diameter = depth(root.left, diameter) + right, diameter = depth(root.right, diameter) + return 1 + max(left, right), max(diameter, 1 + left + right) + + return depth(root, 1)[1] - 1 diff --git a/Python/different-ways-to-add-parentheses.py b/Python/different-ways-to-add-parentheses.py new file mode 100644 index 000000000..b83604fbf --- /dev/null +++ b/Python/different-ways-to-add-parentheses.py @@ -0,0 +1,75 @@ +# Time: O(n * 4^n / n^(3/2)) ~= n * Catalan numbers = n * (C(2n, n) - C(2n, n - 1)), +# due to the size of the results is Catalan numbers, +# and every way of evaluation is the length of the string, +# so the time complexity is at most n * Catalan numbers. +# Space: O(n * 4^n / n^(3/2)), the cache size of lookup is at most n * Catalan numbers. +# +# Given a string of numbers and operators, return all possible +# results from computing all the different possible ways to +# group numbers and operators. The valid operators are +, - and *. +# +# +# Example 1 +# Input: "2-1-1". +# +# ((2-1)-1) = 0 +# (2-(1-1)) = 2 +# Output: [0, 2] +# +# +# Example 2 +# Input: "2*3-4*5" +# +# (2*(3-(4*5))) = -34 +# ((2*3)-(4*5)) = -14 +# ((2*(3-4))*5) = -10 +# (2*((3-4)*5)) = -10 +# (((2*3)-4)*5) = 10 +# Output: [-34, -14, -10, -10, 10] +# + +class Solution: + # @param {string} input + # @return {integer[]} + def diffWaysToCompute(self, input): + tokens = re.split('(\D)', input) + nums = map(int, tokens[::2]) + ops = map({'+': operator.add, '-': operator.sub, '*': operator.mul}.get, tokens[1::2]) + lookup = [[None for _ in xrange(len(nums))] for _ in xrange(len(nums))] + + def diffWaysToComputeRecu(left, right): + if left == right: + return [nums[left]] + if lookup[left][right]: + return lookup[left][right] + lookup[left][right] = [ops[i](x, y) + for i in xrange(left, right) + for x in diffWaysToComputeRecu(left, i) + for y in diffWaysToComputeRecu(i + 1, right)] + return lookup[left][right] + + return diffWaysToComputeRecu(0, len(nums) - 1) + +class Solution2: + # @param {string} input + # @return {integer[]} + def diffWaysToCompute(self, input): + lookup = [[None for _ in xrange(len(input) + 1)] for _ in xrange(len(input) + 1)] + ops = {'+': operator.add, '-': operator.sub, '*': operator.mul} + + def diffWaysToComputeRecu(left, right): + if lookup[left][right]: + return lookup[left][right] + result = [] + for i in xrange(left, right): + if input[i] in ops: + for x in diffWaysToComputeRecu(left, i): + for y in diffWaysToComputeRecu(i + 1, right): + result.append(ops[input[i]](x, y)) + + if not result: + result = [int(input[left:right])] + lookup[left][right] = result + return lookup[left][right] + + return diffWaysToComputeRecu(0, len(input)) diff --git a/Python/distribute-candies.py b/Python/distribute-candies.py new file mode 100644 index 000000000..922454a98 --- /dev/null +++ b/Python/distribute-candies.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(n) + +# Given an integer array with even length, where different numbers +# in this array represent different kinds of candies. +# Each number means one candy of the corresponding kind. +# You need to distribute these candies equally in number to brother and sister. +# Return the maximum number of kinds of candies the sister could gain. +# +# Example 1: +# Input: candies = [1,1,2,2,3,3] +# Output: 3 +# Explanation: +# There are three different kinds of candies (1, 2 and 3), and two candies for each kind. +# Optimal distribution: The sister has candies [1,2,3] and the brother has candies [1,2,3], too. +# The sister has three different kinds of candies. +# +# Example 2: +# Input: candies = [1,1,2,3] +# Output: 2 +# Explanation: For example, the sister has candies [2,3] and the brother has candies [1,1]. +# The sister has two different kinds of candies, the brother has only one kind of candies. +# +# Note: +# The length of the given array is in range [2, 10,000], and will be even. +# The number in given array is in range [-100,000, 100,000]. + +class Solution(object): + def distributeCandies(self, candies): + """ + :type candies: List[int] + :rtype: int + """ + lookup = set() + for candy in candies: + lookup.add(candy) + return min(len(lookup), len(candies)/2) diff --git a/Python/divide-two-integers.py b/Python/divide-two-integers.py index ff8bd757e..b024170f6 100644 --- a/Python/divide-two-integers.py +++ b/Python/divide-two-integers.py @@ -1,12 +1,16 @@ -# Time: O(logn) +# Time: O(logn) = O(1) # Space: O(1) # # Divide two integers without using multiplication, division and mod operator. -# + class Solution: - # @return an integer def divide(self, dividend, divisor): + """ + :type dividend: int + :type divisor: int + :rtype: int + """ result, dvd, dvs = 0, abs(dividend), abs(divisor) while dvd >= dvs: inc = dvs @@ -20,9 +24,29 @@ def divide(self, dividend, divisor): return -result else: return result + + def divide2(self, dividend, divisor): + """ + :type dividend: int + :type divisor: int + :rtype: int + """ + positive = (dividend < 0) is (divisor < 0) + dividend, divisor = abs(dividend), abs(divisor) + res = 0 + while dividend >= divisor: + temp, i = divisor, 1 + while dividend >= temp: + dividend -= temp + res += i + i <<= 1 + temp <<= 1 + if not positive: + res = -res + return min(max(-2147483648, res), 2147483647) if __name__ == "__main__": print Solution().divide(123, 12) print Solution().divide(123, -12) print Solution().divide(-123, 12) - print Solution().divide(-123, -12) \ No newline at end of file + print Solution().divide(-123, -12) diff --git a/Python/dota2-senate.py b/Python/dota2-senate.py new file mode 100644 index 000000000..bbed007e5 --- /dev/null +++ b/Python/dota2-senate.py @@ -0,0 +1,65 @@ +# Time: O(n) +# Space: O(n) + +# In the world of Dota2, there are two parties: the Radiant and the Dire. +# +# The Dota2 senate consists of senators coming from two parties. +# Now the senate wants to make a decision about a change in the Dota2 game. +# The voting for this change is a round-based procedure. +# In each round, each senator can exercise one of the two rights: +# +# Ban one senator's right: +# A senator can make another senator lose all his rights in this and all the following rounds. +# Announce the victory: +# If this senator found the senators who still have rights to vote are all from the same party, +# he can announce the victory and make the decision about the change in the game. +# +# Given a string representing each senator's party belonging. +# The character 'R' and 'D' represent the Radiant party and the Dire party respectively. +# Then if there are n senators, the size of the given string will be n. +# +# The round-based procedure starts from the first senator to the last senator in the given order. +# This procedure will last until the end of voting. All the senators +# who have lost their rights will be skipped during the procedure. +# +# Suppose every senator is smart enough and will play the best strategy for his own party, +# you need to predict which party will finally announce the victory and make the change in the Dota2 game. +# The output should be Radiant or Dire. +# +# Example 1: +# Input: "RD" +# Output: "Radiant" +# Explanation: The first senator comes from Radiant and he can just ban the next senator's right in the round 1. +# And the second senator can't exercise any rights any more since his right has been banned. +# And in the round 2, the first senator can just announce the victory since he is the only guy in the senate who can vote. +# Example 2: +# Input: "RDD" +# Output: "Dire" +# Explanation: +# The first senator comes from Radiant and he can just ban the next senator's right in the round 1. +# And the second senator can't exercise any rights anymore since his right has been banned. +# And the third senator comes from Dire and he can ban the first senator's right in the round 1. +# And in the round 2, the third senator can just announce the victory since he is the only guy in the senate who can vote. +# Note: +# The length of the given string will in the range [1, 10,000]. + +class Solution(object): + def predictPartyVictory(self, senate): + """ + :type senate: str + :rtype: str + """ + n = len(senate) + radiant, dire = collections.deque(), collections.deque() + for i, c in enumerate(senate): + if c == 'R': + radiant.append(i) + else: + dire.append(i) + while radiant and dire: + r_idx, d_idx = radiant.popleft(), dire.popleft() + if r_idx < d_idx: + radiant.append(r_idx+n) + else: + dire.append(d_idx+n) + return "Radiant" if len(radiant) > len(dire) else "Dire" diff --git a/Python/elimination-game.py b/Python/elimination-game.py new file mode 100644 index 000000000..0dd69f485 --- /dev/null +++ b/Python/elimination-game.py @@ -0,0 +1,39 @@ +# Time: O(logn) +# Space: O(1) + +# There is a list of sorted integers from 1 to n. Starting from left to right, +# remove the first number and every other number afterward until you reach the end of the list. +# +# Repeat the previous step again, but this time from right to left, +# remove the right most number and every other number from the remaining numbers. +# +# We keep repeating the steps again, alternating left to right and right to left, +# until a single number remains. +# +# Find the last number that remains starting with a list of length n. +# +# Example: +# +# Input: +# n = 9, +# 1 2 3 4 5 6 7 8 9 +# 2 4 6 8 +# 2 6 +# 6 +# +# Output: +# 6 + +class Solution(object): + def lastRemaining(self, n): + """ + :type n: int + :rtype: int + """ + start, step, direction = 1, 2, 1 + while n > 1: + start += direction * (step * (n/2) - step/2) + n /= 2 + step *= 2 + direction *= -1 + return start diff --git a/Python/employee-importance.py b/Python/employee-importance.py new file mode 100644 index 000000000..92bab697b --- /dev/null +++ b/Python/employee-importance.py @@ -0,0 +1,72 @@ +# Time: O(n) +# Space: O(h) + +# You are given a data structure of employee information, +# which includes the employee's unique id, his importance value and his direct subordinates' id. +# +# For example, employee 1 is the leader of employee 2, and employee 2 is the leader of employee 3. +# They have importance value 15, 10 and 5, respectively. +# Then employee 1 has a data structure like [1, 15, [2]], and employee 2 has [2, 10, [3]], +# and employee 3 has [3, 5, []]. Note that although employee 3 is also a subordinate of employee 1, +# the relationship is not direct. +# +# Now given the employee information of a company, +# and an employee id, you need to return the total importance value of this employee and all his subordinates. +# +# Example 1: +# Input: [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1 +# Output: 11 +# +# Explanation: +# Employee 1 has importance value 5, and he has two direct subordinates: +# employee 2 and employee 3. They both have importance value 3. +# So the total importance value of employee 1 is 5 + 3 + 3 = 11. +# +# Note: +# One employee has at most one direct leader and may have several subordinates. +# The maximum number of employees won't exceed 2000. + +""" +# Employee info +class Employee(object): + def __init__(self, id, importance, subordinates): + # It's the unique id of each node. + # unique id of this employee + self.id = id + # the importance value of this employee + self.importance = importance + # the id of direct subordinates + self.subordinates = subordinates +""" +class Solution(object): + def getImportance(self, employees, id): + """ + :type employees: Employee + :type id: int + :rtype: int + """ + if employees[id-1] is None: + return 0 + result = employees[id-1].importance + for id in employees[id-1].subordinates: + result += self.getImportance(employees, id) + return result + + +# Time: O(n) +# Space: O(w), w is the max number of nodes in the levels of the tree +class Solution2(object): + def getImportance(self, employees, id): + """ + :type employees: Employee + :type id: int + :rtype: int + """ + result, q = 0, collections.deque([id]) + while q: + curr = q.popleft() + employee = employees[curr-1] + result += employee.importance; + for id in employee.subordinates: + q.append(id) + return result diff --git a/Python/encode-and-decode-strings.py b/Python/encode-and-decode-strings.py new file mode 100644 index 000000000..39445a51a --- /dev/null +++ b/Python/encode-and-decode-strings.py @@ -0,0 +1,30 @@ +# Time: O(n) +# Space: O(1) + +class Codec: + + def encode(self, strs): + """Encodes a list of strings to a single string. + + :type strs: List[str] + :rtype: str + """ + encoded_str = "" + for s in strs: + encoded_str += "%0*x" % (8, len(s)) + s + return encoded_str + + + def decode(self, s): + """Decodes a single string to a list of strings. + + :type s: str + :rtype: List[str] + """ + i = 0 + strs = [] + while i < len(s): + l = int(s[i:i+8], 16) + strs.append(s[i+8:i+8+l]) + i += 8+l + return strs diff --git a/Python/encode-and-decode-tinyurl.py b/Python/encode-and-decode-tinyurl.py new file mode 100644 index 000000000..b112e211f --- /dev/null +++ b/Python/encode-and-decode-tinyurl.py @@ -0,0 +1,51 @@ +# Time: O(1) +# Space: O(n) + +# TinyURL is a URL shortening service where you enter a URL +# such as https://leetcode.com/problems/design-tinyurl and +# it returns a short URL such as http://tinyurl.com/4e9iAk. +# +# Design the encode and decode methods for the TinyURL service. +# There is no restriction on how your encode/decode algorithm should work. +# You just need to ensure that a URL can be encoded to a tiny URL +# and the tiny URL can be decoded to the original URL. + +class Codec: + def __init__(self): + self.__random_length = 6 + self.__tiny_url = "http://tinyurl.com/" + self.__alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + self.__lookup = {} + + + def encode(self, longUrl): + """Encodes a URL to a shortened URL. + + :type longUrl: str + :rtype: str + """ + def getRand(): + rand = [] + for _ in xrange(self.__random_length): + rand += self.__alphabet[random.randint(0, len(self.__alphabet)-1)] + return "".join(rand) + + key = getRand() + while key in self.__lookup: + key = getRand() + self.__lookup[key] = longUrl + return self.__tiny_url + key + + + def decode(self, shortUrl): + """Decodes a shortened URL to its original URL. + + :type shortUrl: str + :rtype: str + """ + return self.__lookup[shortUrl[len(self.__tiny_url):]] + + +# Your Codec object will be instantiated and called as such: +# codec = Codec() +# codec.decode(codec.encode(url)) diff --git a/Python/encode-string-with-shortest-length.py b/Python/encode-string-with-shortest-length.py new file mode 100644 index 000000000..6988e6d4c --- /dev/null +++ b/Python/encode-string-with-shortest-length.py @@ -0,0 +1,28 @@ +# Time: O(n^3) on average +# Space: O(n^2) + +class Solution(object): + def encode(self, s): + """ + :type s: str + :rtype: str + """ + def encode_substr(dp, s, i, j): + temp = s[i:j+1] + pos = (temp + temp).find(temp, 1) # O(n) on average + if pos >= len(temp): + return temp + return str(len(temp)/pos) + '[' + dp[i][i + pos - 1] + ']' + + dp = [["" for _ in xrange(len(s))] for _ in xrange(len(s))] + for length in xrange(1, len(s)+1): + for i in xrange(len(s)+1-length): + j = i+length-1 + dp[i][j] = s[i:i+length] + for k in xrange(i, j): + if len(dp[i][k]) + len(dp[k+1][j]) < len(dp[i][j]): + dp[i][j] = dp[i][k] + dp[k+1][j] + encoded_string = encode_substr(dp, s, i, j) + if len(encoded_string) < len(dp[i][j]): + dp[i][j] = encoded_string + return dp[0][len(s) - 1] diff --git a/Python/equal-tree-partition.py b/Python/equal-tree-partition.py new file mode 100644 index 000000000..7f77d97a4 --- /dev/null +++ b/Python/equal-tree-partition.py @@ -0,0 +1,30 @@ +# Time: O(n) +# Space: O(n) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def checkEqualTree(self, root): + """ + :type root: TreeNode + :rtype: bool + """ + def getSumHelper(node, lookup): + if not node: + return 0 + total = node.val + \ + getSumHelper(node.left, lookup) + \ + getSumHelper(node.right, lookup) + lookup[total] += 1 + return total + + lookup = collections.defaultdict(int) + total = getSumHelper(root, lookup) + if total == 0: + return lookup[total] > 1 + return total%2 == 0 and (total/2) in lookup diff --git a/Python/erect-the-fence.py b/Python/erect-the-fence.py new file mode 100644 index 000000000..c1ffe423d --- /dev/null +++ b/Python/erect-the-fence.py @@ -0,0 +1,55 @@ +# Time: O(nlogn) +# Space: O(n) + +# There are some trees, where each tree is represented by +# (x,y) coordinate in a two-dimensional garden. +# Your job is to fence the entire garden using the minimum length of rope +# as it is expensive. The garden is well fenced only if all the trees are enclosed. +# Your task is to help find the coordinates of trees which are exactly located on the fence perimeter. +# +# Example 1: +# Input: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]] +# Output: [[1,1],[2,0],[4,2],[3,3],[2,4]] +# +# Example 2: +# Input: [[1,2],[2,2],[4,2]] +# Output: [[1,2],[2,2],[4,2]] +# +# Even you only have trees in a line, you need to use rope to enclose them. +# Note: +# +# All trees should be enclosed together. +# You cannot cut the rope to enclose trees that will separate them in more than one group. +# All input integers will range from 0 to 100. +# The garden has at least one tree. +# All coordinates are distinct. +# Input points have NO order. No order required for output. + +# Definition for a point. +# class Point(object): +# def __init__(self, a=0, b=0): +# self.x = a +# self.y = b + +# Monotone Chain Algorithm +class Solution(object): + def outerTrees(self, points): + """ + :type points: List[Point] + :rtype: List[Point] + """ + def orientation(p, q, r): + return (q.y - p.y) * (r.x - q.x) - \ + (q.x - p.x) * (r.y - q.y) + + hull = [] + points.sort(key=lambda p: (p.x, p.y)) + + for i in itertools.chain(xrange(len(points)), \ + reversed(xrange(len(points)))): + while len(hull) >= 2 and \ + orientation(hull[-2], hull[-1], points[i]) > 0: + hull.pop() + hull.append(points[i]) + + return list(set(hull)) diff --git a/Python/evaluate-division.py b/Python/evaluate-division.py new file mode 100644 index 000000000..bf1399601 --- /dev/null +++ b/Python/evaluate-division.py @@ -0,0 +1,56 @@ +# Time: O(e + q * |V|!), |V| is the number of variables +# Space: O(e) + +# Equations are given in the format A / B = k, +# where A and B are variables represented as strings, +# and k is a real number (floating point number). +# Given some queries, return the answers. +# If the answer does not exist, return -1.0. +# +# Example: +# Given a / b = 2.0, b / c = 3.0. +# queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? . +# return [6.0, 0.5, -1.0, 1.0, -1.0 ]. +# +# The input is: +# vector> euqations, vector& values, vector> query . +# +# where equations.size() == values.size(),the values are positive. +# this represents the equations.return vector. . +# The example above: equations = [ ["a", "b"], ["b", "c"] ]. +# values = [2.0, 3.0]. queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]. +# +# The input is always valid. You may assume that +# evaluating the queries will result in no division by zero and there is no contradiction. + +class Solution(object): + def calcEquation(self, equations, values, query): + """ + :type equations: List[List[str]] + :type values: List[float] + :type query: List[List[str]] + :rtype: List[float] + """ + def check(up, down, lookup, visited): + if up in lookup and down in lookup[up]: + return (True, lookup[up][down]) + for k, v in lookup[up].iteritems(): + if k not in visited: + visited.add(k) + tmp = check(k, down, lookup, visited) + if tmp[0]: + return (True, v * tmp[1]) + return (False, 0) + + lookup = collections.defaultdict(dict) + for i, e in enumerate(equations): + lookup[e[0]][e[1]] = values[i] + if values[i]: + lookup[e[1]][e[0]] = 1.0 / values[i] + + result = [] + for q in query: + visited = set() + tmp = check(q[0], q[1], lookup, visited) + result.append(tmp[1] if tmp[0] else -1) + return result diff --git a/Python/excel-sheet-column-number.py b/Python/excel-sheet-column-number.py index 7ea985aa3..667233c59 100644 --- a/Python/excel-sheet-column-number.py +++ b/Python/excel-sheet-column-number.py @@ -1,6 +1,6 @@ # Time: O(n) # Space: O(1) -# + # Related to question Excel Sheet Column Title # # Given a column title as appear in an Excel sheet, return its corresponding column number. @@ -14,17 +14,19 @@ # Z -> 26 # AA -> 27 # AB -> 28 -# -class Solution: - # @param s, a string - # @return an integer +class Solution(object): def titleToNumber(self, s): + """ + :type s: str + :rtype: int + """ result = 0 for i in xrange(len(s)): result *= 26 result += ord(s[i]) - ord('A') + 1 return result + if __name__ == "__main__": - print Solution().titleToNumber("AAAB") \ No newline at end of file + print Solution().titleToNumber("AAAB") diff --git a/Python/excel-sheet-column-title.py b/Python/excel-sheet-column-title.py index fe8cb669b..a2160e9d5 100644 --- a/Python/excel-sheet-column-title.py +++ b/Python/excel-sheet-column-title.py @@ -1,6 +1,6 @@ # Time: O(logn) # Space: O(1) -# + # Given a positive integer, return its corresponding column title as appear in an Excel sheet. # # For example: @@ -12,19 +12,22 @@ # 26 -> Z # 27 -> AA # 28 -> AB -# -class Solution: - # @return a string - def convertToTitle(self, num): - result, dvd = "", num +class Solution(object): + def convertToTitle(self, n): + """ + :type n: int + :rtype: str + """ + result, dvd = "", n while dvd: result += chr((dvd - 1) % 26 + ord('A')) dvd = (dvd - 1) / 26 return result[::-1] - + + if __name__ == "__main__": for i in xrange(1, 29): - print Solution().convertToTitle(i) \ No newline at end of file + print Solution().convertToTitle(i) diff --git a/Python/exclusive-time-of-functions.py b/Python/exclusive-time-of-functions.py new file mode 100644 index 000000000..02127e25c --- /dev/null +++ b/Python/exclusive-time-of-functions.py @@ -0,0 +1,62 @@ +# Time: O(n) +# Space: O(n) + +# Given the running logs of n functions that are executed +# in a nonpreemptive single threaded CPU, find the exclusive time of these functions. +# +# Each function has a unique id, start from 0 to n-1. +# A function may be called recursively or by another function. +# +# A log is a string has this format : function_id:start_or_end:timestamp. +# For example, "0:start:0" means function 0 starts from the very beginning of time 0. +# "0:end:0" means function 0 ends to the very end of time 0. +# +# Exclusive time of a function is defined as the time spent within this function, +# the time spent by calling other functions should not be considered as +# this function's exclusive time. +# You should return the exclusive time of each function sorted by their function id. +# +# Example 1: +# Input: +# n = 2 +# logs = +# ["0:start:0", +# "1:start:2", +# "1:end:5", +# "0:end:6"] +# Output:[3, 4] +# +# Explanation: +# Function 0 starts at time 0, then it executes 2 units of time and reaches the end of time 1. +# Now function 0 calls function 1, function 1 starts at time 2, executes 4 units of time and end at time 5. +# Function 0 is running again at time 6, and also end at the time 6, thus executes 1 unit of time. +# So function 0 totally execute 2 + 1 = 3 units of time, and function 1 totally execute 4 units of time. +# +# Note: +# Input logs will be sorted by timestamp, NOT log id. +# Your output should be sorted by function id, +# which means the 0th element of your output corresponds to the exclusive time of function 0. +# Two functions won't start or end at the same time. +# Functions could be called recursively, and will always end. +# 1 <= n <= 100 + +class Solution(object): + def exclusiveTime(self, n, logs): + """ + :type n: int + :type logs: List[str] + :rtype: List[int] + """ + result = [0] * n + stk, prev = [], 0 + for log in logs: + tokens = log.split(":") + if tokens[1] == "start": + if stk: + result[stk[-1]] += int(tokens[2]) - prev + stk.append(int(tokens[0])) + prev = int(tokens[2]) + else: + result[stk.pop()] += int(tokens[2]) - prev + 1 + prev = int(tokens[2]) + 1 + return result diff --git a/Python/expression-add-operators.py b/Python/expression-add-operators.py new file mode 100644 index 000000000..15d972d3f --- /dev/null +++ b/Python/expression-add-operators.py @@ -0,0 +1,67 @@ +# Time: O(4^n) +# Space: O(n) +# +# Given a string that contains only digits 0-9 +# and a target value, return all possibilities +# to add operators +, -, or * between the digits +# so they evaluate to the target value. +# +# Examples: +# "123", 6 -> ["1+2+3", "1*2*3"] +# "232", 8 -> ["2*3+2", "2+3*2"] +# "00", 0 -> ["0+0", "0-0", "0*0"] +# "3456237490", 9191 -> [] +# + +class Solution(object): + def addOperators(self, num, target): + """ + :type num: str + :type target: int + :rtype: List[str] + """ + result, expr = [], [] + val, i = 0, 0 + val_str = "" + while i < len(num): + val = val * 10 + ord(num[i]) - ord('0') + val_str += num[i] + # Avoid "00...". + if str(val) != val_str: + break + expr.append(val_str) + self.addOperatorsDFS(num, target, i + 1, 0, val, expr, result) + expr.pop() + i += 1 + return result + + def addOperatorsDFS(self, num, target, pos, operand1, operand2, expr, result): + if pos == len(num) and operand1 + operand2 == target: + result.append("".join(expr)) + else: + val, i = 0, pos + val_str = "" + while i < len(num): + val = val * 10 + ord(num[i]) - ord('0') + val_str += num[i] + # Avoid "00...". + if str(val) != val_str: + break + + # Case '+': + expr.append("+" + val_str) + self.addOperatorsDFS(num, target, i + 1, operand1 + operand2, val, expr, result) + expr.pop() + + # Case '-': + expr.append("-" + val_str) + self.addOperatorsDFS(num, target, i + 1, operand1 + operand2, -val, expr, result) + expr.pop() + + # Case '*': + expr.append("*" + val_str) + self.addOperatorsDFS(num, target, i + 1, operand1, operand2 * val, expr, result) + expr.pop() + + i += 1 + diff --git a/Python/factor-combinations.py b/Python/factor-combinations.py new file mode 100644 index 000000000..9e2c1a687 --- /dev/null +++ b/Python/factor-combinations.py @@ -0,0 +1,23 @@ +# Time: O(nlogn) +# Space: O(logn) + +class Solution: + # @param {integer} n + # @return {integer[][]} + def getFactors(self, n): + result = [] + factors = [] + self.getResult(n, result, factors) + return result + + def getResult(self, n, result, factors): + i = 2 if not factors else factors[-1] + while i <= n / i: + if n % i == 0: + factors.append(i); + factors.append(n / i); + result.append(list(factors)); + factors.pop(); + self.getResult(n / i, result, factors); + factors.pop() + i += 1 diff --git a/Python/factorial-trailing-zeroes.py b/Python/factorial-trailing-zeroes.py index d649a86ff..106b59beb 100644 --- a/Python/factorial-trailing-zeroes.py +++ b/Python/factorial-trailing-zeroes.py @@ -1,4 +1,4 @@ -# Time: O(logn) +# Time: O(logn) = O(1) # Space: O(1) # # Given an integer n, return the number of trailing zeroes in n!. @@ -16,4 +16,4 @@ def trailingZeroes(self, n): return result if __name__ == "__main__": - print Solution().trailingZeroes(100) \ No newline at end of file + print Solution().trailingZeroes(100) diff --git a/Python/falling-squares.py b/Python/falling-squares.py new file mode 100644 index 000000000..13bb1c82b --- /dev/null +++ b/Python/falling-squares.py @@ -0,0 +1,224 @@ +# Time: O(nlogn) +# Space: O(n) + +# On an infinite number line (x-axis), we drop given squares in the order they are given. +# +# The i-th square dropped (positions[i] = (left, side_length)) is a square +# with the left-most point being positions[i][0] and sidelength positions[i][1]. +# +# The square is dropped with the bottom edge parallel to the number line, +# and from a higher height than all currently landed squares. +# We wait for each square to stick before dropping the next. +# +# The squares are infinitely sticky on their bottom edge, and will remain fixed +# to any positive length surface they touch (either the number line or another square). +# Squares dropped adjacent to each other will not stick together prematurely. +# +# Return a list ans of heights. Each height ans[i] represents the current highest height +# of any square we have dropped, after dropping squares represented by positions[0], positions[1], ..., positions[i]. +# +# Example 1: +# Input: [[1, 2], [2, 3], [6, 1]] +# Output: [2, 5, 5] +# Explanation: +# +# After the first drop of +# positions[0] = [1, 2]: +# _aa +# _aa +# ------- +# The maximum height of any square is 2. +# +# After the second drop of +# positions[1] = [2, 3]: +# __aaa +# __aaa +# __aaa +# _aa__ +# _aa__ +# -------------- +# The maximum height of any square is 5. +# The larger square stays on top of the smaller square despite where its center +# of gravity is, because squares are infinitely sticky on their bottom edge. +# +# After the third drop of +# positions[1] = [6, 1]: +# __aaa +# __aaa +# __aaa +# _aa +# _aa___a +# -------------- +# The maximum height of any square is still 5. +# +# Thus, we return an answer of +# [2, 5, 5] +# . +# +# Example 2: +# Input: [[100, 100], [200, 100]] +# Output: [100, 100] +# Explanation: Adjacent squares don't get stuck prematurely - only their bottom edge can stick to surfaces. +# Note: +# +# 1 <= positions.length <= 1000. +# 1 <= positions[0] <= 10^8. +# 1 <= positions[1] <= 10^6. + +class SegmentTree(object): + def __init__(self, N, update_fn, query_fn): + self.N = N + self.H = 1 + while (1 << self.H) < N: + self.H += 1 + + self.update_fn = update_fn + self.query_fn = query_fn + self.tree = [0] * (2 * N) + self.lazy = [0] * N + + def __apply(self, x, val): + self.tree[x] = self.update_fn(self.tree[x], val) + if x < self.N: + self.lazy[x] = self.update_fn(self.lazy[x], val) + + def __pull(self, x): + while x > 1: + x /= 2 + self.tree[x] = self.query_fn(self.tree[x*2], self.tree[x*2 + 1]) + self.tree[x] = self.update_fn(self.tree[x], self.lazy[x]) + + def __push(self, x): + for h in xrange(self.H, 0, -1): + y = x >> h + if self.lazy[y]: + self.__apply(y*2, self.lazy[y]) + self.__apply(y*2 + 1, self.lazy[y]) + self.lazy[y] = 0 + + def update(self, L, R, h): + L += self.N + R += self.N + L0, R0 = L, R + while L <= R: + if L & 1: + self.__apply(L, h) + L += 1 + if R & 1 == 0: + self.__apply(R, h) + R -= 1 + L /= 2; R /= 2 + self.__pull(L0) + self.__pull(R0) + + def query(self, L, R): + L += self.N + R += self.N + self.__push(L); self.__push(R) + result = 0 + while L <= R: + if L & 1: + result = self.query_fn(result, self.tree[L]) + L += 1 + if R & 1 == 0: + result = self.query_fn(result, self.tree[R]) + R -= 1 + L /= 2; R /= 2 + return result + + +# Segment Tree solution. +class Solution(object): + def fallingSquares(self, positions): + index = set() + for left, size in positions: + index.add(left); + index.add(left+size-1) + index = sorted(list(index)) + tree = SegmentTree(len(index), max, max) + max_height = 0 + result = [] + for left, size in positions: + L, R = bisect.bisect_left(index, left), bisect.bisect_left(index, left+size-1) + h = tree.query(L, R) + size + tree.update(L, R, h) + max_height = max(max_height, h) + result.append(max_height) + return result + + +# Time: O(n * sqrt(n)) +# Space: O(n) +class Solution2(object): + def fallingSquares(self, positions): + def query(heights, left, right, B, blocks, blocks_read): + result = 0 + while left % B and left <= right: + result = max(result, heights[left], blocks[left//B]) + left += 1 + while right % B != B-1 and left <= right: + result = max(result, heights[right], blocks[right//B]) + right -= 1 + while left <= right: + result = max(result, blocks[left//B], blocks_read[left//B]) + left += B + return result + + def update(heights, left, right, B, blocks, blocks_read, h): + while left % B and left <= right: + heights[left] = max(heights[left], h) + blocks_read[left//B] = max(blocks_read[left//B], h) + left += 1 + while right % B != B-1 and left <= right: + heights[right] = max(heights[right], h) + blocks_read[right//B] = max(blocks_read[right//B], h) + right -= 1 + while left <= right: + blocks[left//B] = max(blocks[left//B], h) + left += B + + index = set() + for left, size in positions: + index.add(left); + index.add(left+size-1) + index = sorted(list(index)) + W = len(index) + B = int(W**.5) + heights = [0] * W + blocks = [0] * (B+2) + blocks_read = [0] * (B+2) + + max_height = 0 + result = [] + for left, size in positions: + L, R = bisect.bisect_left(index, left), bisect.bisect_left(index, left+size-1) + h = query(heights, L, R, B, blocks, blocks_read) + size + update(heights, L, R, B, blocks, blocks_read, h) + max_height = max(max_height, h) + result.append(max_height) + return result + + +# Time: O(n^2) +# Space: O(n) +class Solution3(object): + def fallingSquares(self, positions): + """ + :type positions: List[List[int]] + :rtype: List[int] + """ + heights = [0] * len(positions) + for i in xrange(len(positions)): + left_i, size_i = positions[i] + right_i = left_i + size_i + heights[i] += size_i + for j in xrange(i+1, len(positions)): + left_j, size_j = positions[j] + right_j = left_j + size_j + if left_j < right_i and left_i < right_j: # intersect + heights[j] = max(heights[j], heights[i]) + + result = [] + for height in heights: + result.append(max(result[-1], height) if result else height) + return result diff --git a/Python/find-all-anagrams-in-a-string.py b/Python/find-all-anagrams-in-a-string.py new file mode 100644 index 000000000..e80e46ee0 --- /dev/null +++ b/Python/find-all-anagrams-in-a-string.py @@ -0,0 +1,59 @@ +# Time: O(n) +# Space: O(1) + +# Given a string s and a non-empty string p, find all the start indices +# of p's anagrams in s. +# +# Strings consists of lowercase English letters only and the length of +# both strings s and p will not be larger than 20,100. +# +# The order of output does not matter. +# +# Example 1: +# +# Input: +# s: "cbaebabacd" p: "abc" +# +# Output: +# [0, 6] +# +# Explanation: +# The substring with start index = 0 is "cba", which is an anagram of "abc". +# The substring with start index = 6 is "bac", which is an anagram of "abc". +# Example 2: +# +# Input: +# s: "abab" p: "ab" +# +# Output: +# [0, 1, 2] +# +# Explanation: +# The substring with start index = 0 is "ab", which is an anagram of "ab". +# The substring with start index = 1 is "ba", which is an anagram of "ab". +# The substring with start index = 2 is "ab", which is an anagram of "ab". + +class Solution(object): + def findAnagrams(self, s, p): + """ + :type s: str + :type p: str + :rtype: List[int] + """ + result = [] + + cnts = [0] * 26 + for c in p: + cnts[ord(c) - ord('a')] += 1 + + left, right = 0, 0 + while right < len(s): + cnts[ord(s[right]) - ord('a')] -= 1 + while left <= right and cnts[ord(s[right]) - ord('a')] < 0: + cnts[ord(s[left]) - ord('a')] += 1 + left += 1 + if right - left + 1 == len(p): + result.append(left) + right += 1 + + return result diff --git a/Python/find-all-duplicates-in-an-array.py b/Python/find-all-duplicates-in-an-array.py new file mode 100644 index 000000000..79c8b174c --- /dev/null +++ b/Python/find-all-duplicates-in-an-array.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of integers, 1 <= a[i] <= n (n = size of array), +# some elements appear twice and others appear once. +# Find all the elements that appear twice in this array. +# Could you do it without extra space and in O(n) runtime? +# +# Example: +# Input +# +# [4,3,2,7,8,2,3,1] +# +# Output +# +# [2,3] + +class Solution(object): + def findDuplicates(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + result = [] + i = 0 + while i < len(nums): + if nums[i] != nums[nums[i]-1]: + nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1] + else: + i += 1 + + for i in xrange(len(nums)): + if i != nums[i]-1: + result.append(nums[i]) + return result diff --git a/Python/find-all-numbers-disappeared-in-an-array.py b/Python/find-all-numbers-disappeared-in-an-array.py new file mode 100644 index 000000000..cde02ffa0 --- /dev/null +++ b/Python/find-all-numbers-disappeared-in-an-array.py @@ -0,0 +1,57 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of integers where 1 <= a[i] <= n (n = size of array), +# some elements appear twice and others appear once. +# +# Find all the elements of [1, n] inclusive that do not appear in this array. +# +# Could you do it without extra space and in O(n) runtime? +# You may assume the returned list does not count as extra space. +# +# Example: +# +# Input: +# [4,3,2,7,8,2,3,1] +# +# Output: +# [5,6] + + +class Solution(object): + def findDisappearedNumbers(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + for i in xrange(len(nums)): + if nums[abs(nums[i]) - 1] > 0: + nums[abs(nums[i]) - 1] *= -1 + + result = [] + for i in xrange(len(nums)): + if nums[i] > 0: + result.append(i+1) + else: + nums[i] *= -1 + return result + + def findDisappearedNumbers2(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + return list(set(range(1, len(nums) + 1)) - set(nums)) + + def findDisappearedNumbers3(self, nums): + for i in range(len(nums)): + index = abs(nums[i]) - 1 + nums[index] = - abs(nums[index]) + + return [i + 1 for i in range(len(nums)) if nums[i] > 0] + + +if __name__ == '__main__': + s = Solution() + r = s.findDisappearedNumbers([4, 3, 2, 7, 8, 2, 3, 1]) + print r diff --git a/Python/find-bottom-left-tree-value.py b/Python/find-bottom-left-tree-value.py new file mode 100644 index 000000000..bda1f8710 --- /dev/null +++ b/Python/find-bottom-left-tree-value.py @@ -0,0 +1,67 @@ +# Time: O(n) +# Space: O(h) + +# Given a binary tree, find the leftmost value in the last row of the tree. +# +# Example 1: +# Input: +# +# 2 +# / \ +# 1 3 +# +# Output: +# 1 +# Example 2: +# Input: +# +# 1 +# / \ +# 2 3 +# / / \ +# 4 5 6 +# / +# 7 +# +# Output: +# 7 +# Note: You may assume the tree (i.e., the given root node) is not NULL. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findBottomLeftValue(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def findBottomLeftValueHelper(root, curr_depth, max_depth, bottom_left_value): + if not root: + return max_depth, bottom_left_value + if not root.left and not root.right and curr_depth+1 > max_depth: + return curr_depth+1, root.val + max_depth, bottom_left_value = findBottomLeftValueHelper(root.left, curr_depth+1, max_depth, bottom_left_value) + max_depth, bottom_left_value = findBottomLeftValueHelper(root.right, curr_depth+1, max_depth, bottom_left_value) + return max_depth, bottom_left_value + + result, max_depth = 0, 0 + return findBottomLeftValueHelper(root, 0, max_depth, result)[1] + + +# Time: O(n) +# Space: O(n) +class Solution2(object): + def findBottomLeftValue(self, root): + """ + :type root: TreeNode + :rtype: int + """ + queue = [root] + for node in queue: + queue += filter(None, (node.right, node.left)) + return node.val diff --git a/Python/find-duplicate-file-in-system.py b/Python/find-duplicate-file-in-system.py new file mode 100644 index 000000000..34e36011e --- /dev/null +++ b/Python/find-duplicate-file-in-system.py @@ -0,0 +1,66 @@ +# Time: O(n * l), l is the average length of file content +# Space: O(n * l) + +# Given a list of directory info including directory path, +# and all the files with contents in this directory, +# you need to find out all the groups of duplicate files +# in the file system in terms of their paths. +# +# A group of duplicate files consists of at least two files that have exactly the same content. +# +# A single directory info string in the input list has the following format: +# +# "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)" +# +# It means there are n files (f1.txt, f2.txt ... fn.txt +# with content f1_content, f2_content ... fn_content, respectively) in +# directory root/d1/d2/.../dm. Note that n >= 1 and m >= 0. If m = 0, it means the directory is just the root directory. +# +# The output is a list of group of duplicate file paths. For each group, +# it contains all the file paths of the files that have the same content. +# A file path is a string that has the following format: +# +# "directory_path/file_name.txt" +# +# Example 1: +# Input: +# ["root/a 1.txt(abcd) 2.txt(efgh)", "root/c 3.txt(abcd)", "root/c/d 4.txt(efgh)", "root 4.txt(efgh)"] +# Output: +# [["root/a/2.txt","root/c/d/4.txt","root/4.txt"],["root/a/1.txt","root/c/3.txt"]] +# Note: +# No order is required for the final output. +# You may assume the directory name, file name and file content only has letters +# and digits, and the length of file content is in the range of [1,50]. +# +# The number of files given is in the range of [1,20000]. +# You may assume no files or directories share the same name in the same directory. +# You may assume each given directory info represents a unique directory. +# Directory path and file info are separated by a single blank space. +# +# Follow-up beyond contest: +# 1. Imagine you are given a real file system, how will you search files? DFS or BFS? +# 2. If the file content is very large (GB level), how will you modify your solution? +# 3. If you can only read the file by 1kb each time, how will you modify your solution? +# 4. What is the time complexity of your modified solution? +# What is the most time-consuming part and memory consuming part of it? How to optimize? +# 5. How to make sure the duplicated files you find are not false positive? + +class Solution(object): + def findDuplicate(self, paths): + """ + :type paths: List[str] + :rtype: List[List[str]] + """ + files = collections.defaultdict(list) + for path in paths: + s = path.split(" ") + for i in xrange(1,len(s)): + file_name = s[0] + "/" + s[i][0:s[i].find("(")] + file_content = s[i][s[i].find("(")+1:s[i].find(")")] + files[file_content].append(file_name) + + result = [] + for file_content, file_names in files.iteritems(): + if len(file_names)>1: + result.append(file_names) + return result diff --git a/Python/find-duplicate-subtrees.py b/Python/find-duplicate-subtrees.py new file mode 100644 index 000000000..2ec2552c2 --- /dev/null +++ b/Python/find-duplicate-subtrees.py @@ -0,0 +1,75 @@ +# Time: O(n) +# Space: O(n) + +# Given a binary tree, return all duplicate subtrees. +# For each kind of duplicate subtrees, you only need to return the root node of any one of them. +# +# Two trees are duplicate if they have the same structure with same node values. +# +# Example 1: +# 1 +# / \ +# 2 3 +# / / \ +# 4 2 4 +# / +# 4 +# The following are two duplicate subtrees: +# 2 +# / +# 4 +# and +# 4 +# Therefore, you need to return above trees' root in the form of a list. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findDuplicateSubtrees(self, root): + """ + :type root: TreeNode + :rtype: List[TreeNode] + """ + def getid(root, lookup, trees): + if root: + node_id = lookup[root.val, \ + getid(root.left, lookup, trees), \ + getid(root.right, lookup, trees)] + trees[node_id].append(root) + return node_id + trees = collections.defaultdict(list) + lookup = collections.defaultdict() + lookup.default_factory = lookup.__len__ + getid(root, lookup, trees) + return [roots[0] for roots in trees.values() if len(roots) > 1] + + +# Time: O(n * h) +# Space: O(n * h) +class Solution2(object): + def findDuplicateSubtrees(self, root): + """ + :type root: TreeNode + :rtype: List[TreeNode] + """ + def postOrderTraversal(node, lookup, result): + if not node: + return "" + s = "(" + postOrderTraversal(node.left, lookup, result) + \ + str(node.val) + \ + postOrderTraversal(node.right, lookup, result) + \ + ")" + if lookup[s] == 1: + result.append(node) + lookup[s] += 1 + return s + + lookup = collections.defaultdict(int) + result = [] + postOrderTraversal(root, lookup, result) + return result diff --git a/Python/find-k-closest-elements.py b/Python/find-k-closest-elements.py new file mode 100644 index 000000000..d983de952 --- /dev/null +++ b/Python/find-k-closest-elements.py @@ -0,0 +1,36 @@ +# Time: O(logn + k) +# Space: O(1) + +# Given a sorted array, two integers k and x, find the k closest elements to x in the array. +# The result should also be sorted in ascending order. +# If there is a tie, the smaller elements are always preferred. +# +# Example 1: +# Input: [1,2,3,4,5], k=4, x=3 +# Output: [1,2,3,4] +# Example 2: +# Input: [1,2,3,4,5], k=4, x=-1 +# Output: [1,2,3,4] +# Note: +# The value k is positive and will always be smaller than the length of the sorted array. +# Length of the given array is positive and will not exceed 10^4 +# Absolute value of elements in the array and x will not exceed 10^4 + +class Solution(object): + def findClosestElements(self, arr, k, x): + """ + :type arr: List[int] + :type k: int + :type x: int + :rtype: List[int] + """ + i = bisect.bisect_left(arr, x) + left, right = i-1, i + while k: + if right >= len(arr) or \ + (left >= 0 and abs(arr[left]-x) <= abs(arr[right]-x)): + left -= 1 + else: + right += 1 + k -= 1 + return arr[left+1:right] diff --git a/Python/find-k-pairs-with-smallest-sums.py b/Python/find-k-pairs-with-smallest-sums.py new file mode 100644 index 000000000..272a4ccff --- /dev/null +++ b/Python/find-k-pairs-with-smallest-sums.py @@ -0,0 +1,63 @@ +# Time: O(k * log(min(n, m, k))), where n is the size of num1, and m is the size of num2. +# Space: O(min(n, m, k)) + +# You are given two integer arrays nums1 +# and nums2 sorted in ascending order and an integer k. +# +# Define a pair (u,v) which consists of one element +# from the first array and one element from the second array. +# +# Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums. +# +# Example 1: +# Given nums1 = [1,7,11], nums2 = [2,4,6], k = 3 +# +# Return: [1,2],[1,4],[1,6] +# +# The first 3 pairs are returned from the sequence: +# [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6] +# Example 2: +# Given nums1 = [1,1,2], nums2 = [1,2,3], k = 2 +# +# Return: [1,1],[1,1] +# +# The first 2 pairs are returned from the sequence: +# [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3] +# Example 3: +# Given nums1 = [1,2], nums2 = [3], k = 3 +# +# Return: [1,3],[2,3] +# +# All possible pairs are returned from the sequence: +# [1,3],[2,3] + +from heapq import heappush, heappop + +class Solution(object): + def kSmallestPairs(self, nums1, nums2, k): + """ + :type nums1: List[int] + :type nums2: List[int] + :type k: int + :rtype: List[List[int]] + """ + pairs = [] + if len(nums1) > len(nums2): + tmp = self.kSmallestPairs(nums2, nums1, k) + for pair in tmp: + pairs.append([pair[1], pair[0]]) + return pairs + + min_heap = [] + def push(i, j): + if i < len(nums1) and j < len(nums2): + heappush(min_heap, [nums1[i] + nums2[j], i, j]) + + push(0, 0) + while min_heap and len(pairs) < k: + _, i, j = heappop(min_heap) + pairs.append([nums1[i], nums2[j]]) + push(i, j + 1) + if j == 0: + push(i + 1, 0) # at most queue min(n, m) space + return pairs diff --git a/Python/find-k-th-smallest-pair-distance.py b/Python/find-k-th-smallest-pair-distance.py new file mode 100644 index 000000000..6badaf3c1 --- /dev/null +++ b/Python/find-k-th-smallest-pair-distance.py @@ -0,0 +1,49 @@ +# Time: O(nlogn + nlogw), n = len(nums), w = max(nums)-min(nums) +# Space: O(1) + +# Given an integer array, return the k-th smallest distance among all the pairs. +# The distance of a pair (A, B) is defined as the absolute difference between A and B. +# +# Example 1: +# Input: +# nums = [1,3,1] +# k = 1 +# Output: 0 +# Explanation: +# Here are all the pairs: +# (1,3) -> 2 +# (1,1) -> 0 +# (3,1) -> 2 +# Then the 1st smallest distance pair is (1,1), and its distance is 0. +# +# Note: +# 2 <= len(nums) <= 10000. +# 0 <= nums[i] < 1000000. +# 1 <= k <= len(nums) * (len(nums) - 1) / 2. + +# Binary search with sliding window solution +class Solution(object): + def smallestDistancePair(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + # Sliding window solution + def possible(guess, nums, k): + count, left = 0, 0 + for right, num in enumerate(nums): + while num-nums[left] > guess: + left += 1 + count += right-left + return count >= k + + nums.sort() + left, right = 0, nums[-1]-nums[0]+1 + while left < right: + mid = left + (right-left)/2 + if possible(mid, nums, k): + right = mid + else: + left = mid+1 + return left diff --git a/Python/find-largest-value-in-each-tree-row.py b/Python/find-largest-value-in-each-tree-row.py new file mode 100644 index 000000000..0ddc4af54 --- /dev/null +++ b/Python/find-largest-value-in-each-tree-row.py @@ -0,0 +1,59 @@ +# Time: O(n) +# Space: O(h) + +# You need to find the largest value in each row of a binary tree. +# +# Example: +# Input: +# +# 1 +# / \ +# 3 2 +# / \ \ +# 5 3 9 +# +# Output: [1, 3, 9] + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def largestValues(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + def largestValuesHelper(root, depth, result): + if not root: + return + if depth == len(result): + result.append(root.val) + else: + result[depth] = max(result[depth], root.val) + largestValuesHelper(root.left, depth+1, result) + largestValuesHelper(root.right, depth+1, result) + + result = [] + largestValuesHelper(root, 0, result) + return result + + +# Time: O(n) +# Space: O(n) +class Solution2(object): + def largestValues(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + result = [] + curr = [root] + while any(curr): + result.append(max(node.val for node in curr)) + curr = [child for node in curr for child in (node.left, node.right) if child] + return result + diff --git a/Python/find-leaves-of-binary-tree.py b/Python/find-leaves-of-binary-tree.py new file mode 100644 index 000000000..0560ed748 --- /dev/null +++ b/Python/find-leaves-of-binary-tree.py @@ -0,0 +1,29 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findLeaves(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + def findLeavesHelper(node, result): + if not node: + return -1 + level = 1 + max(findLeavesHelper(node.left, result), \ + findLeavesHelper(node.right, result)) + if len(result) < level + 1: + result.append([]) + result[level].append(node.val) + return level + + result = [] + findLeavesHelper(root, result) + return result diff --git a/Python/find-median-from-data-stream.py b/Python/find-median-from-data-stream.py new file mode 100644 index 000000000..3e3f968fb --- /dev/null +++ b/Python/find-median-from-data-stream.py @@ -0,0 +1,64 @@ +# Time: O(nlogn) for total n addNums, O(logn) per addNum, O(1) per findMedian. +# Space: O(n), total space + +# Median is the middle value in an ordered integer list. +# If the size of the list is even, there is no middle value. +# So the median is the mean of the two middle value. +# +# Examples: +# [2,3,4] , the median is 3 +# +# [2,3], the median is (2 + 3) / 2 = 2.5 +# +# Design a data structure that supports the following two operations: +# +# void addNum(int num) - Add a integer number from the data stream to the data structure. +# double findMedian() - Return the median of all elements so far. +# For example: +# +# add(1) +# add(2) +# findMedian() -> 1.5 +# add(3) +# findMedian() -> 2 + +# Heap solution. +from heapq import heappush, heappop + +class MedianFinder: + def __init__(self): + """ + Initialize your data structure here. + """ + self.__max_heap = [] + self.__min_heap = [] + + def addNum(self, num): + """ + Adds a num into the data structure. + :type num: int + :rtype: void + """ + # Balance smaller half and larger half. + if not self.__max_heap or num > -self.__max_heap[0]: + heappush(self.__min_heap, num) + if len(self.__min_heap) > len(self.__max_heap) + 1: + heappush(self.__max_heap, -heappop(self.__min_heap)) + else: + heappush(self.__max_heap, -num) + if len(self.__max_heap) > len(self.__min_heap): + heappush(self.__min_heap, -heappop(self.__max_heap)) + + def findMedian(self): + """ + Returns the median of current data stream + :rtype: float + """ + return (-self.__max_heap[0] + self.__min_heap[0]) / 2.0 \ + if len(self.__min_heap) == len(self.__max_heap) \ + else self.__min_heap[0] + +# Your MedianFinder object will be instantiated and called as such: +# mf = MedianFinder() +# mf.addNum(1) +# mf.findMedian() diff --git a/Python/find-minimum-in-rotated-sorted-array-ii.py b/Python/find-minimum-in-rotated-sorted-array-ii.py index 0340791a2..fcb09d212 100644 --- a/Python/find-minimum-in-rotated-sorted-array-ii.py +++ b/Python/find-minimum-in-rotated-sorted-array-ii.py @@ -14,46 +14,46 @@ # The array may contain duplicates. # +class Solution(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums) - 1 + while left < right: + mid = left + (right - left) / 2 -class Solution: - # @param num, a list of integer - # @return an integer - def findMin(self, num): - low, high = 0, len(num) - - while low < high - 1 and num[low] >= num[high - 1]: - mid = low + (high - low) / 2 - - if num[mid] > num[low]: - low = mid + 1 - elif num[mid] < num[low]: - if mid == high - 1: - return num[mid] - else: - high = mid + 1 + if nums[mid] == nums[right]: + right -= 1 + elif nums[mid] < nums[right]: + right = mid else: - low += 1 - - return num[low] - -class Solution2: - # @param num, a list of integer - # @return an integer - def findMin(self, num): - low, high = 0, len(num) - 1 - - while low < high and num[low] >= num[high]: - mid = low + (high - low) / 2 + left = mid + 1 + + return nums[left] + + +class Solution2(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums) - 1 + while left < right and nums[left] >= nums[right]: + mid = left + (right - left) / 2 - if num[mid] > num[low]: - low = mid + 1 - elif num[mid] < num[low]: - high = mid + if nums[mid] == nums[left]: + left += 1 + elif nums[mid] < nums[left]: + right = mid else: - low += 1 + left = mid + 1 + + return nums[left] - return num[low] if __name__ == "__main__": print Solution().findMin([3, 1, 1, 2, 2, 3]) - print Solution2().findMin([2, 2, 2, 3, 3, 1]) \ No newline at end of file + print Solution2().findMin([2, 2, 2, 3, 3, 1]) diff --git a/Python/find-minimum-in-rotated-sorted-array.py b/Python/find-minimum-in-rotated-sorted-array.py index b54c78042..87bf741e8 100644 --- a/Python/find-minimum-in-rotated-sorted-array.py +++ b/Python/find-minimum-in-rotated-sorted-array.py @@ -10,46 +10,47 @@ # You may assume no duplicate exists in the array. # -class Solution: - # @param num, a list of integer - # @return an integer - def findMin(self, num): - low, high = 0, len(num) - - while low < high - 1 and num[low] >= num[high - 1]: - mid = low + (high - low) / 2 - - if num[mid] > num[low]: - low = mid + 1 - elif num[mid] < num[low]: - if mid == high - 1: - return num[mid] - else: - high = mid + 1 +class Solution(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums) + target = nums[-1] + + while left < right: + mid = left + (right - left) / 2 + + if nums[mid] <= target: + right = mid else: - return num[mid] - - return num[low] - -class Solution2: - # @param num, a list of integer - # @return an integer - def findMin(self, num): - low, high = 0, len(num) - 1 - - while low < high and num[low] >= num[high]: - mid = low + (high - low) / 2 - - if num[mid] >= num[low]: - low = mid + 1 + left = mid + 1 + + return nums[left] + + +class Solution2(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums) - 1 + while left < right and nums[left] >= nums[right]: + mid = left + (right - left) / 2 + + if nums[mid] < nums[left]: + right = mid else: - high = mid + left = mid + 1 + + return nums[left] - return num[low] if __name__ == "__main__": print Solution().findMin([1]) print Solution().findMin([1, 2]) print Solution().findMin([2, 1]) print Solution().findMin([3, 1, 2]) - print Solution().findMin([2, 3, 1]) \ No newline at end of file + print Solution().findMin([2, 3, 1]) diff --git a/Python/find-mode-in-binary-search-tree.py b/Python/find-mode-in-binary-search-tree.py new file mode 100644 index 000000000..60a53fa65 --- /dev/null +++ b/Python/find-mode-in-binary-search-tree.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(1) + +# Given a binary search tree (BST) with duplicates, +# find all the mode(s) (the most frequently occurred element) in the given BST. +# +# Assume a BST is defined as follows: +# +# The left subtree of a node contains only nodes with keys less than or equal to the node's key. +# The right subtree of a node contains only nodes with keys greater than or equal to the node's key. +# Both the left and right subtrees must also be binary search trees. +# For example: +# Given BST [1,null,2,2], +# 1 +# \ +# 2 +# / +# 2 +# return [2]. +# +# Note: If a tree has more than one mode, you can return them in any order. +# +# Follow up: Could you do that without using any extra space? +# (Assume that the implicit stack space incurred due to recursion does not count). + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findMode(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + def inorder(root, prev, cnt, max_cnt, result): + if not root: + return prev, cnt, max_cnt + + prev, cnt, max_cnt = inorder(root.left, prev, cnt, max_cnt, result) + if prev: + if root.val == prev.val: + cnt += 1 + else: + cnt = 1 + if cnt > max_cnt: + max_cnt = cnt; + del result[:] + result.append(root.val) + elif cnt == max_cnt: + result.append(root.val) + return inorder(root.right, root, cnt, max_cnt, result) + + if not root: + return [] + result = [] + inorder(root, None, 1, 0, result); + return result diff --git a/Python/find-peak-element.py b/Python/find-peak-element.py index 84eb19221..dfa85fd2d 100644 --- a/Python/find-peak-element.py +++ b/Python/find-peak-element.py @@ -1,39 +1,41 @@ # Time: O(logn) # Space: O(1) -# + # A peak element is an element that is greater than its neighbors. # -# Given an input array where num[i] != num[i+1], find a peak element and return its index. +# Given an input array where num[i] != num[i+1], +# find a peak element and return its index. # -# The array may contain multiple peaks, in that case return the index to any one of the peaks is fine. +# The array may contain multiple peaks, in that case +# return the index to any one of the peaks is fine. # # You may imagine that num[-1] = num[n] = -infinite. # -# For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2. +# For example, in array [1, 2, 3, 1], 3 is a peak element +# and your function should return the index number 2. # # Note: # Your solution should be in logarithmic complexity. -# -class Solution: - # @param num, a list of integer - # @return an integer - def findPeakElement(self, num): - low, high = 0, len(num) - 1 + +class Solution(object): + def findPeakElement(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums) - 1 - while low < high: - mid = low + (high - low) / 2 - if (mid == 0 or num[mid - 1] <= num[mid]) and \ - (mid == len(num) - 1 or num[mid + 1] <= num[mid]): - return mid - elif mid > 0 and num[mid - 1] > num[mid]: - high = mid - 1 + while left < right: + mid = left + (right - left) / 2 + if nums[mid] > nums[mid + 1]: + right = mid else: - low = mid + 1 - mid = low + (high - low) / 2 + left = mid + 1 - return low + return left + if __name__ == "__main__": # print Solution().findPeakElement([1,2,1]) - print Solution().findPeakElement([1,2,3, 1]) \ No newline at end of file + print Solution().findPeakElement([1,2,3,1]) diff --git a/Python/find-permutation.py b/Python/find-permutation.py new file mode 100644 index 000000000..4a9710abf --- /dev/null +++ b/Python/find-permutation.py @@ -0,0 +1,14 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def findPermutation(self, s): + """ + :type s: str + :rtype: List[int] + """ + result = [] + for i in xrange(len(s)+1): + if i == len(s) or s[i] == 'I': + result += range(i+1, len(result), -1) + return result diff --git a/Python/find-pivot-index.py b/Python/find-pivot-index.py new file mode 100644 index 000000000..5ca035a46 --- /dev/null +++ b/Python/find-pivot-index.py @@ -0,0 +1,44 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of integers nums, write a method that returns the "pivot" index of this array. +# +# We define the pivot index as the index where the sum of the numbers to +# the left of the index is equal to the sum of the numbers to the right of the index. +# +# If no such index exists, we should return -1. If there are multiple pivot indexes, +# you should return the left-most pivot index. +# +# Example 1: +# Input: +# nums = [1, 7, 3, 6, 5, 6] +# Output: 3 +# Explanation: +# The sum of the numbers to the left of index 3 (nums[3] = 6) is equal to the sum of numbers to the right of index 3. +# Also, 3 is the first index where this occurs. +# +# Example 2: +# Input: +# nums = [1, 2, 3] +# Output: -1 +# Explanation: +# There is no index that satisfies the conditions in the problem statement. +# +# Note: +# - The length of nums will be in the range [0, 10000]. +# - Each element nums[i] will be an integer in the range [-1000, 1000]. + +class Solution(object): + def pivotIndex(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + total = sum(nums) + left_sum = 0 + for i, num in enumerate(nums): + if left_sum == (total-left_sum-num): + return i + left_sum += num + return -1 + diff --git a/Python/find-right-interval.py b/Python/find-right-interval.py new file mode 100644 index 000000000..8c1a9a9a2 --- /dev/null +++ b/Python/find-right-interval.py @@ -0,0 +1,55 @@ +# Time: O(nlogn) +# Space: O(n) + +# Given a set of intervals, for each of the interval i, +# check if there exists an interval j whose start point is bigger than or +# equal to the end point of the interval i, which can be called that j is on the "right" of i. +# +# For any interval i, you need to store the minimum interval j's index, +# which means that the interval j has the minimum start point to +# build the "right" relationship for interval i. If the interval j doesn't exist, +# store -1 for the interval i. Finally, you need output the stored value of each interval as an array. +# +# Note: +# You may assume the interval's end point is always bigger than its start point. +# You may assume none of these intervals have the same start point. +# Example 1: +# Input: [ [1,2] ] +# +# Output: [-1] +# +# Explanation: There is only one interval in the collection, so it outputs -1. +# Example 2: +# Input: [ [3,4], [2,3], [1,2] ] +# +# Output: [-1, 0, 1] +# +# Explanation: There is no satisfied "right" interval for [3,4]. +# For [2,3], the interval [3,4] has minimum-"right" start point; +# For [1,2], the interval [2,3] has minimum-"right" start point. +# Example 3: +# Input: [ [1,4], [2,3], [3,4] ] +# +# Output: [-1, 2, -1] +# +# Explanation: There is no satisfied "right" interval for [1,4] and [3,4]. +# For [2,3], the interval [3,4] has minimum-"right" start point. +# +# Definition for an interval. +# class Interval(object): +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution(object): + def findRightInterval(self, intervals): + """ + :type intervals: List[Interval] + :rtype: List[int] + """ + sorted_intervals = sorted((interval.start, i) for i, interval in enumerate(intervals)) + result = [] + for interval in intervals: + idx = bisect.bisect_left(sorted_intervals, (interval.end,)) + result.append(sorted_intervals[idx][1] if idx < len(sorted_intervals) else -1) + return result diff --git a/Python/find-smallest-letter-greater-than-target.py b/Python/find-smallest-letter-greater-than-target.py new file mode 100644 index 000000000..0f8fc0c37 --- /dev/null +++ b/Python/find-smallest-letter-greater-than-target.py @@ -0,0 +1,52 @@ +# Time: O(logn) +# Space: O(1) + +# Given a list of sorted characters letters containing only lowercase letters, +# and given a target letter target, find the smallest element in the list that is larger than the given target. +# +# Letters also wrap around. For example, if the target is target = 'z' and letters = ['a', 'b'], the answer is 'a'. +# +# Examples: +# Input: +# letters = ["c", "f", "j"] +# target = "a" +# Output: "c" +# +# Input: +# letters = ["c", "f", "j"] +# target = "c" +# Output: "f" +# +# Input: +# letters = ["c", "f", "j"] +# target = "d" +# Output: "f" +# +# Input: +# letters = ["c", "f", "j"] +# target = "g" +# Output: "j" +# +# Input: +# letters = ["c", "f", "j"] +# target = "j" +# Output: "c" +# +# Input: +# letters = ["c", "f", "j"] +# target = "k" +# Output: "c" +# Note: +# - letters has a length in range [2, 10000]. +# - letters consists of lowercase letters, and contains at least 2 unique letters. +# - target is a lowercase letter. + +class Solution(object): + def nextGreatestLetter(self, letters, target): + """ + :type letters: List[str] + :type target: str + :rtype: str + """ + i = bisect.bisect_right(letters, target) + return letters[0] if i == len(letters) else letters[i] diff --git a/Python/find-the-celebrity.py b/Python/find-the-celebrity.py new file mode 100644 index 000000000..da013af89 --- /dev/null +++ b/Python/find-the-celebrity.py @@ -0,0 +1,27 @@ +# Time: O(n) +# Space: O(1) +# +# The knows API is already defined for you. +# @param a, person a +# @param b, person b +# @return a boolean, whether a knows b +# def knows(a, b): +# + +class Solution(object): + def findCelebrity(self, n): + """ + :type n: int + :rtype: int + """ + candidate = 0 + # Find the candidate. + for i in xrange(1, n): + if knows(candidate, i): # All candidates < i are not celebrity candidates. + candidate = i + # Verify the candidate. + for i in xrange(n): + if i != candidate and (knows(candidate, i) \ + or not knows(i, candidate)): + return -1 + return candidate diff --git a/Python/find-the-closest-palindrome.py b/Python/find-the-closest-palindrome.py new file mode 100644 index 000000000..f4b9bae21 --- /dev/null +++ b/Python/find-the-closest-palindrome.py @@ -0,0 +1,27 @@ +# Time: O(l) +# Space: O(l) + +# Given an integer n, find the closest integer (not including itself), which is a palindrome. +# +# The 'closest' is defined as absolute difference minimized between two integers. +# +# Example 1: +# Input: "123" +# Output: "121" +# Note: +# The input n is a positive integer represented by string, whose length will not exceed 18. +# If there is a tie, return the smaller one as answer. + +class Solution(object): + def nearestPalindromic(self, n): + """ + :type n: str + :rtype: str + """ + l = len(n) + candidates = set((str(10**l + 1), str(10**(l - 1) - 1))) + prefix = int(n[:(l + 1)/2]) + for i in map(str, (prefix-1, prefix, prefix+1)): + candidates.add(i + [i, i[:-1]][l%2][::-1]) + candidates.discard(n) + return min(candidates, key=lambda x: (abs(int(x) - int(n)), int(x))) diff --git a/Python/find-the-derangement-of-an-array.py b/Python/find-the-derangement-of-an-array.py new file mode 100644 index 000000000..67ac500b2 --- /dev/null +++ b/Python/find-the-derangement-of-an-array.py @@ -0,0 +1,15 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def findDerangement(self, n): + """ + :type n: int + :rtype: int + """ + M = 1000000007 + mul, total = 1, 0 + for i in reversed(xrange(n+1)): + total = (total + M + (1 if i % 2 == 0 else -1) * mul) % M + mul = (mul * i) % M + return total diff --git a/Python/find-the-difference.py b/Python/find-the-difference.py new file mode 100644 index 000000000..d661e7967 --- /dev/null +++ b/Python/find-the-difference.py @@ -0,0 +1,62 @@ +# Time: O(n) +# Space: O(1) + +# Given two strings s and t which consist of only lowercase letters. +# +# String t is generated by random shuffling string s +# and then add one more letter at a random position. +# +# Find the letter that was added in t. +# +# Example: +# +# Input: +# s = "abcd" +# t = "abcde" +# +# Output: +# e +# +# Explanation: +# 'e' is the letter that was added. + +import operator +import collections + + +class Solution(object): + def findTheDifference(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ + return chr(reduce(operator.xor, map(ord, s), 0) ^ reduce(operator.xor, map(ord, t), 0)) + + def findTheDifference2(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ + t = list(t) + s = list(s) + for i in s: + t.remove(i) + return t[0] + + def findTheDifference3(self, s, t): + return chr(reduce(operator.xor, map(ord, s + t))) + + def findTheDifference4(self, s, t): + return list((collections.Counter(t) - collections.Counter(s)))[0] + + def findTheDifference5(self, s, t): + s, t = sorted(s), sorted(t) + return t[-1] if s == t[:-1] else [x[1] for x in zip(s, t) if x[0] != x[1]][0] + + +if __name__ == '__main__': + s = Solution() + r = s.findTheDifference2('abcd', 'abcde') + print r diff --git a/Python/find-the-duplicate-number.py b/Python/find-the-duplicate-number.py new file mode 100644 index 000000000..c7c9fe49d --- /dev/null +++ b/Python/find-the-duplicate-number.py @@ -0,0 +1,85 @@ +# Time: O(n) +# Space: O(1) +# +# Given an array nums containing n + 1 integers where each integer +# is between 1 and n (inclusive), prove that at least one duplicate +# element must exist. Assume that there is only one duplicate number, +# find the duplicate one. +# +# Note: +# - You must not modify the array (assume the array is read only). +# - You must use only constant extra space. +# - Your runtime complexity should be less than O(n^2). +# + +# Two pointers method, same as Linked List Cycle II. +class Solution(object): + def findDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + # Treat each (key, value) pair of the array as the (pointer, next) node of the linked list, + # thus the duplicated number will be the begin of the cycle in the linked list. + # Besides, there is always a cycle in the linked list which + # starts from the first element of the array. + slow = nums[0] + fast = nums[nums[0]] + while slow != fast: + slow = nums[slow] + fast = nums[nums[fast]] + + fast = 0 + while slow != fast: + slow = nums[slow] + fast = nums[fast] + return slow + + +# Time: O(nlogn) +# Space: O(1) +# Binary search method. +class Solution2(object): + def findDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 1, len(nums) - 1 + + while left <= right: + mid = left + (right - left) / 2 + # Get count of num <= mid. + count = 0 + for num in nums: + if num <= mid: + count += 1 + if count > mid: + right = mid - 1 + else: + left = mid + 1 + return left + +# Time: O(n) +# Space: O(n) +class Solution3(object): + def findDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + duplicate = 0 + # Mark the value as visited by negative. + for num in nums: + if nums[abs(num) - 1] > 0: + nums[abs(num) - 1] *= -1 + else: + duplicate = abs(num) + break + # Rollback the value. + for num in nums: + if nums[abs(num) - 1] < 0: + nums[abs(num) - 1] *= -1 + else: + break + return duplicate diff --git a/Python/first-bad-version.py b/Python/first-bad-version.py new file mode 100644 index 000000000..af2bdc0a5 --- /dev/null +++ b/Python/first-bad-version.py @@ -0,0 +1,38 @@ +# Time: O(logn) +# Space: O(1) +# +# You are a product manager and currently leading a team to +# develop a new product. Unfortunately, the latest version of +# your product fails the quality check. Since each version is +# developed based on the previous version, all the versions +# after a bad version are also bad. +# +# Suppose you have n versions [1, 2, ..., n] and you want to +# find out the first bad one, which causes all the following +# ones to be bad. +# +# You are given an API bool isBadVersion(version) which will +# return whether version is bad. Implement a function to find +# the first bad version. You should minimize the number of +# calls to the API. +# + +# The isBadVersion API is already defined for you. +# @param version, an integer +# @return a bool +# def isBadVersion(version): + +class Solution(object): + def firstBadVersion(self, n): + """ + :type n: int + :rtype: int + """ + left, right = 1, n + while left <= right: + mid = left + (right - left) / 2 + if isBadVersion(mid): + right = mid - 1 + else: + left = mid + 1 + return left diff --git a/Python/first-missing-positive.py b/Python/first-missing-positive.py index b2fa788f0..134baa714 100644 --- a/Python/first-missing-positive.py +++ b/Python/first-missing-positive.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(n) +# Space: O(1) # # Given an unsorted integer array, find the first missing positive integer. # @@ -28,4 +28,4 @@ def firstMissingPositive(self, A): if __name__ == "__main__": print Solution().firstMissingPositive([1,2,0]) - print Solution().firstMissingPositive([3,4,-1,1]) \ No newline at end of file + print Solution().firstMissingPositive([3,4,-1,1]) diff --git a/Python/first-unique-character-in-a-string.py b/Python/first-unique-character-in-a-string.py new file mode 100644 index 000000000..9dbbff04e --- /dev/null +++ b/Python/first-unique-character-in-a-string.py @@ -0,0 +1,34 @@ +# Time: O(n) +# Space: O(n) + +# Given a string, find the first non-repeating character in it and +# return it's index. If it doesn't exist, return -1. +# +# Examples: +# +# s = "leetcode" +# return 0. +# +# s = "loveleetcode", +# return 2. +# Note: You may assume the string contain only lowercase letters. + + +from collections import defaultdict + +class Solution(object): + def firstUniqChar(self, s): + """ + :type s: str + :rtype: int + """ + lookup = defaultdict(int) + candidtates = set() + for i, c in enumerate(s): + if lookup[c]: + candidtates.discard(lookup[c]) + else: + lookup[c] = i+1 + candidtates.add(i+1) + + return min(candidtates)-1 if candidtates else -1 diff --git a/Python/fizz-buzz.py b/Python/fizz-buzz.py new file mode 100644 index 000000000..0e46b90e1 --- /dev/null +++ b/Python/fizz-buzz.py @@ -0,0 +1,74 @@ +# Time: O(n) +# Space: O(1) + +# Write a program that outputs the string representation of numbers from 1 to n. +# +# But for multiples of three it should output “Fizz” instead of the number and for +# the multiples of five output “Buzz”. For numbers which are multiples of both three +# and five output “FizzBuzz”. +# +# Example: +# +# n = 15, +# +# Return: +# [ +# "1", +# "2", +# "Fizz", +# "4", +# "Buzz", +# "Fizz", +# "7", +# "8", +# "Fizz", +# "Buzz", +# "11", +# "Fizz", +# "13", +# "14", +# "FizzBuzz" +# ] + +class Solution(object): + def fizzBuzz(self, n): + """ + :type n: int + :rtype: List[str] + """ + result = [] + + for i in xrange(1, n+1): + if i % 15 == 0: + result.append("FizzBuzz") + elif i % 5 == 0: + result.append("Buzz") + elif i % 3 == 0: + result.append("Fizz") + else: + result.append(str(i)) + + return result + + def fizzBuzz2(self, n): + """ + :type n: int + :rtype: List[str] + """ + l = [str(x) for x in range(n + 1)] + l3 = range(0, n + 1, 3) + l5 = range(0, n + 1, 5) + for i in l3: + l[i] = 'Fizz' + for i in l5: + if l[i] == 'Fizz': + l[i] += 'Buzz' + else: + l[i] = 'Buzz' + return l[1:] + + def fizzBuzz3(self, n): + return ['Fizz' * (not i % 3) + 'Buzz' * (not i % 5) or str(i) for i in range(1, n + 1)] + + def fizzBuzz4(self, n): + return ['FizzBuzz'[i % -3 & -4:i % -5 & 8 ^ 12] or `i` for i in range(1, n + 1)] diff --git a/Python/flatten-2d-vector.py b/Python/flatten-2d-vector.py new file mode 100644 index 000000000..7b40db259 --- /dev/null +++ b/Python/flatten-2d-vector.py @@ -0,0 +1,32 @@ +# Time: O(1) +# Space: O(1) + +class Vector2D: + x, y = 0, 0 + vec = None + + # Initialize your data structure here. + # @param {integer[][]} vec2d + def __init__(self, vec2d): + self.vec = vec2d + self.x = 0 + if self.x != len(self.vec): + self.y = 0 + self.adjustNextIter() + + # @return {integer} + def next(self): + ret = self.vec[self.x][self.y] + self.y += 1 + self.adjustNextIter() + return ret + + # @return {boolean} + def hasNext(self): + return self.x != len(self.vec) and self.y != len(self.vec[self.x]) + + def adjustNextIter(self): + while self.x != len(self.vec) and self.y == len(self.vec[self.x]): + self.x += 1 + if self.x != len(self.vec): + self.y = 0 diff --git a/Python/flatten-binary-tree-to-linked-list.py b/Python/flatten-binary-tree-to-linked-list.py index 8d081290a..579f2e319 100644 --- a/Python/flatten-binary-tree-to-linked-list.py +++ b/Python/flatten-binary-tree-to-linked-list.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, flatten it to a linked list in-place. # @@ -74,4 +74,4 @@ def flatten(self, root): print result.right.right.val print result.right.right.right.val print result.right.right.right.right.val - print result.right.right.right.right.right.val \ No newline at end of file + print result.right.right.right.right.right.val diff --git a/Python/flatten-nested-list-iterator.py b/Python/flatten-nested-list-iterator.py new file mode 100644 index 000000000..e9646fb69 --- /dev/null +++ b/Python/flatten-nested-list-iterator.py @@ -0,0 +1,66 @@ +# Time: O(n), n is the number of the integers. +# Space: O(h), h is the depth of the nested lists. + +# """ +# This is the interface that allows for creating nested lists. +# You should not implement it, or speculate about its implementation +# """ +#class NestedInteger(object): +# def isInteger(self): +# """ +# @return True if this NestedInteger holds a single integer, rather than a nested list. +# :rtype bool +# """ +# +# def getInteger(self): +# """ +# @return the single integer that this NestedInteger holds, if it holds a single integer +# Return None if this NestedInteger holds a nested list +# :rtype int +# """ +# +# def getList(self): +# """ +# @return the nested list that this NestedInteger holds, if it holds a nested list +# Return None if this NestedInteger holds a single integer +# :rtype List[NestedInteger] +# """ + +class NestedIterator(object): + + def __init__(self, nestedList): + """ + Initialize your data structure here. + :type nestedList: List[NestedInteger] + """ + self.__depth = [[nestedList, 0]] + + + def next(self): + """ + :rtype: int + """ + nestedList, i = self.__depth[-1] + self.__depth[-1][1] += 1 + return nestedList[i].getInteger() + + + def hasNext(self): + """ + :rtype: bool + """ + while self.__depth: + nestedList, i = self.__depth[-1] + if i == len(nestedList): + self.__depth.pop() + elif nestedList[i].isInteger(): + return True + else: + self.__depth[-1][1] += 1 + self.__depth.append([nestedList[i].getList(), 0]) + return False + + +# Your NestedIterator object will be instantiated and called as such: +# i, v = NestedIterator(nestedList), [] +# while i.hasNext(): v.append(i.next()) diff --git a/Python/flip-game-ii.py b/Python/flip-game-ii.py new file mode 100644 index 000000000..79cc4b979 --- /dev/null +++ b/Python/flip-game-ii.py @@ -0,0 +1,67 @@ +# Time: O(n + c^2) +# Space: O(c) + +# The best theory solution (DP, O(n + c^2)) could be seen here: +# https://leetcode.com/discuss/64344/theory-matters-from-backtracking-128ms-to-dp-0m +class Solution(object): + def canWin(self, s): + g, g_final = [0], 0 + for p in itertools.imap(len, re.split('-+', s)): + while len(g) <= p: + # Theorem 2: g[game] = g[subgame1]^g[subgame2]^g[subgame3]...; + # and find first missing number. + g += min(set(xrange(p)) - {x^y for x, y in itertools.izip(g[:len(g)/2], g[-2:-len(g)/2-2:-1])}), + g_final ^= g[p] + return g_final > 0 # Theorem 1: First player must win iff g(current_state) != 0 + + +# Time: O(n + c^3 * 2^c * logc), n is length of string, c is count of "++" +# Space: O(c * 2^c) +# hash solution. +# We have total O(2^c) game strings, +# and each hash key in hash table would cost O(c), +# each one has O(c) choices to the next one, +# and each one would cost O(clogc) to sort, +# so we get O((c * 2^c) * (c * clogc)) = O(c^3 * 2^c * logc) time. +# To cache the results of all combinations, thus O(c * 2^c) space. +class Solution2(object): + def canWin(self, s): + """ + :type s: str + :rtype: bool + """ + lookup = {} + + def canWinHelper(consecutives): # O(2^c) time + consecutives = tuple(sorted(c for c in consecutives if c >= 2)) # O(clogc) time + if consecutives not in lookup: + lookup[consecutives] = any(not canWinHelper(consecutives[:i] + (j, c-2-j) + consecutives[i+1:]) # O(c) time + for i, c in enumerate(consecutives) # O(c) time + for j in xrange(c - 1)) # O(c) time + return lookup[consecutives] # O(c) time + + # re.findall: O(n) time, canWinHelper: O(c) in depth + return canWinHelper(map(len, re.findall(r'\+\++', s))) + + +# Time: O(c * n * c!), n is length of string, c is count of "++" +# Space: O(c * n), recursion would be called at most c in depth. +# Besides, it costs n space for modifying string at each depth. +class Solution3(object): + def canWin(self, s): + """ + :type s: str + :rtype: bool + """ + i, n = 0, len(s) - 1 + is_win = False + while not is_win and i < n: # O(n) time + if s[i] == '+': + while not is_win and i < n and s[i+1] == '+': # O(c) time + # t(n, c) = c * (t(n, c-1) + n) + n = ... + # = c! * t(n, 0) + n * c! * (c + 1) * (1/0! + 1/1! + ... 1/c!) + # = n * c! + n * c! * (c + 1) * O(e) = O(c * n * c!) + is_win = not self.canWin(s[:i] + '--' + s[i+2:]) # O(n) space + i += 1 + i += 1 + return is_win diff --git a/Python/flip-game.py b/Python/flip-game.py new file mode 100644 index 000000000..8c8760f43 --- /dev/null +++ b/Python/flip-game.py @@ -0,0 +1,32 @@ +# Time: O(c * n + n) = O(n * (c+1)) +# Space: O(n) + +# This solution compares only O(1) times for the two consecutive "+" +class Solution(object): + def generatePossibleNextMoves(self, s): + """ + :type s: str + :rtype: List[str] + """ + res = [] + i, n = 0, len(s) - 1 + while i < n: # O(n) time + if s[i] == '+': + while i < n and s[i+1] == '+': # O(c) time + res.append(s[:i] + '--' + s[i+2:]) # O(n) time and space + i += 1 + i += 1 + return res + + +# Time: O(c * m * n + n) = O(c * n + n), where m = 2 in this question +# Space: O(n) +# This solution compares O(m) = O(2) times for two consecutive "+", where m is length of the pattern +class Solution2(object): + def generatePossibleNextMoves(self, s): + """ + :type s: str + :rtype: List[str] + """ + return [s[:i] + "--" + s[i+2:] for i in xrange(len(s) - 1) if s[i:i+2] == "++"] + diff --git a/Python/flood-fill.py b/Python/flood-fill.py new file mode 100644 index 000000000..7f1149a0f --- /dev/null +++ b/Python/flood-fill.py @@ -0,0 +1,57 @@ +# Time: O(m * n) +# Space: O(m * n) + +# An image is represented by a 2-D array of integers, +# each integer representing the pixel value of the image (from 0 to 65535). +# +# Given a coordinate (sr, sc) representing the starting pixel (row and column) +# of the flood fill, and a pixel value newColor, "flood fill" the image. +# +# To perform a "flood fill", consider the starting pixel, +# plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, +# plus any pixels connected 4-directionally to those pixels (also with the same color as the starting pixel), +# and so on. Replace the color of all of the aforementioned pixels with the newColor. +# +# At the end, return the modified image. +# +# Example 1: +# Input: +# image = [[1,1,1],[1,1,0],[1,0,1]] +# sr = 1, sc = 1, newColor = 2 +# Output: [[2,2,2],[2,2,0],[2,0,1]] +# Explanation: +# From the center of the image (with position (sr, sc) = (1, 1)), all pixels connected +# by a path of the same color as the starting pixel are colored with the new color. +# Note the bottom corner is not colored 2, because it is not 4-directionally connected +# to the starting pixel. +# +# Note: +# - The length of image and image[0] will be in the range [1, 50]. +# - The given starting pixel will satisfy 0 <= sr < image.length and 0 <= sc < image[0].length. +# - The value of each color in image[i][j] and newColor will be an integer in [0, 65535]. + +class Solution(object): + def floodFill(self, image, sr, sc, newColor): + """ + :type image: List[List[int]] + :type sr: int + :type sc: int + :type newColor: int + :rtype: List[List[int]] + """ + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + + def dfs(image, r, c, newColor, color): + if not (0 <= r < len(image) and \ + 0 <= c < len(image[0]) and \ + image[r][c] == color): + return + + image[r][c] = newColor + for d in directions: + dfs(image, r+d[0], c+d[1], newColor, color) + + color = image[sr][sc] + if color == newColor: return image + dfs(image, sr, sc, newColor, color) + return image diff --git a/Python/fraction-addition-and-subtraction.py b/Python/fraction-addition-and-subtraction.py new file mode 100644 index 000000000..cd51acb8e --- /dev/null +++ b/Python/fraction-addition-and-subtraction.py @@ -0,0 +1,53 @@ +# Time: O(nlogx), x is the max denominator +# Space: O(n) + +# Given a string representing an expression of fraction addition and subtraction, +# you need to return the calculation result in string format. +# The final result should be irreducible fraction. If your final result is an integer, say 2, +# you need to change it to the format of fraction that has denominator 1. +# So in this case, 2 should be converted to 2/1. +# +# Example 1: +# Input:"-1/2+1/2" +# Output: "0/1" +# Example 2: +# Input:"-1/2+1/2+1/3" +# Output: "1/3" +# Example 3: +# Input:"1/3-1/2" +# Output: "-1/6" +# Example 4: +# Input:"5/3+1/3" +# Output: "2/1" +# Note: +# The input string only contains '0' to '9', '/', '+' and '-'. So does the output. +# Each fraction (input and output) has format ±numerator/denominator. +# If the first input fraction or the output is positive, then '+' will be omitted. +# The input only contains valid irreducible fractions, +# where the numerator and denominator of each fraction will +# always be in the range [1,10]. If the denominator is 1, +# it means this fraction is actually an integer in a fraction format defined above. +# The number of given fractions will be in the range [1,10]. +# The numerator and denominator of the final result are guaranteed to be valid and in the range of 32-bit int. + +class Solution(object): + def fractionAddition(self, expression): + """ + :type expression: str + :rtype: str + """ + def gcd(a, b): + while b: + a, b = b, a%b + return a + + ints = map(int, re.findall('[+-]?\d+', expression)) + A, B = 0, 1 + for i in xrange(0, len(ints), 2): + a, b = ints[i], ints[i+1] + A = A * b + a * B + B *= b + g = gcd(A, B) + A //= g + B //= g + return '%d/%d' % (A, B) diff --git a/Python/fraction-to-recurring-decimal.py b/Python/fraction-to-recurring-decimal.py index 13aa5a9e4..98dff2202 100644 --- a/Python/fraction-to-recurring-decimal.py +++ b/Python/fraction-to-recurring-decimal.py @@ -1,7 +1,8 @@ # Time: O(logn), where logn is the length of result strings # Space: O(1) -# -# Given two integers representing the numerator and denominator of a fraction, return the fraction in string format. + +# Given two integers representing the numerator and denominator of a fraction, +# return the fraction in string format. # # If the fractional part is repeating, enclose the repeating part in parentheses. # @@ -10,43 +11,40 @@ # Given numerator = 1, denominator = 2, return "0.5". # Given numerator = 2, denominator = 1, return "2". # Given numerator = 2, denominator = 3, return "0.(6)". -# -class Solution: - # @return a string +class Solution(object): def fractionToDecimal(self, numerator, denominator): + """ + :type numerator: int + :type denominator: int + :rtype: str + """ + result = "" + if (numerator > 0 and denominator < 0) or (numerator < 0 and denominator > 0): + result = "-" + dvd, dvs = abs(numerator), abs(denominator) - integer, decimal, dict = "", "", {} - - if dvd > dvs: - integer = str(dvd / dvs) - dvd %= dvs - else: - integer = "0" - + result += str(dvd / dvs) + dvd %= dvs + if dvd > 0: - integer += "." - - idx = 0 - while dvd: - if dvd in dict: - decimal = decimal[:dict[dvd]] + "(" + decimal[dict[dvd]:] + ")" - break - - dict[dvd] = idx - idx += 1 - + result += "." + + lookup = {} + while dvd and dvd not in lookup: + lookup[dvd] = len(result) dvd *= 10 - decimal += str(dvd / dvs) + result += str(dvd / dvs) dvd %= dvs - - if (numerator > 0 and denominator < 0) or (numerator < 0 and denominator > 0): - return "-" + integer + decimal - else: - return integer + decimal + + if dvd in lookup: + result = result[:lookup[dvd]] + "(" + result[lookup[dvd]:] + ")" + + return result + if __name__ == "__main__": print Solution().fractionToDecimal(1, 9) print Solution().fractionToDecimal(-50, 8) print Solution().fractionToDecimal(22, 2) - print Solution().fractionToDecimal(-22, -2) \ No newline at end of file + print Solution().fractionToDecimal(-22, -2) diff --git a/Python/freedom-trail.py b/Python/freedom-trail.py new file mode 100644 index 000000000..227b48c74 --- /dev/null +++ b/Python/freedom-trail.py @@ -0,0 +1,61 @@ +# Time: O(k) ~ O(k * r^2) +# Space: O(r) + +# In the video game Fallout 4, the quest "Road to Freedom" +# requires players to reach a metal dial called the "Freedom Trail Ring", +# and use the dial to spell a specific keyword in order to open the door. +# +# Given a string ring, which represents the code engraved on the outer ring +# and another string key, which represents the keyword needs to be spelled. +# You need to find the minimum number of steps in order to spell all the characters in the keyword. +# +# Initially, the first character of the ring is aligned at 12:00 direction. +# You need to spell all the characters in the string key one by one +# by rotating the ring clockwise or anticlockwise to make each character of +# the string key aligned at 12:00 direction and then by pressing the center button. +# At the stage of rotating the ring to spell the key character key[i]: +# You can rotate the ring clockwise or anticlockwise one place, which counts as 1 step. +# The final purpose of the rotation is to align one of the string ring's +# characters at the 12:00 direction, where this character must equal to the character key[i]. +# If the character key[i] has been aligned at the 12:00 direction, +# you need to press the center button to spell, which also counts as 1 step. +# After the pressing, you could begin to spell the next character in the key (next stage), +# otherwise, you've finished all the spelling. +# Example: +# +# Input: ring = "godding", key = "gd" +# Output: 4 +# Explanation: +# For the first key character 'g', since it is already in place, we just need 1 step to spell this character. +# For the second key character 'd', +# we need to rotate the ring "godding" anticlockwise by two steps to make it become "ddinggo". +# Also, we need 1 more step for spelling. +# So the final output is 4. +# Note: +# Length of both ring and key will be in range 1 to 100. +# There are only lowercase letters in both strings and might be some duplcate characters in both strings. +# It's guaranteed that string key could always be spelled by rotating the string ring. + +class Solution(object): + def findRotateSteps(self, ring, key): + """ + :type ring: str + :type key: str + :rtype: int + """ + lookup = collections.defaultdict(list) + for i in xrange(len(ring)): + lookup[ring[i]].append(i) + + dp = [[0] * len(ring) for _ in xrange(2)] + prev = [0] + for i in xrange(1, len(key)+1): + dp[i%2] = [float("inf")] * len(ring) + for j in lookup[key[i-1]]: + for k in prev: + dp[i%2][j] = min(dp[i%2][j], + min((k+len(ring)-j) % len(ring), \ + (j+len(ring)-k) % len(ring)) + \ + dp[(i-1) % 2][k]) + prev = lookup[key[i-1]] + return min(dp[len(key)%2]) + len(key) diff --git a/Python/friend-circles.py b/Python/friend-circles.py new file mode 100644 index 000000000..19ee1f376 --- /dev/null +++ b/Python/friend-circles.py @@ -0,0 +1,66 @@ +# Time: O(n^2) +# Space: O(n) + +# There are N students in a class. Some of them are friends, while some are not. +# Their friendship is transitive in nature. +# For example, if A is a direct friend of B, and B is a direct friend of C, +# then A is an indirect friend of C. +# And we defined a friend circle is a group of students who are direct or indirect friends. +# +# Given a N*N matrix M representing the friend relationship between students in the class. +# If M[i][j] = 1, then the ith and jth students are direct friends with each other, +# otherwise not. And you have to output the total number of friend circles among all the students. +# +# Example 1: +# Input: +# [[1,1,0], +# [1,1,0], +# [0,0,1]] +# Output: 2 +# Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. +# The 2nd student himself is in a friend circle. So return 2. +# +# Example 2: +# Input: +# [[1,1,0], +# [1,1,1], +# [0,1,1]] +# Output: 1 +# Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends, +# so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return 1. +# +# Note: +# N is in range [1,200]. +# M[i][i] = 1 for all students. +# If M[i][j] = 1, then M[j][i] = 1. + +class Solution(object): + def findCircleNum(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + + class UnionFind(object): + def __init__(self, n): + self.set = range(n) + self.count = n + + def find_set(self, x): + if self.set[x] != x: + self.set[x] = self.find_set(self.set[x]) # path compression. + return self.set[x] + + def union_set(self, x, y): + x_root, y_root = map(self.find_set, (x, y)) + if x_root != y_root: + self.set[min(x_root, y_root)] = max(x_root, y_root) + self.count -= 1 + + circles = UnionFind(len(M)) + for i in xrange(len(M)): + for j in xrange(len(M)): + if M[i][j] and i != j: + circles.union_set(i, j) + return circles.count + diff --git a/Python/frog-jump.py b/Python/frog-jump.py new file mode 100644 index 000000000..447071fbe --- /dev/null +++ b/Python/frog-jump.py @@ -0,0 +1,57 @@ +# Time: O(n) ~ O(n^2) +# Space: O(n) + +# A frog is crossing a river. The river is divided into x units and +# at each unit there may or may not exist a stone. +# The frog can jump on a stone, but it must not jump into the water. +# +# Given a list of stones' positions (in units) in sorted ascending order, +# determine if the frog is able to cross the river by landing on the last stone. +# Initially, the frog is on the first stone and assume the first jump must be 1 unit. +# +# If the frog has just jumped k units, then its next jump must be +# either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction. +# +# Note: +# +# The number of stones is >= 2 and is < 1,100. +# Each stone's position will be a non-negative integer < 231. +# The first stone's position is always 0. +# Example 1: +# +# [0,1,3,5,6,8,12,17] +# +# There are a total of 8 stones. +# The first stone at the 0th unit, second stone at the 1st unit, +# third stone at the 3rd unit, and so on... +# The last stone at the 17th unit. +# +# Return true. The frog can jump to the last stone by jumping +# 1 unit to the 2nd stone, then 2 units to the 3rd stone, then +# 2 units to the 4th stone, then 3 units to the 6th stone, +# 4 units to the 7th stone, and 5 units to the 8th stone. +# Example 2: +# +# [0,1,2,3,4,8,9,11] +# +# Return false. There is no way to jump to the last stone as +# the gap between the 5th and 6th stone is too large. + +# DP with hash table +class Solution(object): + def canCross(self, stones): + """ + :type stones: List[int] + :rtype: bool + """ + if stones[1] != 1: + return False + + last_jump_units = {s: set() for s in stones} + last_jump_units[1].add(1) + for s in stones[:-1]: + for j in last_jump_units[s]: + for k in (j-1, j, j+1): + if k > 0 and s+k in last_jump_units: + last_jump_units[s+k].add(k) + return bool(last_jump_units[stones[-1]]) diff --git a/Python/game-of-life.py b/Python/game-of-life.py new file mode 100644 index 000000000..f569bde1f --- /dev/null +++ b/Python/game-of-life.py @@ -0,0 +1,64 @@ +# Time: O(m * n) +# Space: O(1) + +# According to the Wikipedia's article: +# "The Game of Life, also known simply as Life, +# is a cellular automaton devised by the British +# mathematician John Horton Conway in 1970." +# +# Given a board with m by n cells, each cell has +# an initial state live (1) or dead (0). +# Each cell interacts with its eight neighbors +# (horizontal, vertical, diagonal) +# using the following four rules +# (taken from the above Wikipedia article): +# +# - Any live cell with fewer than two live neighbors dies, +# as if caused by under-population. +# - Any live cell with two or three live neighbors lives +# on to the next generation. +# - Any live cell with more than three live neighbors dies, +# as if by over-population.. +# - Any dead cell with exactly three live neighbors +# becomes a live cell, as if by reproduction. +# +# Write a function to compute the next state +# (after one update) of the board given its current state. +# +# Follow up: +# - Could you solve it in-place? Remember that the board needs +# to be updated at the same time: You cannot update some cells +# first and then use their updated values to update other cells. +# - In this question, we represent the board using a 2D array. +# In principle, the board is infinite, which would cause problems +# when the active area encroaches the border of the array. +# How would you address these problems? +# + +class Solution(object): + def gameOfLife(self, board): + """ + :type board: List[List[int]] + :rtype: void Do not return anything, modify board in-place instead. + """ + m = len(board) + n = len(board[0]) if m else 0 + for i in xrange(m): + for j in xrange(n): + count = 0 + ## Count live cells in 3x3 block. + for I in xrange(max(i-1, 0), min(i+2, m)): + for J in xrange(max(j-1, 0), min(j+2, n)): + count += board[I][J] & 1 + + # if (count == 4 && board[i][j]) means: + # Any live cell with three live neighbors lives. + # if (count == 3) means: + # Any live cell with two live neighbors. + # Any dead cell with exactly three live neighbors lives. + if (count == 4 and board[i][j]) or count == 3: + board[i][j] |= 2 # Mark as live. + + for i in xrange(m): + for j in xrange(n): + board[i][j] >>= 1 # Update to the next state. diff --git a/Python/generalized-abbreviation.py b/Python/generalized-abbreviation.py new file mode 100644 index 000000000..850259e04 --- /dev/null +++ b/Python/generalized-abbreviation.py @@ -0,0 +1,26 @@ +# Time: O(n * 2^n) +# Space: O(n) + +class Solution(object): + def generateAbbreviations(self, word): + """ + :type word: str + :rtype: List[str] + """ + def generateAbbreviationsHelper(word, i, cur, res): + if i == len(word): + res.append("".join(cur)) + return + cur.append(word[i]) + generateAbbreviationsHelper(word, i + 1, cur, res) + cur.pop() + if not cur or not cur[-1][-1].isdigit(): + for l in xrange(1, len(word) - i + 1): + cur.append(str(l)) + generateAbbreviationsHelper(word, i + l, cur, res) + cur.pop() + + res, cur = [], [] + generateAbbreviationsHelper(word, 0, cur, res) + return res + diff --git a/Python/graph-valid-tree.py b/Python/graph-valid-tree.py new file mode 100644 index 000000000..54408e956 --- /dev/null +++ b/Python/graph-valid-tree.py @@ -0,0 +1,71 @@ +# Time: O(|V| + |E|) +# Space: O(|V| + |E|) + +# BFS solution. Same complexity but faster version. +class Solution: + # @param {integer} n + # @param {integer[][]} edges + # @return {boolean} + def validTree(self, n, edges): + if len(edges) != n - 1: # Check number of edges. + return False + elif n == 1: + return True + + # A structure to track each node's [visited_from, neighbors] + visited_from = [-1] * n + neighbors = collections.defaultdict(list) + for u, v in edges: + neighbors[u].append(v) + neighbors[v].append(u) + + if len(neighbors) != n: # Check number of nodes. + return False + + # BFS to check whether the graph is valid tree. + visited = {} + q = collections.deque([0]) + while q: + i = q.popleft() + visited[i] = True + for node in neighbors[i]: + if node != visited_from[i]: + if node in visited: + return False + else: + visited[node] = True + visited_from[node] = i + q.append(node) + return len(visited) == n + + +# Time: O(|V| + |E|) +# Space: O(|V| + |E|) +# BFS solution. +class Solution2: + # @param {integer} n + # @param {integer[][]} edges + # @return {boolean} + def validTree(self, n, edges): + # A structure to track each node's [visited_from, neighbors] + visited_from = [-1] * n + neighbors = collections.defaultdict(list) + for u, v in edges: + neighbors[u].append(v) + neighbors[v].append(u) + + # BFS to check whether the graph is valid tree. + visited = {} + q = collections.deque([0]) + while q: + i = q.popleft() + visited[i] = True + for node in neighbors[i]: + if node != visited_from[i]: + if node in visited: + return False + else: + visited[node] = True + visited_from[node] = i + q.append(node) + return len(visited) == n diff --git a/Python/gray-code.py b/Python/gray-code.py index 2bad42513..415e0f752 100644 --- a/Python/gray-code.py +++ b/Python/gray-code.py @@ -1,6 +1,6 @@ # Time: O(2^n) # Space: O(1) -# + # The gray code is a binary numeral system where two successive values differ in only one bit. # # Given a non-negative integer n representing the total number of bits in the code, @@ -15,26 +15,36 @@ # Note: # For a given n, a gray code sequence is not uniquely defined. # -# For example, [0,2,3,1] is also a valid gray code sequence according to the above definition. +# For example, [0,2,3,1] is also a valid gray code sequence according +# to the above definition. # -# For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that. +# For now, the judge is able to judge based on one instance of gray code +# sequence. Sorry about that. -class Solution: - # @return a list of integers +class Solution(object): def grayCode(self, n): + """ + :type n: int + :rtype: List[int] + """ result = [0] - for i in xrange(0, n): + for i in xrange(n): for n in reversed(result): result.append(1 << i | n) return result -# proof of closed form formula could be found here: + +# Proof of closed form formula could be found here: # http://math.stackexchange.com/questions/425894/proof-of-closed-form-formula-to-convert-a-binary-number-to-its-gray-code -class Solution2: - # @return a list of integers +class Solution2(object): def grayCode(self, n): + """ + :type n: int + :rtype: List[int] + """ return [i >> 1 ^ i for i in xrange(1 << n)] + if __name__ == "__main__": print Solution().grayCode(0) print Solution().grayCode(2) diff --git a/Python/group-shifted-strings.py b/Python/group-shifted-strings.py new file mode 100644 index 000000000..53259c496 --- /dev/null +++ b/Python/group-shifted-strings.py @@ -0,0 +1,26 @@ +# Time: O(nlogn) +# Space: O(n) + +class Solution: + # @param {string[]} strings + # @return {string[][]} + def groupStrings(self, strings): + groups = collections.defaultdict(list) + for s in strings: # Grouping. + groups[self.hashStr(s)].append(s) + + result = [] + for key, val in groups.iteritems(): + result.append(sorted(val)) + + return result + + def hashStr(self, s): + base = ord(s[0]) + hashcode = "" + for i in xrange(len(s)): + if ord(s[i]) - base >= 0: + hashcode += unichr(ord('a') + ord(s[i]) - base) + else: + hashcode += unichr(ord('a') + ord(s[i]) - base + 26) + return hashcode diff --git a/Python/guess-number-higher-or-lower-ii.py b/Python/guess-number-higher-or-lower-ii.py new file mode 100644 index 000000000..48e7139a8 --- /dev/null +++ b/Python/guess-number-higher-or-lower-ii.py @@ -0,0 +1,49 @@ +# Time: O(n^2) +# Space: O(n^2) + +# We are playing the Guess Game. The game is as follows: +# +# I pick a number from 1 to n. You have to guess which number I picked. +# +# Every time you guess wrong, I'll tell you whether the number I picked is higher or lower. +# +# However, when you guess a particular number x, and you guess wrong, +# you pay $x. You win the game when you guess the number I picked. +# +# Example: +# +# n = 10, I pick 8. +# +# First round: You guess 5, I tell you that it's higher. You pay $5. +# Second round: You guess 7, I tell you that it's higher. You pay $7. +# Third round: You guess 9, I tell you that it's lower. You pay $9. +# +# Game over. 8 is the number I picked. +# +# You end up paying $5 + $7 + $9 = $21. +# Given a particular n >= 1, find out how much money you need to have to guarantee a win. +# +# Hint: +# +# The best strategy to play the game is to minimize the maximum loss +# you could possibly face. Another strategy is to minimize the expected loss. +# Here, we are interested in the first scenario. +# Take a small example (n = 3). What do you end up paying in the worst case? +# Check out this article if you're still stuck. +# The purely recursive implementation of minimax would be worthless +# for even a small n. You MUST use dynamic programming. +# As a follow-up, how would you modify your code to solve the problem of +# minimizing the expected loss, instead of the worst-case loss? + +class Solution(object): + def getMoneyAmount(self, n): + """ + :type n: int + :rtype: int + """ + pay = [[0] * n for _ in xrange(n+1)] + for i in reversed(xrange(n)): + for j in xrange(i+1, n): + pay[i][j] = min(k+1 + max(pay[i][k-1], pay[k+1][j]) \ + for k in xrange(i, j+1)) + return pay[0][n-1] diff --git a/Python/guess-number-higher-or-lower.py b/Python/guess-number-higher-or-lower.py new file mode 100644 index 000000000..14f6bb46a --- /dev/null +++ b/Python/guess-number-higher-or-lower.py @@ -0,0 +1,32 @@ +# Time: O(logn) +# Space: O(1) + +# Given an array nums containing n + 1 integers where each integer is +# between 1 and n (inclusive), prove that at least one duplicate number +# must exist. Assume that there is only one duplicate number, find the duplicate one. +# +# Note: +# You must not modify the array (assume the array is read only). +# You must use only constant, O(1) extra space. +# Your runtime complexity should be less than O(n2). +# There is only one duplicate number in the array, but it could be repeated more than once. + +# The guess API is already defined for you. +# @param num, your guess +# @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 +# def guess(num): + +class Solution(object): + def guessNumber(self, n): + """ + :type n: int + :rtype: int + """ + left, right = 1, n + while left <= right: + mid = left + (right - left) / 2 + if guess(mid) <= 0: + right = mid - 1 + else: + left = mid + 1 + return left diff --git a/Python/h-index-ii.py b/Python/h-index-ii.py new file mode 100644 index 000000000..c20392b38 --- /dev/null +++ b/Python/h-index-ii.py @@ -0,0 +1,26 @@ +# Time: O(logn) +# Space: O(1) +# +# Follow up for H-Index: What if the citations array is sorted in +# ascending order? Could you optimize your algorithm? +# +# Hint: +# +# Expected runtime complexity is in O(log n) and the input is sorted. +# + +class Solution(object): + def hIndex(self, citations): + """ + :type citations: List[int] + :rtype: int + """ + n = len(citations) + left, right = 0, n - 1 + while left <= right: + mid = (left + right) / 2 + if citations[mid] >= n - mid: + right = mid - 1 + else: + left = mid + 1 + return n - left diff --git a/Python/h-index.py b/Python/h-index.py new file mode 100644 index 000000000..4ad07afdb --- /dev/null +++ b/Python/h-index.py @@ -0,0 +1,70 @@ +# Time: O(n) +# Space: O(n) + +# Given an array of citations (each citation is a non-negative integer) +# of a researcher, write a function to compute the researcher's h-index. +# +# According to the definition of h-index on Wikipedia: +# "A scientist has index h if h of his/her N papers have +# at least h citations each, and the other N − h papers have +# no more than h citations each." +# +# For example, given citations = [3, 0, 6, 1, 5], +# which means the researcher has 5 papers in total +# and each of them had received 3, 0, 6, 1, 5 citations respectively. +# Since the researcher has 3 papers with at least 3 citations each and +# the remaining two with no more than 3 citations each, his h-index is 3. +# +# Note: If there are several possible values for h, the maximum one is taken as the h-index. +# + +# Counting sort. +class Solution(object): + def hIndex(self, citations): + """ + :type citations: List[int] + :rtype: int + """ + n = len(citations); + count = [0] * (n + 1) + for x in citations: + # Put all x >= n in the same bucket. + if x >= n: + count[n] += 1 + else: + count[x] += 1 + + h = 0 + for i in reversed(xrange(0, n + 1)): + h += count[i] + if h >= i: + return i + return h + +# Time: O(nlogn) +# Space: O(1) +class Solution2(object): + def hIndex(self, citations): + """ + :type citations: List[int] + :rtype: int + """ + citations.sort(reverse=True) + h = 0 + for x in citations: + if x >= h + 1: + h += 1 + else: + break + return h + +# Time: O(nlogn) +# Space: O(n) +class Solution3(object): + def hIndex(self, citations): + """ + :type citations: List[int] + :rtype: int + """ + return sum(x >= i + 1 for i, x in enumerate(sorted(citations, reverse=True))) + diff --git a/Python/hamming-distance.py b/Python/hamming-distance.py new file mode 100644 index 000000000..31d0c6ce7 --- /dev/null +++ b/Python/hamming-distance.py @@ -0,0 +1,45 @@ +# Time: O(1) +# Space: O(1) + +# The Hamming distance between two integers is the number of positions +# at which the corresponding bits are different. +# +# Given two integers x and y, calculate the Hamming distance. +# +# Note: +# 0 ≤ x, y < 231. +# +# Example: +# +# Input: x = 1, y = 4 +# +# Output: 2 +# +# Explanation: +# 1 (0 0 0 1) +# 4 (0 1 0 0) +# ↑ ↑ +# +# The above arrows point to positions where the corresponding bits are different. + +class Solution(object): + def hammingDistance(self, x, y): + """ + :type x: int + :type y: int + :rtype: int + """ + distance = 0 + z = x ^ y + while z: + distance += 1 + z &= z - 1 + return distance + + def hammingDistance2(self, x, y): + """ + :type x: int + :type y: int + :rtype: int + """ + return bin(x ^ y).count('1') diff --git a/Python/happy-number.py b/Python/happy-number.py new file mode 100644 index 000000000..7ea4a5675 --- /dev/null +++ b/Python/happy-number.py @@ -0,0 +1,34 @@ +# Time: O(k), where k is the steps to be happy number +# Space: O(k) +# +# Write an algorithm to determine if a number is "happy". +# +# A happy number is a number defined by the following process: +# Starting with any positive integer, replace the number by the sum +# of the squares of its digits, and repeat the process until +# the number equals 1 (where it will stay), or it loops endlessly +# in a cycle which does not include 1. Those numbers for which +# this process ends in 1 are happy numbers. +# +# Example: 19 is a happy number +# +# 1^2 + 9^2 = 82 +# 8^2 + 2^2 = 68 +# 6^2 + 8^2 = 100 +# 1^2 + 0^2 + 0^2 = 1 +# +class Solution: + # @param {integer} n + # @return {boolean} + def isHappy(self, n): + lookup = {} + while n != 1 and n not in lookup: + lookup[n] = True + n = self.nextNumber(n) + return n == 1 + + def nextNumber(self, n): + new = 0 + for char in str(n): + new += int(char)**2 + return new diff --git a/Python/heaters.py b/Python/heaters.py new file mode 100644 index 000000000..65de830f7 --- /dev/null +++ b/Python/heaters.py @@ -0,0 +1,48 @@ +# Time: O((m + n) * logn), m is the number of the houses, n is the number of the heaters. +# Space: O(1) + +# Winter is coming! Your first job during the contest is to +# design a standard heater with fixed warm radius to warm all the houses. +# +# Now, you are given positions of houses and heaters on a horizontal line, +# find out minimum radius of heaters so that all houses could be covered by those heaters. +# +# So, your input will be the positions of houses and heaters seperately, +# and your expected output will be the minimum radius standard of heaters. +# +# Note: +# Numbers of houses and heaters you are given are non-negative and will not exceed 25000. +# Positions of houses and heaters you are given are non-negative and will not exceed 10^9. +# As long as a house is in the heaters' warm radius range, it can be warmed. +# All the heaters follow your radius standard and the warm radius will the same. +# Example 1: +# Input: [1,2,3],[2] +# Output: 1 +# Explanation: The only heater was placed in the position 2, and if we use the radius 1 standard, +# then all the houses can be warmed. +# Example 2: +# Input: [1,2,3,4],[1,4] +# Output: 1 +# Explanation: The two heater was placed in the position 1 and 4. We need to use radius 1 standard, +# then all the houses can be warmed. + +class Solution(object): + def findRadius(self, houses, heaters): + """ + :type houses: List[int] + :type heaters: List[int] + :rtype: int + """ + heaters.sort() + min_radius = 0 + for house in houses: + equal_or_larger = bisect.bisect_left(heaters, house) + curr_radius = float("inf") + if equal_or_larger != len(heaters): + curr_radius = heaters[equal_or_larger] - house + if equal_or_larger != 0: + smaller = equal_or_larger-1 + curr_radius = min(curr_radius, house - heaters[smaller]) + min_radius = max(min_radius, curr_radius) + return min_radius + diff --git a/Python/house-robber-ii.py b/Python/house-robber-ii.py new file mode 100644 index 000000000..554ed4828 --- /dev/null +++ b/Python/house-robber-ii.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(1) +# +# Note: This is an extension of House Robber. +# +# After robbing those houses on that street, the thief has found himself a new place +# for his thievery so that he will not get too much attention. This time, all houses +# at this place are arranged in a circle. That means the first house is the neighbor +# of the last one. Meanwhile, the security system for these houses remain the same as +# for those in the previous street. +# +# Given a list of non-negative integers representing the amount of money of each house, +# determine the maximum amount of money you can rob tonight without alerting the police. +# +class Solution: + # @param {integer[]} nums + # @return {integer} + def rob(self, nums): + if len(nums) == 0: + return 0 + + if len(nums) == 1: + return nums[0] + + return max(self.robRange(nums, 0, len(nums) - 1),\ + self.robRange(nums, 1, len(nums))) + + def robRange(self, nums, start, end): + num_i, num_i_1 = nums[start], 0 + for i in xrange(start + 1, end): + num_i_1, num_i_2 = num_i, num_i_1 + num_i = max(nums[i] + num_i_2, num_i_1); + + return num_i + +if __name__ == '__main__': + print Solution().rob([8,4,8,5,9,6,5,4,4,10]) diff --git a/Python/house-robber-iii.py b/Python/house-robber-iii.py new file mode 100644 index 000000000..06d4ea317 --- /dev/null +++ b/Python/house-robber-iii.py @@ -0,0 +1,49 @@ +# Time: O(n) +# Space: O(h) + +# The thief has found himself a new place for his thievery again. +# There is only one entrance to this area, called the "root." +# Besides the root, each house has one and only one parent house. +# After a tour, the smart thief realized that "all houses in this +# place forms a binary tree". It will automatically contact the +# police if two directly-linked houses were broken into on the +# same night. +# +# Determine the maximum amount of money the thief can rob tonight +# without alerting the police. +# +# Example 1: +# 3 +# / \ +# 2 3 +# \ \ +# 3 1 +# Maximum amount of money the thief can rob = 3 + 3 + 1 = 7. +# Example 2: +# 3 +# / \ +# 4 5 +# / \ \ +# 1 3 1 +# Maximum amount of money the thief can rob = 4 + 5 = 9. +# +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def rob(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def robHelper(root): + if not root: + return (0, 0) + left, right = robHelper(root.left), robHelper(root.right) + return (root.val + left[1] + right[1], max(left) + max(right)) + + return max(robHelper(root)) diff --git a/Python/house-robber.py b/Python/house-robber.py new file mode 100644 index 000000000..3efd6e8a0 --- /dev/null +++ b/Python/house-robber.py @@ -0,0 +1,41 @@ +# Time: O(n) +# Space: O(1) +# +# You are a professional robber planning to rob houses along a street. +# Each house has a certain amount of money stashed, the only constraint stopping you +# from robbing each of them is that adjacent houses have security system connected +# and it will automatically contact the police if two adjacent houses were broken into on the same night. +# +# Given a list of non-negative integers representing the amount of money of each house, +# determine the maximum amount of money you can rob tonight without alerting the police. +# +class Solution: + # @param num, a list of integer + # @return an integer + def rob(self, num): + if len(num) == 0: + return 0 + + if len(num) == 1: + return num[0] + + num_i, num_i_1 = max(num[1], num[0]), num[0] + for i in xrange(2, len(num)): + num_i_1, num_i_2 = num_i, num_i_1 + num_i = max(num[i] + num_i_2, num_i_1); + + return num_i + + def rob2(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + last, now = 0, 0 + for i in nums: + last, now = now, max(last + i, now) + return now + + +if __name__ == '__main__': + print Solution().rob([8,4,8,5,9,6,5,4,4,10]) diff --git a/Python/image-smoother.py b/Python/image-smoother.py new file mode 100644 index 000000000..44e03c24e --- /dev/null +++ b/Python/image-smoother.py @@ -0,0 +1,49 @@ +# Time: O(m * n) +# Space: O(1) + +# Given a 2D integer matrix M representing the gray scale of an image, +# you need to design a smoother to make the gray scale of each cell becomes +# the average gray scale (rounding down) of all the 8 surrounding cells and itself. +# If a cell has less than 8 surrounding cells, then use as many as you can. +# +# Example 1: +# Input: +# [[1,1,1], +# [1,0,1], +# [1,1,1]] +# Output: +# [[0, 0, 0], +# [0, 0, 0], +# [0, 0, 0]] +# Explanation: +# For the point (0,0), (0,2), (2,0), (2,2): floor(3/4) = floor(0.75) = 0 +# For the point (0,1), (1,0), (1,2), (2,1): floor(5/6) = floor(0.83333333) = 0 +# For the point (1,1): floor(8/9) = floor(0.88888889) = 0 +# Note: +# The value in the given matrix is in the range of [0, 255]. +# The length and width of the given matrix are in the range of [1, 150]. + +class Solution(object): + def imageSmoother(self, M): + """ + :type M: List[List[int]] + :rtype: List[List[int]] + """ + def getGray(M, i, j): + directions = [[-1, -1], [0, -1], [1, -1], \ + [-1, 0], [0, 0], [1, 0], \ + [-1, 1], [0, 1], [1, 1]] + + total, count = 0, 0.0 + for direction in directions: + ii, jj = i + direction[0], j + direction[1] + if 0 <= ii < len(M) and 0 <= jj < len(M[0]): + total += M[ii][jj] + count += 1.0 + return int(total / count) + + result = [[0 for _ in xrange(len(M[0]))] for _ in xrange(len(M))] + for i in xrange(len(M)): + for j in xrange(len(M[0])): + result[i][j] = getGray(M, i, j); + return result diff --git a/Python/implement-magic-dictionary.py b/Python/implement-magic-dictionary.py new file mode 100644 index 000000000..d7785e595 --- /dev/null +++ b/Python/implement-magic-dictionary.py @@ -0,0 +1,72 @@ +# Time: O(n), n is the length of the word +# Space: O(d) + +# Implement a magic directory with buildDict, and search methods. +# +# For the method buildDict, you'll be given a list of non-repetitive words to build a dictionary. +# +# For the method search, you'll be given a word, and judge whether +# if you modify exactly one character into another character in this word, +# the modified word is in the dictionary you just built. +# +# Example 1: +# Input: buildDict(["hello", "leetcode"]), Output: Null +# Input: search("hello"), Output: False +# Input: search("hhllo"), Output: True +# Input: search("hell"), Output: False +# Input: search("leetcoded"), Output: False +# Note: +# You may assume that all the inputs are consist of lowercase letters a-z. +# For contest purpose, the test data is rather small by now. +# You could think about highly efficient algorithm after the contest. +# Please remember to RESET your class variables declared in class MagicDictionary, +# as static/class variables are persisted across multiple test cases. Please see here for more details. + +class MagicDictionary(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + _trie = lambda: collections.defaultdict(_trie) + self.trie = _trie() + + + def buildDict(self, dictionary): + """ + Build a dictionary through a list of words + :type dictionary: List[str] + :rtype: void + """ + for word in dictionary: + reduce(dict.__getitem__, word, self.trie).setdefault("_end") + + + def search(self, word): + """ + Returns if there is any word in the trie that equals to the given word after modifying exactly one character + :type word: str + :rtype: bool + """ + def find(word, curr, i, mistakeAllowed): + if i == len(word): + return "_end" in curr and not mistakeAllowed + + if word[i] not in curr: + return any(find(word, curr[c], i+1, False) for c in curr if c != "_end") \ + if mistakeAllowed else False + + if mistakeAllowed: + return find(word, curr[word[i]], i+1, True) or \ + any(find(word, curr[c], i+1, False) \ + for c in curr if c not in ("_end", word[i])) + return find(word, curr[word[i]], i+1, False) + + return find(word, self.trie, 0, True) + + + +# Your MagicDictionary object will be instantiated and called as such: +# obj = MagicDictionary() +# obj.buildDict(dict) +# param_2 = obj.search(word) diff --git a/Python/implement-queue-using-stacks.py b/Python/implement-queue-using-stacks.py new file mode 100644 index 000000000..1cfeb014d --- /dev/null +++ b/Python/implement-queue-using-stacks.py @@ -0,0 +1,45 @@ +# Time: O(1), amortized +# Space: O(n) +# +# Implement the following operations of a queue using stacks. +# +# push(x) -- Push element x to the back of queue. +# pop() -- Removes the element from in front of queue. +# peek() -- Get the front element. +# empty() -- Return whether the queue is empty. +# +# Notes: +# You must use only standard operations of a stack +# -- which means only push to top, peek/pop from top, size, and is empty operations are valid. +# Depending on your language, stack may not be supported natively. +# You may simulate a stack by using a list or deque (double-ended queue), +# as long as you use only standard operations of a stack. +# You may assume that all operations are valid +# (for example, no pop or peek operations will be called on an empty queue). +# + +class Queue: + # initialize your data structure here. + def __init__(self): + self.A, self.B = [], [] + + # @param x, an integer + # @return nothing + def push(self, x): + self.A.append(x) + + # @return nothing + def pop(self): + self.peek() + self.B.pop() + + # @return an integer + def peek(self): + if not self.B: + while self.A: + self.B.append(self.A.pop()) + return self.B[-1] + + # @return an boolean + def empty(self): + return not self.A and not self.B diff --git a/Python/implement-stack-using-queues.py b/Python/implement-stack-using-queues.py new file mode 100644 index 000000000..05ec228d6 --- /dev/null +++ b/Python/implement-stack-using-queues.py @@ -0,0 +1,93 @@ +# Time: push: O(n), pop: O(1), top: O(1) +# Space: O(n) +# +# Implement the following operations of a stack using queues. +# +# push(x) -- Push element x onto stack. +# pop() -- Removes the element on top of the stack. +# top() -- Get the top element. +# empty() -- Return whether the stack is empty. +# Notes: +# You must use only standard operations of a queue -- which +# means only push to back, peek/pop from front, size, and is +# empty operations are valid. +# Depending on your language, queue may not be supported natively. +# You may simulate a queue by using a list or deque (double-ended +# queue), as long as you use only standard operations of a queue. +# You may assume that all operations are valid (for example, no pop +# or top operations will be called on an empty stack). +# + +class Queue: + def __init__(self): + self.data = collections.deque() + + def push(self, x): + self.data.append(x) + + def peek(self): + return self.data[0] + + def pop(self): + return self.data.popleft() + + def size(self): + return len(self.data) + + def empty(self): + return len(self.data) == 0 + + +class Stack: + # initialize your data structure here. + def __init__(self): + self.q_ = Queue() + + # @param x, an integer + # @return nothing + def push(self, x): + self.q_.push(x) + for _ in xrange(self.q_.size() - 1): + self.q_.push(self.q_.pop()) + + # @return nothing + def pop(self): + self.q_.pop() + + # @return an integer + def top(self): + return self.q_.peek() + + # @return an boolean + def empty(self): + return self.q_.empty() + + +# Time: push: O(1), pop: O(n), top: O(1) +# Space: O(n) +class Stack2: + # initialize your data structure here. + def __init__(self): + self.q_ = Queue() + self.top_ = None + + # @param x, an integer + # @return nothing + def push(self, x): + self.q_.push(x) + self.top_ = x + + # @return nothing + def pop(self): + for _ in xrange(self.q_.size() - 1): + self.top_ = self.q_.pop() + self.q_.push(self.top_) + self.q_.pop() + + # @return an integer + def top(self): + return self.top_ + + # @return an boolean + def empty(self): + return self.q_.empty() diff --git a/Python/implement-strstr.py b/Python/implement-strstr.py index 543835dd4..6af9a5ec2 100644 --- a/Python/implement-strstr.py +++ b/Python/implement-strstr.py @@ -1,5 +1,5 @@ -# Time: O(n + m) -# Space: O(m) +# Time: O(n + k) +# Space: O(k) # # Implement strStr(). # @@ -9,22 +9,17 @@ # Wiki of KMP algorithm: # http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm -class Solution: - # @param haystack, a string - # @param needle, a string - # @return a string or None +class Solution(object): def strStr(self, haystack, needle): - if len(haystack) < len(needle): - return None - - if len(needle) == 0: - return haystack - - i = self.KMP(haystack, needle) - if i > -1: - return haystack[i:] - else: - return None + """ + :type haystack: str + :type needle: str + :rtype: int + """ + if not needle: + return 0 + + return self.KMP(haystack, needle) def KMP(self, text, pattern): prefix = self.getPrefix(pattern) @@ -40,7 +35,7 @@ def KMP(self, text, pattern): def getPrefix(self, pattern): prefix = [-1] * len(pattern) - j = - 1 + j = -1 for i in xrange(1, len(pattern)): while j > -1 and pattern[j + 1] != pattern[i]: j = prefix[j] @@ -48,18 +43,31 @@ def getPrefix(self, pattern): j += 1 prefix[i] = j return prefix + + def strStr2(self, haystack, needle): + """ + :type haystack: str + :type needle: str + :rtype: int + """ + try: + return haystack.index(needle) + except: + return -1 -# Time: (n * m) -# Space: (1) -class Solution2: - # @param haystack, a string - # @param needle, a string - # @return a string or None +# Time: O(n * k) +# Space: O(k) +class Solution2(object): def strStr(self, haystack, needle): + """ + :type haystack: str + :type needle: str + :rtype: int + """ for i in xrange(len(haystack) - len(needle) + 1): if haystack[i : i + len(needle)] == needle: - return haystack[i:] - return None + return i + return -1 if __name__ == "__main__": print Solution().strStr("a", "") diff --git a/Python/implement-trie-prefix-tree.py b/Python/implement-trie-prefix-tree.py new file mode 100644 index 000000000..0301555ad --- /dev/null +++ b/Python/implement-trie-prefix-tree.py @@ -0,0 +1,61 @@ +# Time: O(n), per operation +# Space: O(1) +# +# Implement a trie with insert, search, and startsWith methods. +# +# Note: +# You may assume that all inputs are consist of lowercase letters a-z. +# + +class TrieNode: + # Initialize your data structure here. + def __init__(self): + self.is_string = False + self.leaves = {} + + +class Trie: + + def __init__(self): + self.root = TrieNode() + + # @param {string} word + # @return {void} + # Inserts a word into the trie. + def insert(self, word): + cur = self.root + for c in word: + if not c in cur.leaves: + cur.leaves[c] = TrieNode() + cur = cur.leaves[c] + cur.is_string = True + + # @param {string} word + # @return {boolean} + # Returns if the word is in the trie. + def search(self, word): + node = self.childSearch(word) + if node: + return node.is_string + return False + + # @param {string} prefix + # @return {boolean} + # Returns if there is any word in the trie + # that starts with the given prefix. + def startsWith(self, prefix): + return self.childSearch(prefix) is not None + + def childSearch(self, word): + cur = self.root + for c in word: + if c in cur.leaves: + cur = cur.leaves[c] + else: + return None + return cur + +# Your Trie object will be instantiated and called as such: +# trie = Trie() +# trie.insert("somestring") +# trie.search("key") diff --git a/Python/increasing-subsequences.py b/Python/increasing-subsequences.py new file mode 100644 index 000000000..e246be299 --- /dev/null +++ b/Python/increasing-subsequences.py @@ -0,0 +1,38 @@ +# Time: O(n * 2^n) +# Space: O(n^2) + +# Given an integer array, your task is +# to find all the different possible increasing +# subsequences of the given array, +# and the length of an increasing subsequence should be at least 2 . +# +# Example: +# Input: [4, 6, 7, 7] +# Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]] +# Note: +# The length of the given array will not exceed 15. +# The range of integer in the given array is [-100,100]. +# The given array may contain duplicates, +# and two equal integers should also be considered as a special case of increasing sequence. + +class Solution(object): + def findSubsequences(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + def findSubsequencesHelper(nums, pos, seq, result): + if len(seq) >= 2: + result.append(list(seq)) + lookup = set() + for i in xrange(pos, len(nums)): + if (not seq or nums[i] >= seq[-1]) and \ + nums[i] not in lookup: + lookup.add(nums[i]) + seq.append(nums[i]) + findSubsequencesHelper(nums, i+1, seq, result) + seq.pop() + + result, seq = [], [] + findSubsequencesHelper(nums, 0, seq, result) + return result diff --git a/Python/increasing-triplet-subsequence.py b/Python/increasing-triplet-subsequence.py new file mode 100644 index 000000000..da1e27ccb --- /dev/null +++ b/Python/increasing-triplet-subsequence.py @@ -0,0 +1,55 @@ +# Time: O(n) +# Space: O(1) + +# Given an unsorted array return whether an increasing +# subsequence of length 3 exists or not in the array. + +# Formally the function should: +# Return true if there exists i, j, k +# such that arr[i] < arr[j] < arr[k] +# given 0 <= i < j < k <= n-1 else return false. +# Your algorithm should run in O(n) time complexity and O(1) space complexity. + +# Examples: +# Given [1, 2, 3, 4, 5], +# return true. + +# Given [5, 4, 3, 2, 1], +# return false. + + +class Solution(object): + def increasingTriplet(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + min_num, a, b = float("inf"), float("inf"), float("inf") + for c in nums: + if min_num >= c: + min_num = c + elif b >= c: + a, b = min_num, c + else: # a < b < c + return True + return False + +# Time: O(n * logk) +# Space: O(k) +# Generalization of k-uplet. +class Solution_Generalization(object): + def increasingTriplet(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + def increasingKUplet(nums, k): + inc = [float('inf')] * (k - 1) + for num in nums: + i = bisect.bisect_left(inc, num) + if i >= k - 1: + return True + inc[i] = num + return k == 0 + + return increasingKUplet(nums, 3) diff --git a/Python/inorder-successor-in-bst.py b/Python/inorder-successor-in-bst.py new file mode 100644 index 000000000..a3d6ee653 --- /dev/null +++ b/Python/inorder-successor-in-bst.py @@ -0,0 +1,34 @@ +# Time: O(h) +# Space: O(1) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def inorderSuccessor(self, root, p): + """ + :type root: TreeNode + :type p: TreeNode + :rtype: TreeNode + """ + # If it has right subtree. + if p and p.right: + p = p.right + while p.left: + p = p.left + return p + + # Search from root. + successor = None + while root and root != p: + if root.val > p.val: + successor = root + root = root.left + else: + root = root.right + + return successor diff --git a/Python/insert-delete-getrandom-o1-duplicates-allowed.py b/Python/insert-delete-getrandom-o1-duplicates-allowed.py new file mode 100644 index 000000000..3aa6ab1a7 --- /dev/null +++ b/Python/insert-delete-getrandom-o1-duplicates-allowed.py @@ -0,0 +1,93 @@ +# Time: O(1) +# Space: O(n) + +# Design a data structure that supports all following operations in average O(1) time. +# +# Note: Duplicate elements are allowed. +# insert(val): Inserts an item val to the collection. +# remove(val): Removes an item val from the collection if present. +# getRandom: Returns a random element from current collection of elements. +# The probability of each element being returned is linearly related to +# the number of same value the collection contains. +# Example: +# +# // Init an empty collection. +# RandomizedCollection collection = new RandomizedCollection(); +# +# // Inserts 1 to the collection. Returns true as the collection did not contain 1. +# collection.insert(1); +# +# // Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1]. +# collection.insert(1); +# +# // Inserts 2 to the collection, returns true. Collection now contains [1,1,2]. +# collection.insert(2); +# +# // getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3. +# collection.getRandom(); +# +# // Removes 1 from the collection, returns true. Collection now contains [1,2]. +# collection.remove(1); +# +# // getRandom should return 1 and 2 both equally likely. +# collection.getRandom(); + +from random import randint +from collections import defaultdict + +class RandomizedCollection(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.__list = [] + self.__used = defaultdict(list) + + + def insert(self, val): + """ + Inserts a value to the collection. Returns true if the collection did not already contain the specified element. + :type val: int + :rtype: bool + """ + has = val in self.__used + + self.__list += val, + self.__used[val] += len(self.__list)-1, + + return not has + + + def remove(self, val): + """ + Removes a value from the collection. Returns true if the collection contained the specified element. + :type val: int + :rtype: bool + """ + if val not in self.__used: + return False + + self.__used[self.__list[-1]][-1] = self.__used[val][-1] + self.__list[self.__used[val][-1]], self.__list[-1] = self.__list[-1], self.__list[self.__used[val][-1]] + + self.__used[val].pop() + if not self.__used[val]: + self.__used.pop(val) + self.__list.pop() + + return True + + def getRandom(self): + """ + Get a random element from the collection. + :rtype: int + """ + return self.__list[randint(0, len(self.__list)-1)] + + +# Your RandomizedCollection object will be instantiated and called as such: +# obj = RandomizedCollection() +# param_1 = obj.insert(val) +# param_2 = obj.remove(val) +# param_3 = obj.getRandom() diff --git a/Python/insert-delete-getrandom-o1.py b/Python/insert-delete-getrandom-o1.py new file mode 100644 index 000000000..136636091 --- /dev/null +++ b/Python/insert-delete-getrandom-o1.py @@ -0,0 +1,94 @@ +# Time: O(1) +# Space: O(n) + +# Design a data structure that supports all following operations in O(1) time. +# +# insert(val): Inserts an item val to the set if not already present. +# remove(val): Removes an item val from the set if present. +# getRandom: Returns a random element from current set of elements. +# Each element must have the same probability of being returned. +# +# Example: +# +# // Init an empty set. +# RandomizedSet randomSet = new RandomizedSet(); +# +# // Inserts 1 to the set. Returns true as 1 was inserted successfully. +# randomSet.insert(1); +# +# // Returns false as 2 does not exist in the set. +# randomSet.remove(2); +# +# // Inserts 2 to the set, returns true. Set now contains [1,2]. +# randomSet.insert(2); +# +# // getRandom should return either 1 or 2 randomly. +# randomSet.getRandom(); +# +# // Removes 1 from the set, returns true. Set now contains [2]. +# randomSet.remove(1); +# +# // 2 was already in the set, so return false. +# randomSet.insert(2); +# +# // Since 1 is the only number in the set, getRandom always return 1. +# randomSet.getRandom(); + + +from random import randint + +class RandomizedSet(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.__set = [] + self.__used = {} + + + def insert(self, val): + """ + Inserts a value to the set. Returns true if the set did not already contain the specified element. + :type val: int + :rtype: bool + """ + if val in self.__used: + return False + + self.__set += val, + self.__used[val] = len(self.__set)-1 + + return True + + + def remove(self, val): + """ + Removes a value from the set. Returns true if the set contained the specified element. + :type val: int + :rtype: bool + """ + if val not in self.__used: + return False + + self.__used[self.__set[-1]] = self.__used[val] + self.__set[self.__used[val]], self.__set[-1] = self.__set[-1], self.__set[self.__used[val]] + + self.__used.pop(val) + self.__set.pop() + + return True + + def getRandom(self): + """ + Get a random element from the set. + :rtype: int + """ + return self.__set[randint(0, len(self.__set)-1)] + + +# Your RandomizedSet object will be instantiated and called as such: +# obj = RandomizedSet() +# param_1 = obj.insert(val) +# param_2 = obj.remove(val) +# param_3 = obj.getRandom() diff --git a/Python/insert-interval.py b/Python/insert-interval.py index f108a7078..16cf7c0a7 100644 --- a/Python/insert-interval.py +++ b/Python/insert-interval.py @@ -1,8 +1,8 @@ # Time: O(n) # Space: O(1) -# -# Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). -# + +# Given a set of non-overlapping intervals, insert a new interval into the +# intervals (merge if necessary). # You may assume that the intervals were initially sorted according to their start times. # # Example 1: @@ -12,7 +12,6 @@ # Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16]. # # This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10]. -# # Definition for an interval. class Interval: @@ -23,25 +22,27 @@ def __init__(self, s=0, e=0): def __repr__(self): return "[{}, {}]".format(self.start, self.end) -class Solution: - # @param intervals, a list of Intervals - # @param newInterval, a Interval - # @return a list of Interval + +class Solution(object): def insert(self, intervals, newInterval): - return self.merge(intervals + [newInterval]) - - def merge(self, intervals): - if len(intervals) == 0: - return intervals - intervals.sort(key = lambda x: x.start) - result = [intervals[0]] - for i in range(1, len(intervals)): - prev, current = result[-1], intervals[i] - if current.start <= prev.end: - prev.end = max(prev.end, current.end) - else: - result.append(current) + """ + :type intervals: List[Interval] + :type newInterval: Interval + :rtype: List[Interval] + """ + result = [] + i = 0 + while i < len(intervals) and newInterval.start > intervals[i].end: + result += intervals[i], + i += 1 + while i < len(intervals) and newInterval.end >= intervals[i].start: + newInterval = Interval(min(newInterval.start, intervals[i].start), \ + max(newInterval.end, intervals[i].end)) + i += 1 + result += newInterval, + result += intervals[i:] return result + if __name__ == "__main__": - print Solution().insert([Interval(1, 2), Interval(3, 5), Interval(6, 7), Interval(8, 10), Interval(12, 16)], Interval(4, 9)) \ No newline at end of file + print Solution().insert([Interval(1, 2), Interval(3, 5), Interval(6, 7), Interval(8, 10), Interval(12, 16)], Interval(4, 9)) diff --git a/Python/integer-break.py b/Python/integer-break.py new file mode 100644 index 000000000..c2127f3e9 --- /dev/null +++ b/Python/integer-break.py @@ -0,0 +1,77 @@ +# Time: O(logn), pow is O(logn). +# Space: O(1) + +# Given a positive integer n, break it into the sum of +# at least two positive integers and maximize the product +# of those integers. Return the maximum product you can get. +# +# For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, +# return 36 (10 = 3 + 3 + 4). +# +# Note: you may assume that n is not less than 2. +# +# Hint: +# +# There is a simple O(n) solution to this problem. +# You may check the breaking results of n ranging from 7 to 10 +# to discover the regularities. + +class Solution(object): + def integerBreak(self, n): + """ + :type n: int + :rtype: int + """ + if n < 4: + return n - 1 + + # Proof. + # 1. Let n = a1 + a2 + ... + ak, product = a1 * a2 * ... * ak + # - For each ai >= 4, we can always maximize the product by: + # ai <= 2 * (ai - 2) + # - For each aj >= 5, we can always maximize the product by: + # aj <= 3 * (aj - 3) + # + # Conclusion 1: + # - For n >= 4, the max of the product must be in the form of + # 3^a * 2^b, s.t. 3a + 2b = n + # + # 2. To maximize the product = 3^a * 2^b s.t. 3a + 2b = n + # - For each b >= 3, we can always maximize the product by: + # 3^a * 2^b <= 3^(a+2) * 2^(b-3) s.t. 3(a+2) + 2(b-3) = n + # + # Conclusion 2: + # - For n >= 4, the max of the product must be in the form of + # 3^Q * 2^R, 0 <= R < 3 s.t. 3Q + 2R = n + # i.e. + # if n = 3Q + 0, the max of the product = 3^Q * 2^0 + # if n = 3Q + 2, the max of the product = 3^Q * 2^1 + # if n = 3Q + 2*2, the max of the product = 3^Q * 2^2 + + res = 0 + if n % 3 == 0: # n = 3Q + 0, the max is 3^Q * 2^0 + res = 3 ** (n // 3) + elif n % 3 == 2: # n = 3Q + 2, the max is 3^Q * 2^1 + res = 3 ** (n // 3) * 2 + else: # n = 3Q + 4, the max is 3^Q * 2^2 + res = 3 ** (n // 3 - 1) * 4 + return res + + +# Time: O(n) +# Space: O(1) +# DP solution. +class Solution2(object): + def integerBreak(self, n): + """ + :type n: int + :rtype: int + """ + if n < 4: + return n - 1 + + # integerBreak(n) = max(integerBreak(n - 2) * 2, integerBreak(n - 3) * 3) + res = [0, 1, 2, 3] + for i in xrange(4, n + 1): + res[i % 4] = max(res[(i - 2) % 4] * 2, res[(i - 3) % 4] * 3) + return res[n % 4] diff --git a/Python/integer-replacement.py b/Python/integer-replacement.py new file mode 100644 index 000000000..8ec74bf04 --- /dev/null +++ b/Python/integer-replacement.py @@ -0,0 +1,73 @@ +# Time: O(logn) +# Space: O(1) + +# Given a positive integer n and you can do operations as follow: +# +# If n is even, replace n with n/2. +# If n is odd, you can replace n with either n + 1 or n - 1. +# What is the minimum number of replacements needed for n to become 1? +# +# Example 1: +# +# Input: +# 8 +# +# Output: +# 3 +# +# Explanation: +# 8 -> 4 -> 2 -> 1 +# Example 2: +# +# Input: +# 7 +# +# Output: +# 4 +# +# Explanation: +# 7 -> 8 -> 4 -> 2 -> 1 +# or +# 7 -> 6 -> 3 -> 2 -> 1 + +# Iterative solution. +class Solution(object): + def integerReplacement(self, n): + """ + :type n: int + :rtype: int + """ + result = 0 + while n != 1: + b = n & 3 + if n == 3: + n -= 1 + elif b == 3: + n += 1 + elif b == 1: + n -= 1 + else: + n /= 2 + result += 1 + + return result + + +# Time: O(logn) +# Space: O(logn) +# Recursive solution. +class Solution2(object): + def integerReplacement(self, n): + """ + :type n: int + :rtype: int + """ + if n < 4: + return [0, 0, 1, 2][n] + if n % 4 in (0, 2): + return self.integerReplacement(n / 2) + 1 + elif n % 4 == 1: + return self.integerReplacement((n - 1) / 4) + 3 + else: + return self.integerReplacement((n + 1) / 4) + 3 + diff --git a/Python/integer-to-english-words.py b/Python/integer-to-english-words.py new file mode 100644 index 000000000..8525612f5 --- /dev/null +++ b/Python/integer-to-english-words.py @@ -0,0 +1,64 @@ +# Time: O(logn), n is the value of the integer +# Space: O(1) +# +# Convert a non-negative integer to its english words representation. +# Given input is guaranteed to be less than 2^31 - 1. +# +# For example, +# 123 -> "One Hundred Twenty Three" +# 12345 -> "Twelve Thousand Three Hundred Forty Five" +# 1234567 -> "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven" +# +# Hint: +# +# 1. Did you see a pattern in dividing the number into chunk of words? +# For example, 123 and 123000. +# +# 2. Group the number by thousands (3 digits). You can write a helper +# function that takes a number less than 1000 and convert just that chunk to words. +# +# 3. There are many edge cases. What are some good test cases? +# Does your code work with input such as 0? Or 1000010? +# (middle chunk is zero and should not be printed out) +# + +class Solution(object): + def numberToWords(self, num): + """ + :type num: int + :rtype: str + """ + if num == 0: + return "Zero" + + lookup = {0: "Zero", 1:"One", 2: "Two", 3: "Three", 4: "Four", \ + 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine", \ + 10: "Ten", 11: "Eleven", 12: "Twelve", 13: "Thirteen", 14: "Fourteen", \ + 15: "Fifteen", 16: "Sixteen", 17: "Seventeen", 18: "Eighteen", 19: "Nineteen", \ + 20: "Twenty", 30: "Thirty", 40: "Forty", 50: "Fifty", 60: "Sixty", \ + 70: "Seventy", 80: "Eighty", 90: "Ninety"} + unit = ["", "Thousand", "Million", "Billion"] + + res, i = [], 0 + while num: + cur = num % 1000 + if num % 1000: + res.append(self.threeDigits(cur, lookup, unit[i])) + num //= 1000 + i += 1 + return " ".join(res[::-1]) + + def threeDigits(self, num, lookup, unit): + res = [] + if num / 100: + res = [lookup[num / 100] + " " + "Hundred"] + if num % 100: + res.append(self.twoDigits(num % 100, lookup)) + if unit != "": + res.append(unit) + return " ".join(res) + + def twoDigits(self, num, lookup): + if num in lookup: + return lookup[num] + return lookup[(num / 10) * 10] + " " + lookup[num % 10] diff --git a/Python/integer-to-roman.py b/Python/integer-to-roman.py index 3aa53f397..eed075b1b 100644 --- a/Python/integer-to-roman.py +++ b/Python/integer-to-roman.py @@ -6,12 +6,17 @@ # Input is guaranteed to be within the range from 1 to 3999. # - -class Solution: - # @return a string +class Solution(object): def intToRoman(self, num): - numeral_map = {1: "I", 4: "IV", 5: "V", 9: "IX", 10: "X", 40: "XL", 50: "L", 90: "XC", 100: "C", 400: "CD", 500: "D", 900: "CM", 1000: "M"} - keyset, result = sorted(numeral_map.keys()), "" + """ + :type num: int + :rtype: str + """ + numeral_map = {1: "I", 4: "IV", 5: "V", 9: "IX", \ + 10: "X", 40: "XL", 50: "L", 90: "XC", \ + 100: "C", 400: "CD", 500: "D", 900: "CM", \ + 1000: "M"} + keyset, result = sorted(numeral_map.keys()), [] while num > 0: for key in reversed(keyset): @@ -19,8 +24,9 @@ def intToRoman(self, num): num -= key result += numeral_map[key] - return result + return "".join(result) + if __name__ == "__main__": print Solution().intToRoman(999) - print Solution().intToRoman(3999) \ No newline at end of file + print Solution().intToRoman(3999) diff --git a/Python/intersection-of-two-arrays-ii.py b/Python/intersection-of-two-arrays-ii.py new file mode 100644 index 000000000..9e3f626c6 --- /dev/null +++ b/Python/intersection-of-two-arrays-ii.py @@ -0,0 +1,164 @@ +# If the given array is not sorted and the memory is unlimited: +# - Time: O(m + n) +# - Space: O(min(m, n)) +# elif the given array is already sorted: +# if m << n or m >> n: +# - Time: O(min(m, n) * log(max(m, n))) +# - Space: O(1) +# else: +# - Time: O(m + n) +# - Soace: O(1) +# else: (the given array is not sorted and the memory is limited) +# - Time: O(max(m, n) * log(max(m, n))) +# - Space: O(1) + +# Given two arrays, write a function to compute their intersection. +# +# Example: +# Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2]. +# +# Note: +# Each element in the result should appear as many times as it shows in both arrays. +# The result can be in any order. +# +# Follow up: +# - What if the given array is already sorted? How would you optimize your algorithm? +# - What if nums1's size is small compared to num2's size? Which algorithm is better? +# - What if elements of nums2 are stored on disk, and the memory is limited such that +# you cannot load all elements into the memory at once? + + +# If the given array is not sorted and the memory is unlimited. +# Time: O(m + n) +# Space: O(min(m, n)) +# Hash solution. +import collections + + +class Solution(object): + def intersect(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + if len(nums1) > len(nums2): + return self.intersect(nums2, nums1) + + lookup = collections.defaultdict(int) + for i in nums1: + lookup[i] += 1 + + res = [] + for i in nums2: + if lookup[i] > 0: + res += i, + lookup[i] -= 1 + + return res + + def intersect2(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + c = collections.Counter(nums1) & collections.Counter(nums2) + intersect = [] + for i in c: + intersect.extend([i] * c[i]) + return intersect + + +# If the given array is already sorted, and the memory is limited, and (m << n or m >> n). +# Time: O(min(m, n) * log(max(m, n))) +# Space: O(1) +# Binary search solution. +class Solution(object): + def intersect(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + if len(nums1) > len(nums2): + return self.intersect(nums2, nums1) + + def binary_search(compare, nums, left, right, target): + while left < right: + mid = left + (right - left) / 2 + if compare(nums[mid], target): + right = mid + else: + left = mid + 1 + return left + + nums1.sort(), nums2.sort() # Make sure it is sorted, doesn't count in time. + + res = [] + left = 0 + for i in nums1: + left = binary_search(lambda x, y: x >= y, nums2, left, len(nums2), i) + if left != len(nums2) and nums2[left] == i: + res += i, + left += 1 + + return res + + +# If the given array is already sorted, and the memory is limited or m ~ n. +# Time: O(m + n) +# Soace: O(1) +# Two pointers solution. +class Solution(object): + def intersect(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + nums1.sort(), nums2.sort() # Make sure it is sorted, doesn't count in time. + + res = [] + + it1, it2 = 0, 0 + while it1 < len(nums1) and it2 < len(nums2): + if nums1[it1] < nums2[it2]: + it1 += 1 + elif nums1[it1] > nums2[it2]: + it2 += 1 + else: + res += nums1[it1], + it1 += 1 + it2 += 1 + + return res + + +# If the given array is not sorted, and the memory is limited. +# Time: O(max(m, n) * log(max(m, n))) +# Space: O(1) +# Two pointers solution. +class Solution(object): + def intersect(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + nums1.sort(), nums2.sort() # O(max(m, n) * log(max(m, n))) + + res = [] + + it1, it2 = 0, 0 + while it1 < len(nums1) and it2 < len(nums2): + if nums1[it1] < nums2[it2]: + it1 += 1 + elif nums1[it1] > nums2[it2]: + it2 += 1 + else: + res += nums1[it1], + it1 += 1 + it2 += 1 + + return res diff --git a/Python/intersection-of-two-arrays.py b/Python/intersection-of-two-arrays.py new file mode 100644 index 000000000..e04ff0c40 --- /dev/null +++ b/Python/intersection-of-two-arrays.py @@ -0,0 +1,107 @@ +# Time: O(m + n) +# Space: O(min(m, n)) + +# Given two arrays, write a function to compute their intersection. +# +# Example: +# Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2]. +# +# Note: +# Each element in the result must be unique. +# The result can be in any order. + +# Hash solution. + + +class Solution(object): + def intersection(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + if len(nums1) > len(nums2): + return self.intersection(nums2, nums1) + + lookup = set() + for i in nums1: + lookup.add(i) + + res = [] + for i in nums2: + if i in lookup: + res += i, + lookup.discard(i) + + return res + + def intersection2(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + return list(set(nums1) & set(nums2)) + + +# Time: O(max(m, n) * log(max(m, n))) +# Space: O(1) +# Binary search solution. +class Solution2(object): + def intersection(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + if len(nums1) > len(nums2): + return self.intersection(nums2, nums1) + + def binary_search(compare, nums, left, right, target): + while left < right: + mid = left + (right - left) / 2 + if compare(nums[mid], target): + right = mid + else: + left = mid + 1 + return left + + nums1.sort(), nums2.sort() + + res = [] + left = 0 + for i in nums1: + left = binary_search(lambda x, y: x >= y, nums2, left, len(nums2), i) + if left != len(nums2) and nums2[left] == i: + res += i, + left = binary_search(lambda x, y: x > y, nums2, left, len(nums2), i) + + return res + + +# Time: O(max(m, n) * log(max(m, n))) +# Space: O(1) +# Two pointers solution. +class Solution3(object): + def intersection(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + nums1.sort(), nums2.sort() + res = [] + + it1, it2 = 0, 0 + while it1 < len(nums1) and it2 < len(nums2): + if nums1[it1] < nums2[it2]: + it1 += 1 + elif nums1[it1] > nums2[it2]: + it2 += 1 + else: + if not res or res[-1] != nums1[it1]: + res += nums1[it1], + it1 += 1 + it2 += 1 + + return res diff --git a/Python/intersection-of-two-linked-lists.py b/Python/intersection-of-two-linked-lists.py index d2d7af59f..328df54fb 100644 --- a/Python/intersection-of-two-linked-lists.py +++ b/Python/intersection-of-two-linked-lists.py @@ -33,11 +33,14 @@ class Solution: # @return the intersected ListNode def getIntersectionNode(self, headA, headB): curA, curB = headA, headB - tailA, tailB = None, None + begin, tailA, tailB = None, None, None + # a->c->b->c + # b->c->a->c while curA and curB: if curA == curB: - return curA + begin = curA + break if curA.next: curA = curA.next @@ -55,4 +58,4 @@ def getIntersectionNode(self, headA, headB): else: break - return None \ No newline at end of file + return begin diff --git a/Python/invert-binary-tree.py b/Python/invert-binary-tree.py new file mode 100644 index 000000000..5c62fd73f --- /dev/null +++ b/Python/invert-binary-tree.py @@ -0,0 +1,96 @@ +# Time: O(n) +# Space: O(h) +# +# Invert a binary tree. +# +# 4 +# / \ +# 2 7 +# / \ / \ +# 1 3 6 9 +# to +# 4 +# / \ +# 7 2 +# / \ / \ +# 9 6 3 1 +# + +# Time: O(n) +# Space: O(w), w is the max number of the nodes of the levels. +# BFS solution. +class Queue: + def __init__(self): + self.data = collections.deque() + + def push(self, x): + self.data.append(x) + + def peek(self): + return self.data[0] + + def pop(self): + return self.data.popleft() + + def size(self): + return len(self.data) + + def empty(self): + return len(self.data) == 0 + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @return {TreeNode} + def invertTree(self, root): + if root is not None: + nodes = Queue() + nodes.push(root) + while not nodes.empty(): + node = nodes.pop() + node.left, node.right = node.right, node.left + if node.left is not None: + nodes.push(node.left) + if node.right is not None: + nodes.push(node.right) + + return root + +# Time: O(n) +# Space: O(h) +# Stack solution. +class Solution2: + # @param {TreeNode} root + # @return {TreeNode} + def invertTree(self, root): + if root is not None: + nodes = [] + nodes.append(root) + while nodes: + node = nodes.pop() + node.left, node.right = node.right, node.left + if node.left is not None: + nodes.append(node.left) + if node.right is not None: + nodes.append(node.right) + + return root + +# Time: O(n) +# Space: O(h) +# DFS, Recursive solution. +class Solution3: + # @param {TreeNode} root + # @return {TreeNode} + def invertTree(self, root): + if root is not None: + root.left, root.right = self.invertTree(root.right), \ + self.invertTree(root.left) + + return root diff --git a/Python/ipo.py b/Python/ipo.py new file mode 100644 index 000000000..ef1b99102 --- /dev/null +++ b/Python/ipo.py @@ -0,0 +1,47 @@ +# Time: O(nlogn) +# Space: O(n) + +# Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Capital, +# LeetCode would like to work on some projects to increase its capital before the IPO. +# Since it has limited resources, it can only finish at most k distinct projects before the IPO. +# Help LeetCode design the best way to maximize its total capital after finishing at most k distinct projects. +# +# You are given several projects. For each project i, it has a pure profit Pi and a minimum capital +# of Ci is needed to start the corresponding project. Initially, you have W capital. +# When you finish a project, you will obtain its pure profit and the profit will be added to your total capital. +# +# To sum up, pick a list of at most k distinct projects from given projects to maximize +# your final capital, and output your final maximized capital. +# +# Example 1: +# Input: k=2, W=0, Profits=[1,2,3], Capital=[0,1,1]. +# +# Output: 4 +# +# Explanation: Since your initial capital is 0, you can only start the project indexed 0. +# After finishing it you will obtain profit 1 and your capital becomes 1. +# With capital 1, you can either start the project indexed 1 or the project indexed 2. +# Since you can choose at most 2 projects, you need to finish the project indexed 2 to get the maximum capital. +# Therefore, output the final maximized capital, which is 0 + 1 + 3 = 4. +# Note: +# You may assume all numbers in the input are non-negative integers. +# The length of Profits array and Capital array will not exceed 50,000. +# The answer is guaranteed to fit in a 32-bit signed integer. + +class Solution(object): + def findMaximizedCapital(self, k, W, Profits, Capital): + """ + :type k: int + :type W: int + :type Profits: List[int] + :type Capital: List[int] + :rtype: int + """ + curr = [] + future = sorted(zip(Capital, Profits), reverse=True) + for _ in xrange(k): + while future and future[-1][0] <= W: + heapq.heappush(curr, -future.pop()[1]) + if curr: + W -= heapq.heappop(curr) + return W diff --git a/Python/is-subsequence.py b/Python/is-subsequence.py new file mode 100644 index 000000000..e92eceef0 --- /dev/null +++ b/Python/is-subsequence.py @@ -0,0 +1,41 @@ +# Time: O(n) +# Space: O(1) + +# Given a string s and a string t, check if s is subsequence of t. +# +# You may assume that there is only lower case English letters in both s and t. +# t is potentially a very long (length ~= 500,000) string, and s is a short string (<=100). +# +# A subsequence of a string is a new string which is formed from +# the original string by deleting some (can be none) of the characters +# without disturbing the relative positions of the remaining characters. +# (ie, "ace" is a subsequence of "abcde" while "aec" is not). +# +# Example 1: +# s = "abc", t = "ahbgdc" +# +# Return true. +# +# Example 2: +# s = "axc", t = "ahbgdc" +# +# Return false. + +# Greedy solution. +class Solution(object): + def isSubsequence(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if not s: + return True + + i = 0 + for c in t: + if c == s[i]: + i += 1 + if i == len(s): + break + return i == len(s) diff --git a/Python/island-perimeter.py b/Python/island-perimeter.py new file mode 100644 index 000000000..fc6c9017a --- /dev/null +++ b/Python/island-perimeter.py @@ -0,0 +1,48 @@ +# Time: O(m * n) +# Space: O(1) + +# You are given a map in form of a two-dimensional integer grid +# where 1 represents land and 0 represents water. +# Grid cells are connected horizontally/vertically (not diagonally). +# The grid is completely surrounded by water, and there is exactly one island +# (i.e., one or more connected land cells). +# The island doesn't have "lakes" (water inside that isn't connected to +# the water around the island). One cell is a square with side length 1. +# The grid is rectangular, width and height don't exceed 100. +# Determine the perimeter of the island. +# +# Example: +# +# [[0,1,0,0], +# [1,1,1,0], +# [0,1,0,0], +# [1,1,0,0]] +# +# Answer: 16 +import operator + + +class Solution(object): + def islandPerimeter(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + count, repeat = 0, 0 + + for i in xrange(len(grid)): + for j in xrange(len(grid[i])): + if grid[i][j] == 1: + count += 1 + if i != 0 and grid[i - 1][j] == 1: + repeat += 1 + if j != 0 and grid[i][j - 1] == 1: + repeat += 1 + + return 4*count - 2*repeat + +# Since there are no lakes, every pair of neighbour cells with different values is part of the perimeter +# (more precisely, the edge between them is). So just count the differing pairs, both horizontally and vertically +# (for the latter I simply transpose the grid). + def islandPerimeter2(self, grid): + return sum(sum(map(operator.ne, [0] + row, row + [0])) for row in grid + map(list, zip(*grid))) diff --git a/Python/isomorphic-strings.py b/Python/isomorphic-strings.py new file mode 100644 index 000000000..e22243e67 --- /dev/null +++ b/Python/isomorphic-strings.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(1) + +# Given two strings s and t, determine if they are isomorphic. +# +# Two strings are isomorphic if the characters in s can be replaced to get t. +# +# All occurrences of a character must be replaced with another character +# while preserving the order of characters. No two characters may map to +# the same character but a character may map to itself. +# +# For example, +# Given "egg", "add", return true. +# +# Given "foo", "bar", return false. +# +# Given "paper", "title", return true. +# +# Note: +# You may assume both s and t have the same length. + +from itertools import izip # Generator version of zip. + +class Solution(object): + def isIsomorphic(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if len(s) != len(t): + return False + + s2t, t2s = {}, {} + for p, w in izip(s, t): + if w not in s2t and p not in t2s: + s2t[w] = p + t2s[p] = w + elif w not in s2t or s2t[w] != p: + # Contradict mapping. + return False + return True + + +# Time: O(n) +# Space: O(1) +class Solution2(object): + def isIsomorphic(self, s, t): + if len(s) != len(t): + return False + + return self.halfIsom(s, t) and self.halfIsom(t, s) + + def halfIsom(self, s, t): + lookup = {} + for i in xrange(len(s)): + if s[i] not in lookup: + lookup[s[i]] = t[i] + elif lookup[s[i]] != t[i]: + return False + return True diff --git a/Python/judge-route-circle.py b/Python/judge-route-circle.py new file mode 100644 index 000000000..79cfe6d5d --- /dev/null +++ b/Python/judge-route-circle.py @@ -0,0 +1,34 @@ +# Time: O(n) +# Space: O(1) + +# Initially, there is a Robot at position (0, 0). Given a sequence of its moves, +# judge if this robot makes a circle, which means it moves back to the original place. +# +# The move sequence is represented by a string. And each move is represent by a character. +# The valid robot moves are R (Right), L (Left), U (Up) and D (down). +# The output should be true or false representing whether the robot makes a circle. +# +# Example 1: +# Input: "UD" +# Output: true +# Example 2: +# Input: "LL" +# Output: false + +class Solution(object): + def judgeCircle(self, moves): + """ + :type moves: str + :rtype: bool + """ + v, h = 0, 0 + for move in moves: + if move == 'U': + v += 1 + elif move == 'D': + v -= 1 + elif move == 'R': + h += 1 + elif move == 'L': + h -= 1 + return v == 0 and h == 0 diff --git a/Python/jump-game-ii.py b/Python/jump-game-ii.py index 6a660882e..61223b114 100644 --- a/Python/jump-game-ii.py +++ b/Python/jump-game-ii.py @@ -1,4 +1,4 @@ -# Time: O(n^2) +# Time: O(n) # Space: O(1) # # Given an array of non-negative integers, you are initially positioned at the first index of the array. @@ -13,7 +13,26 @@ # The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.) # +# not pass on leetcode because of time limit class Solution: + # @param A, a list of integers + # @return an integer + def jump(self, A): + jump_count = 0 + reachable = 0 + curr_reachable = 0 + for i, length in enumerate(A): + if i > reachable: + return -1 + if i > curr_reachable: + curr_reachable = reachable + jump_count += 1 + reachable = max(reachable, i + length) + return jump_count + +# Time: O(n^2) +# Space: O(1) +class Solution2: # @param A, a list of integers # @return an integer def jump(self, A): @@ -26,6 +45,31 @@ def jump(self, A): for i, length in enumerate(A[:reachable + 1]): reachable = max(reachable, i + length) return -1 + +# when you on an index of nums, move to next index which can move farthest in range of this index reachable +# Time: O(log(n)) +# Space: O(1) +class Solution3(object): + def jump(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + nums[-1] = 2 ** 31 + nums2, l = [i + j for i, j in enumerate(nums)], len(nums) - 1 + + def find_max_index(index): + tmp = nums2[index:index + nums[index] + 1] + return index + tmp.index(max(tmp)) + + index, steps = 0, 0 + while True: + index = find_max_index(index) + if index: + steps += 1 + if index == l: + break + return steps if __name__ == "__main__": print Solution().jump([2,3,1,1,4]) diff --git a/Python/k-diff-pairs-in-an-array.py b/Python/k-diff-pairs-in-an-array.py new file mode 100644 index 000000000..58a4b29b5 --- /dev/null +++ b/Python/k-diff-pairs-in-an-array.py @@ -0,0 +1,46 @@ +# Time: O(n) +# Space: O(n) + +# Total Accepted: 5671 +# Total Submissions: 20941 +# Difficulty: Easy +# Contributors: murali.kf370 +# Given an array of integers and an integer k, +# you need to find the number of unique k-diff pairs in the array. +# Here a k-diff pair is defined as an integer pair (i, j), +# where i and j are both numbers in the array and their absolute difference is k. +# +# Example 1: +# Input: [3, 1, 4, 1, 5], k = 2 +# Output: 2 +# Explanation: There are two 2-diff pairs in the array, (1, 3) and (3, 5). +# Although we have two 1s in the input, we should only return the number of unique pairs. +# Example 2: +# Input:[1, 2, 3, 4, 5], k = 1 +# Output: 4 +# Explanation: There are four 1-diff pairs in the array, (1, 2), (2, 3), (3, 4) and (4, 5). +# Example 3: +# Input: [1, 3, 1, 5, 4], k = 0 +# Output: 1 +# Explanation: There is one 0-diff pair in the array, (1, 1). +# Note: +# The pairs (i, j) and (j, i) count as the same pair. +# The length of the array won't exceed 10,000. +# All the integers in the given input belong to the range: [-1e7, 1e7]. + +class Solution(object): + def findPairs(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + if k < 0: return 0 + result, lookup = set(), set() + for num in nums: + if num-k in lookup: + result.add(num-k) + if num+k in lookup: + result.add(num) + lookup.add(num) + return len(result) diff --git a/Python/k-empty-slots.py b/Python/k-empty-slots.py new file mode 100644 index 000000000..ca99f58b1 --- /dev/null +++ b/Python/k-empty-slots.py @@ -0,0 +1,54 @@ +# Time: O(n) +# Space: O(n) + +# There is a garden with N slots. In each slot, there is a flower. +# The N flowers will bloom one by one in N days. In each day, +# there will be exactly one flower blooming and it will be in the status of blooming since then. +# +# Given an array flowers consists of number from 1 to N. +# Each number in the array represents the place where the flower will open in that day. +# +# For example, flowers[i] = x means that the unique flower that blooms at day i +# will be at position x, where i and x will be in the range from 1 to N. +# +# Also given an integer k, you need to output in which day there exists two flowers +# in the status of blooming, and also the number of flowers between them is k and +# these flowers are not blooming. +# +# If there isn't such day, output -1. +# +# Example 1: +# Input: +# flowers: [1,3,2] +# k: 1 +# Output: 2 +# Explanation: In the second day, the first and the third flower have become blooming. +# +# Example 2: +# Input: +# flowers: [1,2,3] +# k: 1 +# Output: -1 +# Note: +# The given array will be in the range [1, 20000]. + +class Solution(object): + def kEmptySlots(self, flowers, k): + """ + :type flowers: List[int] + :type k: int + :rtype: int + """ + days = [0] * len(flowers) + for i in xrange(len(flowers)): + days[flowers[i]-1] = i + result = float("inf") + i, left, right = 0, 0, k+1 + while right < len(days): + if days[i] < days[left] or days[i] <= days[right]: + if i == right: + result = min(result, max(days[left], days[right])) + left, right = i, k+1+i; + i += 1 + return -1 if result == float("inf") else result+1 + diff --git a/Python/k-inverse-pairs-array.py b/Python/k-inverse-pairs-array.py new file mode 100644 index 000000000..da1e592dd --- /dev/null +++ b/Python/k-inverse-pairs-array.py @@ -0,0 +1,42 @@ +# Time: O(n * k) +# Space: O(k) + +# Given two integers n and k, find how many different arrays consist of numbers +# from 1 to n such that there are exactly k inverse pairs. +# +# We define an inverse pair as following: For ith and jth element in the array, +# if i < j and a[i] > a[j] then it's an inverse pair; Otherwise, it's not. +# +# Since the answer may very large, the answer should be modulo 109 + 7. +# +# Example 1: +# Input: n = 3, k = 0 +# Output: 1 +# Explanation: +# Only the array [1,2,3] which consists of numbers from 1 to 3 has exactly 0 inverse pair. +# Example 2: +# Input: n = 3, k = 1 +# Output: 2 +# Explanation: +# The array [1,3,2] and [2,1,3] have exactly 1 inverse pair. +# Note: +# The integer n is in the range [1, 1000] and k is in the range [0, 1000]. + +class Solution(object): + def kInversePairs(self, n, k): + """ + :type n: int + :type k: int + :rtype: int + """ + M = 1000000007 + dp = [[0]*(k+1) for _ in xrange(2)] + dp[0][0] = 1 + for i in xrange(1, n+1): + dp[i%2] = [0]*(k+1) + dp[i%2][0] = 1 + for j in xrange(1, k+1): + dp[i%2][j] = (dp[i%2][j-1] + dp[(i-1)%2][j]) % M + if j-i >= 0: + dp[i%2][j] = (dp[i%2][j] - dp[(i-1)%2][j-i]) % M + return dp[n%2][k] diff --git a/Python/k-th-smallest-in-lexicographical-order.py b/Python/k-th-smallest-in-lexicographical-order.py new file mode 100644 index 000000000..4a969c6d5 --- /dev/null +++ b/Python/k-th-smallest-in-lexicographical-order.py @@ -0,0 +1,102 @@ +# Time: O(logn) +# Space: O(logn) + +# Given integers n and k, find the lexicographically k-th smallest integer in the range from 1 to n. +# +# Note: 1 <= k <= n <= 109. +# +# Example: +# +# Input: +# n: 13 k: 2 +# +# Output: +# 10 +# +# Explanation: +# The lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9], +# so the second smallest number is 10. + +class Solution(object): + def findKthNumber(self, n, k): + """ + :type n: int + :type k: int + :rtype: int + """ + result = 0 + + cnts = [0] * 10 + for i in xrange(1, 10): + cnts[i] = cnts[i - 1] * 10 + 1 + + nums = [] + i = n + while i: + nums.append(i % 10) + i /= 10 + + total, target = n, 0 + i = len(nums) - 1 + while i >= 0 and k > 0: + target = target*10 + nums[i] + start = int(i == len(nums)-1) + for j in xrange(start, 10): + candidate = result*10 + j + if candidate < target: + num = cnts[i+1] + elif candidate > target: + num = cnts[i] + else: + num = total - cnts[i + 1]*(j-start) - cnts[i]*(9-j) + if k > num: + k -= num + else: + result = candidate + k -= 1 + total = num-1 + break + i -= 1 + + return result + + +# Time: O(logn * logn) +# Space: O(logn) +class Solution2(object): + def findKthNumber(self, n, k): + """ + :type n: int + :type k: int + :rtype: int + """ + def count(n, prefix): + result, number = 0, 1 + while prefix <= n: + result += number + prefix *= 10 + number *= 10 + result -= max(number/10 - (n - prefix/10 + 1), 0) + return result + + def findKthNumberHelper(n, k, cur, index): + if cur: + index += 1 + if index == k: + return (cur, index) + + i = int(cur == 0) + while i <= 9: + cur = cur * 10 + i + cnt = count(n, cur) + if k > cnt + index: + index += cnt + elif cur <= n: + result = findKthNumberHelper(n, k, cur, index) + if result[0]: + return result + i += 1 + cur /= 10 + return (0, index) + + return findKthNumberHelper(n, k, 0, 0)[0] diff --git a/Python/keyboard-row.py b/Python/keyboard-row.py new file mode 100644 index 000000000..13314b621 --- /dev/null +++ b/Python/keyboard-row.py @@ -0,0 +1,36 @@ +# Time: O(n) +# Space: O(1) + +# Given a List of words, return the words that can be typed +# using letters of alphabet on only one row's of American keyboard like the image below. +# +# Example 1: +# Input: ["Hello", "Alaska", "Dad", "Peace"] +# Output: ["Alaska", "Dad"] +# Note: +# You may use one character in the keyboard more than once. +# You may assume the input string will only contain letters of alphabet. + +class Solution(object): + def findWords(self, words): + """ + :type words: List[str] + :rtype: List[str] + """ + rows = [set(['q', 'w', 'e', 'r', 't', 'y','u', 'i', 'o', 'p']), + set(['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l']), + set(['z', 'x', 'c', 'v', 'b' ,'n', 'm'])] + + result = [] + for word in words: + k = 0 + for i in xrange(len(rows)): + if word[0].lower() in rows[i]: + k = i + break + for c in word: + if c.lower() not in rows[k]: + break + else: + result.append(word) + return result diff --git a/Python/kill-process.py b/Python/kill-process.py new file mode 100644 index 000000000..88b0e0867 --- /dev/null +++ b/Python/kill-process.py @@ -0,0 +1,53 @@ +# Time: O(n) +# Space: O(n) + +# DFS solution. +class Solution(object): + def killProcess(self, pid, ppid, kill): + """ + :type pid: List[int] + :type ppid: List[int] + :type kill: int + :rtype: List[int] + """ + def killAll(pid, children, killed): + killed.append(pid) + for child in children[pid]: + killAll(child, children, killed) + + result = [] + children = collections.defaultdict(set) + for i in xrange(len(pid)): + children[ppid[i]].add(pid[i]) + killAll(kill, children, result) + return result + + +# Time: O(n) +# Space: O(n) +# BFS solution. +class Solution2(object): + def killProcess(self, pid, ppid, kill): + """ + :type pid: List[int] + :type ppid: List[int] + :type kill: int + :rtype: List[int] + """ + def killAll(pid, children, killed): + killed.append(pid) + for child in children[pid]: + killAll(child, children, killed) + + result = [] + children = collections.defaultdict(set) + for i in xrange(len(pid)): + children[ppid[i]].add(pid[i]) + q = collections.deque() + q.append(kill) + while q: + p = q.popleft() + result.append(p); + for child in children[p]: + q.append(child) + return result diff --git a/Python/knight-probability-in-chessboard.py b/Python/knight-probability-in-chessboard.py new file mode 100644 index 000000000..cb87d07ed --- /dev/null +++ b/Python/knight-probability-in-chessboard.py @@ -0,0 +1,52 @@ +# Time: O(k * n^2) +# Space: O(n^2) + +# On an NxN chessboard, a knight starts at the r-th row and c-th column and +# attempts to make exactly K moves. The rows and columns are 0 indexed, +# so the top-left square is (0, 0), and the bottom-right square is (N-1, N-1). +# +# A chess knight has 8 possible moves it can make, as illustrated below. +# Each move is two squares in a cardinal direction, then one square in an orthogonal direction. +# +# Each time the knight is to move, it chooses one of eight possible moves uniformly +# at random (even if the piece would go off the chessboard) and moves there. +# +# The knight continues moving until it has made exactly K moves or has moved off the chessboard. +# Return the probability that the knight remains on the board after it has stopped moving. +# +# Example: +# Input: 3, 2, 0, 0 +# Output: 0.0625 +# +# Explanation: There are two moves (to (1,2), (2,1)) that will keep the knight on the board. +# From each of those positions, there are also two moves that will keep the knight on the board. +# The total probability the knight stays on the board is 0.0625. +# +# Note: +# N will be between 1 and 25. +# K will be between 0 and 100. +# The knight always initially starts on the board. + +class Solution(object): + def knightProbability(self, N, K, r, c): + """ + :type N: int + :type K: int + :type r: int + :type c: int + :rtype: float + """ + directions = \ + [[ 1, 2], [ 1, -2], [ 2, 1], [ 2, -1], \ + [-1, 2], [-1, -2], [-2, 1], [-2, -1]]; + dp = [[[1 for _ in xrange(N)] for _ in xrange(N)] for _ in xrange(2)] + for step in xrange(1, K+1): + for i in xrange(N): + for j in xrange(N): + dp[step%2][i][j] = 0 + for direction in directions: + rr, cc = i+direction[0], j+direction[1] + if 0 <= cc < N and 0 <= rr < N: + dp[step%2][i][j] += 0.125 * dp[(step-1)%2][rr][cc]; + + return dp[K%2][r][c] diff --git a/Python/kth-largest-element-in-an-array.py b/Python/kth-largest-element-in-an-array.py new file mode 100644 index 000000000..08dd0b788 --- /dev/null +++ b/Python/kth-largest-element-in-an-array.py @@ -0,0 +1,33 @@ +# Time: O(n) ~ O(n^2) +# Space: O(1) + +from random import randint + +class Solution: + # @param {integer[]} nums + # @param {integer} k + # @return {integer} + def findKthLargest(self, nums, k): + left, right = 0, len(nums) - 1 + while left <= right: + pivot_idx = randint(left, right) + new_pivot_idx = self.PartitionAroundPivot(left, right, pivot_idx, nums) + if new_pivot_idx == k - 1: + return nums[new_pivot_idx] + elif new_pivot_idx > k - 1: + right = new_pivot_idx - 1 + else: # new_pivot_idx < k - 1. + left = new_pivot_idx + 1 + + def PartitionAroundPivot(self, left, right, pivot_idx, nums): + pivot_value = nums[pivot_idx] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i] > pivot_value: + nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] + new_pivot_idx += 1 + + nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] + return new_pivot_idx + diff --git a/Python/kth-smallest-element-in-a-bst.py b/Python/kth-smallest-element-in-a-bst.py new file mode 100644 index 000000000..ee7216094 --- /dev/null +++ b/Python/kth-smallest-element-in-a-bst.py @@ -0,0 +1,39 @@ +# Time: O(max(h, k)) +# Space: O(h) + +# Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. +# +# Note: +# You may assume k is always valid, 1 ≤ k ≤ BST's total elements. +# +# Follow up: +# What if the BST is modified (insert/delete operations) often and +# you need to find the kth smallest frequently? How would you optimize the kthSmallest routine? +# + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @param {integer} k + # @return {integer} + def kthSmallest(self, root, k): + s, cur, rank = [], root, 0 + + while s or cur: + if cur: + s.append(cur) + cur = cur.left + else: + cur = s.pop() + rank += 1 + if rank == k: + return cur.val + cur = cur.right + + return float("-inf") diff --git a/Python/kth-smallest-element-in-a-sorted-matrix.py b/Python/kth-smallest-element-in-a-sorted-matrix.py new file mode 100644 index 000000000..be66a8b8f --- /dev/null +++ b/Python/kth-smallest-element-in-a-sorted-matrix.py @@ -0,0 +1,52 @@ +# Time: O(k * log(min(n, m, k))), with n x m matrix +# Space: O(min(n, m, k)) + +# Given a n x n matrix where each of the rows and +# columns are sorted in ascending order, +# find the kth smallest element in the matrix. +# +# Note that it is the kth smallest element in the sorted order, +# not the kth distinct element. +# +# Example: +# +# matrix = [ +# [ 1, 5, 9], +# [10, 11, 13], +# [12, 13, 15] +# ], +# k = 8, +# +# return 13. +# Note: +# You may assume k is always valid, 1 <= k <= n^2. + +from heapq import heappush, heappop + +class Solution(object): + def kthSmallest(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + kth_smallest = 0 + min_heap = [] + + def push(i, j): + if len(matrix) > len(matrix[0]): + if i < len(matrix[0]) and j < len(matrix): + heappush(min_heap, [matrix[j][i], i, j]) + else: + if i < len(matrix) and j < len(matrix[0]): + heappush(min_heap, [matrix[i][j], i, j]) + + push(0, 0) + while min_heap and k > 0: + kth_smallest, i, j = heappop(min_heap) + push(i, j + 1) + if j == 0: + push(i + 1, 0) + k -= 1 + + return kth_smallest diff --git a/Python/kth-smallest-number-in-multiplication-table.py b/Python/kth-smallest-number-in-multiplication-table.py new file mode 100644 index 000000000..dc5ee176e --- /dev/null +++ b/Python/kth-smallest-number-in-multiplication-table.py @@ -0,0 +1,51 @@ +# Time: O(m * log(m * n)) +# Space: O(1) + +# Nearly every one have used the Multiplication Table. +# But could you find out the k-th smallest number quickly from the multiplication table? +# +# Given the height m and the length n of a m * n Multiplication Table, and a positive integer k, +# you need to return the k-th smallest number in this table. +# +# Example 1: +# Input: m = 3, n = 3, k = 5 +# Output: +# Explanation: +# The Multiplication Table: +# 1 2 3 +# 2 4 6 +# 3 6 9 +# +# The 5-th smallest number is 3 (1, 2, 2, 3, 3). +# Example 2: +# Input: m = 2, n = 3, k = 6 +# Output: +# Explanation: +# The Multiplication Table: +# 1 2 3 +# 2 4 6 +# +# The 6-th smallest number is 6 (1, 2, 2, 3, 4, 6). +# Note: +# The m and n will be in the range [1, 30000]. +# The k will be in the range [1, m * n] + +class Solution(object): + def findKthNumber(self, m, n, k): + """ + :type m: int + :type n: int + :type k: int + :rtype: int + """ + def count(target, m, n): + return sum(min(target//i, n) for i in xrange(1, m+1)) + + left, right = 1, m*n; + while left <= right: + mid = left + (right-left)/2 + if count(mid, m, n) >= k: + right = mid-1 + else: + left = mid+1 + return left diff --git a/Python/largest-bst-subtree.py b/Python/largest-bst-subtree.py new file mode 100644 index 000000000..35d18f1be --- /dev/null +++ b/Python/largest-bst-subtree.py @@ -0,0 +1,43 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def largestBSTSubtree(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if root is None: + return 0 + + max_size = [1] + def largestBSTSubtreeHelper(root): + if root.left is None and root.right is None: + return 1, root.val, root.val + + left_size, left_min, left_max = 0, root.val, root.val + if root.left is not None: + left_size, left_min, left_max = largestBSTSubtreeHelper(root.left) + + right_size, right_min, right_max = 0, root.val, root.val + if root.right is not None: + right_size, right_min, right_max = largestBSTSubtreeHelper(root.right) + + size = 0 + if (root.left is None or left_size > 0) and \ + (root.right is None or right_size > 0) and \ + left_max <= root.val <= right_min: + size = 1 + left_size + right_size + max_size[0] = max(max_size[0], size) + + return size, left_min, right_max + + largestBSTSubtreeHelper(root) + return max_size[0] diff --git a/Python/largest-divisible-subset.py b/Python/largest-divisible-subset.py new file mode 100644 index 000000000..e908d1887 --- /dev/null +++ b/Python/largest-divisible-subset.py @@ -0,0 +1,48 @@ +# Time: O(n^2) +# Space: O(n) + +# Given a set of distinct positive integers, +# find the largest subset such that every pair (Si, Sj) of +# elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0. +# +# If there are multiple solutions, return any subset is fine. +# +# Example 1: +# +# nums: [1,2,3] +# +# Result: [1,2] (of course, [1,3] will also be ok) +# Example 2: +# +# nums: [1,2,4,8] +# +# Result: [1,2,4,8] + +class Solution(object): + def largestDivisibleSubset(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + if not nums: + return [] + + nums.sort() + dp = [1] * len(nums) + prev = [-1] * len(nums) + largest_idx = 0 + for i in xrange(len(nums)): + for j in xrange(i): + if nums[i] % nums[j] == 0: + if dp[i] < dp[j] + 1: + dp[i] = dp[j] + 1 + prev[i] = j + if dp[largest_idx] < dp[i]: + largest_idx = i + + result = [] + i = largest_idx + while i != -1: + result.append(nums[i]) + i = prev[i] + return result[::-1] diff --git a/Python/largest-number.py b/Python/largest-number.py index ab28367cf..8317a617b 100644 --- a/Python/largest-number.py +++ b/Python/largest-number.py @@ -1,5 +1,5 @@ -# Time: O(n^2) -# Space: O(n) +# Time: O(nlogn) +# Space: O(1) # # Given a list of non negative integers, arrange them such that they form the largest number. # diff --git a/Python/largest-palindrome-product.py b/Python/largest-palindrome-product.py new file mode 100644 index 000000000..c189a0011 --- /dev/null +++ b/Python/largest-palindrome-product.py @@ -0,0 +1,32 @@ +# Time: O(10^(2n)) +# Space: O(n) + +# Find the largest palindrome made from the product of two n-digit numbers. +# Since the result could be very large, you should return the largest palindrome mod 1337. +# +# Example: +# Input: 2 +# Output: 987 +# Explanation: 99 x 91 = 9009, 9009 % 1337 = 987 +# +# Note: +# The range of n is [1,8]. + +class Solution_TLE(object): + def largestPalindrome(self, n): + """ + :type n: int + :rtype: int + """ + if n == 1: + return 9 + + upper, lower = 10**n-1, 10**(n-1) + for i in reversed(xrange(lower, upper+1)): + candidate = int(str(i) + str(i)[::-1]) + j = upper + while j * j >= candidate: + if candidate % j == 0: + return candidate % 1337 + j -= 1 + return -1 diff --git a/Python/largest-rectangle-in-histogram.py b/Python/largest-rectangle-in-histogram.py index 2313b011f..e3dea568b 100644 --- a/Python/largest-rectangle-in-histogram.py +++ b/Python/largest-rectangle-in-histogram.py @@ -16,12 +16,12 @@ class Solution: def largestRectangleArea(self, height): increasing, area, i = [], 0, 0 while i <= len(height): - if len(increasing) == 0 or (i < len(height) and height[i] > height[increasing[-1]]): + if not increasing or (i < len(height) and height[i] > height[increasing[-1]]): increasing.append(i) i += 1 else: last = increasing.pop() - if len(increasing) == 0: + if not increasing: area = max(area, height[last] * i) else: area = max(area, height[last] * (i - increasing[-1] - 1 )) @@ -30,4 +30,4 @@ def largestRectangleArea(self, height): if __name__ == "__main__": print Solution().largestRectangleArea([2, 0, 2]) print Solution().largestRectangleArea([2, 1, 5, 6, 2, 3]) - \ No newline at end of file + diff --git a/Python/letter-combinations-of-a-phone-number.py b/Python/letter-combinations-of-a-phone-number.py index a818ce42b..c876137ca 100644 --- a/Python/letter-combinations-of-a-phone-number.py +++ b/Python/letter-combinations-of-a-phone-number.py @@ -1,5 +1,5 @@ -# Time: O(4^n) -# Space: O(1) +# Time: O(n * 4^n) +# Space: O(n) # # Given a digit string, return all possible letter combinations that the number could represent. # @@ -17,25 +17,33 @@ class Solution: # @return a list of strings, [s1, s2] def letterCombinations(self, digits): - lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"], [""] + if not digits: + return [] + + lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", \ + "pqrs", "tuv", "wxyz"], [""] - for digit in digits: + for digit in reversed(digits): choices = lookup[int(digit)] m, n = len(choices), len(result) - result.extend([result[i % n] for i in xrange(n, m * n)]) + result += [result[i % n] for i in xrange(n, m * n)] for i in xrange(m * n): - result[i] += choices[i / n] + result[i] = choices[i / n] + result[i] return result -# Time: O(4^n) + +# Time: O(n * 4^n) # Space: O(n) # Recursive Solution class Solution2: # @return a list of strings, [s1, s2] def letterCombinations(self, digits): - lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"], [] + if not digits: + return [] + lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", \ + "pqrs", "tuv", "wxyz"], [] self.letterCombinationsRecu(result, digits, lookup, "", 0) return result diff --git a/Python/lexicographical-numbers.py b/Python/lexicographical-numbers.py new file mode 100644 index 000000000..789aa4d51 --- /dev/null +++ b/Python/lexicographical-numbers.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(1) + +# Given an integer n, return 1 - n in lexicographical order. +# +# For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9]. +# +# Please optimize your algorithm to use less time and space. +# The input size may be as large as 5,000,000. + +class Solution(object): + def lexicalOrder(self, n): + result = [] + + i = 1 + while len(result) < n: + k = 0 + while i * 10**k <= n: + result.append(i * 10**k) + k += 1 + + num = result[-1] + 1 + while num <= n and num % 10: + result.append(num) + num += 1 + + if not num % 10: + num -= 1 + else: + num /= 10 + + while num % 10 == 9: + num /= 10 + + i = num+1 + + return result diff --git a/Python/lfu-cache.py b/Python/lfu-cache.py new file mode 100644 index 000000000..087f61380 --- /dev/null +++ b/Python/lfu-cache.py @@ -0,0 +1,131 @@ +# Time: O(1), per operation +# Space: O(k), k is the capacity of cache + +# Design and implement a data structure for Least Frequently Used (LFU) cache. +# It should support the following operations: get and put. +# +# get(key) - Get the value (will always be positive) of the key +# if the key exists in the cache, otherwise return -1. +# put(key, value) - Set or insert the value if the key is not already present. +# When the cache reaches its capacity, +# it should invalidate the least frequently used item before inserting a new item. +# For the purpose of this problem, when there is a tie +# (i.e., two or more keys that have the same frequency), +# the least recently used key would be evicted. +# +# Follow up: +# Could you do both operations in O(1) time complexity? +# +# Example: +# +# LFUCache cache = new LFUCache( 2 /* capacity */ ); +# +# cache.put(1, 1); +# cache.put(2, 2); +# cache.get(1); // returns 1 +# cache.put(3, 3); // evicts key 2 +# cache.get(2); // returns -1 (not found) +# cache.get(3); // returns 3. +# cache.put(4, 4); // evicts key 1. +# cache.get(1); // returns -1 (not found) +# cache.get(3); // returns 3 +# cache.get(4); // returns 4 + +class ListNode(object): + def __init__(self, key, value, freq): + self.key = key + self.val = value + self.freq = freq + self.next = None + self.prev = None + + +class LinkedList(object): + def __init__(self): + self.head = None + self.tail = None + + def append(self, node): + if self.head is None: + self.head = node + else: + self.tail.next = node + node.prev = self.tail + self.tail = node + + def delete(self, node): + if node.prev: + node.prev.next = node.next + else: + self.head = node.next + if node.next: + node.next.prev = node.prev + else: + self.tail = node.prev + del node + + +class LFUCache(object): + + def __init__(self, capacity): + """ + :type capacity: int + """ + self.__capa = capacity + self.__size = 0 + self.__min_freq = 0 + self.__freq_to_nodes = collections.defaultdict(LinkedList) + self.__key_to_node = {} + + + def get(self, key): + """ + :type key: int + :rtype: int + """ + if key not in self.__key_to_node: + return -1 + + old_node = self.__key_to_node[key] + self.__key_to_node[key] = ListNode(key, old_node.val, old_node.freq) + self.__freq_to_nodes[old_node.freq].delete(old_node) + if not self.__freq_to_nodes[self.__key_to_node[key].freq].head: + del self.__freq_to_nodes[self.__key_to_node[key].freq] + if self.__min_freq == self.__key_to_node[key].freq: + self.__min_freq += 1 + + self.__key_to_node[key].freq += 1 + self.__freq_to_nodes[self.__key_to_node[key].freq].append(self.__key_to_node[key]) + + return self.__key_to_node[key].val + + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: void + """ + if self.__capa <= 0: + return + + if self.get(key) != -1: + self.__key_to_node[key].val = value + return + + if self.__size == self.__capa: + del self.__key_to_node[self.__freq_to_nodes[self.__min_freq].head.key] + self.__freq_to_nodes[self.__min_freq].delete(self.__freq_to_nodes[self.__min_freq].head) + if not self.__freq_to_nodes[self.__min_freq].head: + del self.__freq_to_nodes[self.__min_freq] + self.__size -= 1 + + self.__min_freq = 1 + self.__key_to_node[key] = ListNode(key, value, self.__min_freq) + self.__freq_to_nodes[self.__key_to_node[key].freq].append(self.__key_to_node[key]) + self.__size += 1 + +# Your LFUCache object will be instantiated and called as such: +# obj = LFUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) diff --git a/Python/license-key-formatting.py b/Python/license-key-formatting.py new file mode 100644 index 000000000..9c729793b --- /dev/null +++ b/Python/license-key-formatting.py @@ -0,0 +1,51 @@ +# Time: O(n) +# Space: O(1) + +# Now you are given a string S, which represents a software license key which we would like to format. +# The string S is composed of alphanumerical characters and dashes. +# The dashes split the alphanumerical characters within the string into groups. +# (i.e. if there are M dashes, the string is split into M+1 groups). +# The dashes in the given string are possibly misplaced. +# +# We want each group of characters to be of length K +# (except for possibly the first group, which could be shorter, +# but still must contain at least one character). +# To satisfy this requirement, we will reinsert dashes. +# Additionally, all the lower case letters in the string must be converted to upper case. +# +# So, you are given a non-empty string S, representing a license key to format, +# and an integer K. And you need to return the license key formatted according to the description above. +# +# Example 1: +# Input: S = "2-4A0r7-4k", K = 4 +# +# Output: "24A0-R74K" +# +# Explanation: The string S has been split into two parts, each part has 4 characters. +# Example 2: +# Input: S = "2-4A0r7-4k", K = 3 +# +# Output: "24-A0R-74K" +# +# Explanation: The string S has been split into three parts, each part has 3 characters +# except the first part as it could be shorter as said above. +# Note: +# The length of string S will not exceed 12,000, and K is a positive integer. +# String S consists only of alphanumerical characters (a-z and/or A-Z and/or 0-9) and dashes(-). +# String S is non-empty. + +class Solution(object): + def licenseKeyFormatting(self, S, K): + """ + :type S: str + :type K: int + :rtype: str + """ + result = [] + for i in reversed(xrange(len(S))): + if S[i] == '-': + continue + if len(result) % (K + 1) == K: + result += '-' + result += S[i].upper() + return "".join(reversed(result)) diff --git a/Python/line-reflection.py b/Python/line-reflection.py new file mode 100644 index 000000000..2d508e2e4 --- /dev/null +++ b/Python/line-reflection.py @@ -0,0 +1,51 @@ +# Time: O(n) +# Space: O(n) + +# Hash solution. +class Solution(object): + def isReflected(self, points): + """ + :type points: List[List[int]] + :rtype: bool + """ + if not points: + return True + groups_by_y = collections.defaultdict(set) + left, right = float("inf"), float("-inf") + for p in points: + groups_by_y[p[1]].add(p[0]) + left, right = min(left, p[0]), max(right, p[0]) + mid = left + right + for group in groups_by_y.values(): + for x in group: + if mid - x not in group: + return False + return True + + +# Time: O(nlogn) +# Space: O(n) +# Two pointers solution. +class Solution2(object): + def isReflected(self, points): + """ + :type points: List[List[int]] + :rtype: bool + """ + if not points: + return True + points.sort() + # Space: O(n) + points[len(points)/2:] = sorted(points[len(points)/2:], \ + lambda x, y: y[1] - x[1] if x[0] == y[0] else \ + x[0] - y[0]) + mid = points[0][0] + points[-1][0] + left, right = 0, len(points) - 1 + while left <= right: + if (mid != points[left][0] + points[right][0]) or \ + (points[left][0] != points[right][0] and \ + points[left][1] != points[right][1]): + return False + left += 1 + right -= 1 + return True diff --git a/Python/linked-list-random-node.py b/Python/linked-list-random-node.py new file mode 100644 index 000000000..1e6d7de0f --- /dev/null +++ b/Python/linked-list-random-node.py @@ -0,0 +1,53 @@ +# Time: O(n) +# Space: O(1) + +# Given a singly linked list, return a random node's value from the linked list. +# Each node must have the same probability of being chosen. +# +# Follow up: +# What if the linked list is extremely large and its length is unknown to you? +# Could you solve this efficiently without using extra space? +# +# Example: +# +# // Init a singly linked list [1,2,3]. +# ListNode head = new ListNode(1); +# head.next = new ListNode(2); +# head.next.next = new ListNode(3); +# Solution solution = new Solution(head); +# +# // getRandom() should return either 1, 2, or 3 randomly. +# Each element should have equal probability of returning. +# solution.getRandom(); + + +from random import randint + +class Solution(object): + + def __init__(self, head): + """ + @param head The linked list's head. Note that the head is guanranteed to be not null, so it contains at least one node. + :type head: ListNode + """ + self.__head = head + + + # Proof of Reservoir Sampling: + # https://discuss.leetcode.com/topic/53753/brief-explanation-for-reservoir-sampling + def getRandom(self): + """ + Returns a random node's value. + :rtype: int + """ + reservoir = -1 + curr, n = self.__head, 0 + while curr: + reservoir = curr.val if randint(1, n+1) == 1 else reservoir + curr, n = curr.next, n+1 + return reservoir + + +# Your Solution object will be instantiated and called as such: +# obj = Solution(head) +# param_1 = obj.getRandom() diff --git a/Python/logger-rate-limiter.py b/Python/logger-rate-limiter.py new file mode 100644 index 000000000..0e4006813 --- /dev/null +++ b/Python/logger-rate-limiter.py @@ -0,0 +1,31 @@ +# Time: O(1), amortized +# Space: O(k), k is the max number of printed messages in last 10 seconds + +class Logger(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.__dq = collections.deque() + self.__printed = set() + + def shouldPrintMessage(self, timestamp, message): + """ + Returns true if the message should be printed in the given timestamp, otherwise returns false. The timestamp is in seconds granularity. + :type timestamp: int + :type message: str + :rtype: bool + """ + while self.__dq and self.__dq[0][0] <= timestamp - 10: + self.__printed.remove(self.__dq.popleft()[1]) + if message in self.__printed: + return False + self.__dq.append((timestamp, message)) + self.__printed.add(message) + return True + + +# Your Logger object will be instantiated and called as such: +# obj = Logger() +# param_1 = obj.shouldPrintMessage(timestamp,message) diff --git a/Python/lonely-pixel-i.py b/Python/lonely-pixel-i.py new file mode 100644 index 000000000..28f8ba9a1 --- /dev/null +++ b/Python/lonely-pixel-i.py @@ -0,0 +1,33 @@ +# Time: O(m * n) +# Space: O(m + n) + +class Solution(object): + def findLonelyPixel(self, picture): + """ + :type picture: List[List[str]] + :rtype: int + """ + rows, cols = [0] * len(picture), [0] * len(picture[0]) + for i in xrange(len(picture)): + for j in xrange(len(picture[0])): + if picture[i][j] == 'B': + rows[i] += 1 + cols[j] += 1 + + result = 0 + for i in xrange(len(picture)): + if rows[i] == 1: + for j in xrange(len(picture[0])): + result += picture[i][j] == 'B' and cols[j] == 1 + return result + + +class Solution2(object): + def findLonelyPixel(self, picture): + """ + :type picture: List[List[str]] + :type N: int + :rtype: int + """ + return sum(col.count('B') == 1 == picture[col.index('B')].count('B') \ + for col in zip(*picture)) diff --git a/Python/lonely-pixel-ii.py b/Python/lonely-pixel-ii.py new file mode 100644 index 000000000..25bb4c408 --- /dev/null +++ b/Python/lonely-pixel-ii.py @@ -0,0 +1,39 @@ +# Time: O(m * n) +# Space: O(m * n) + +class Solution(object): + def findBlackPixel(self, picture, N): + """ + :type picture: List[List[str]] + :type N: int + :rtype: int + """ + rows, cols = [0] * len(picture), [0] * len(picture[0]) + lookup = collections.defaultdict(int) + for i in xrange(len(picture)): + for j in xrange(len(picture[0])): + if picture[i][j] == 'B': + rows[i] += 1 + cols[j] += 1 + lookup[tuple(picture[i])] += 1 + + result = 0 + for i in xrange(len(picture)): + if rows[i] == N and lookup[tuple(picture[i])] == N: + for j in xrange(len(picture[0])): + result += picture[i][j] == 'B' and cols[j] == N + return result + + +class Solution2(object): + def findBlackPixel(self, picture, N): + """ + :type picture: List[List[str]] + :type N: int + :rtype: int + """ + lookup = collections.Counter(map(tuple, picture)) + cols = [col.count('B') for col in zip(*picture)] + return sum(N * zip(row, cols).count(('B', N)) \ + for row, cnt in lookup.iteritems() \ + if cnt == N == row.count('B')) diff --git a/Python/longest-absolute-file-path.py b/Python/longest-absolute-file-path.py new file mode 100644 index 000000000..bc29abb10 --- /dev/null +++ b/Python/longest-absolute-file-path.py @@ -0,0 +1,68 @@ +# Time: O(n) +# Space: O(d), d is the max depth of the paths + +# Suppose we abstract our file system by a string in the following manner: +# +# The string "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext" represents: +# +# dir +# subdir1 +# subdir2 +# file.ext +# The directory dir contains an empty sub-directory subdir1 and a sub-directory subdir2 containing a file file.ext. +# +# The string "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" represents: +# +# dir +# subdir1 +# file1.ext +# subsubdir1 +# subdir2 +# subsubdir2 +# file2.ext +# The directory dir contains two sub-directories subdir1 and subdir2. +# subdir1 contains a file file1.ext and an empty second-level sub-directory subsubdir1. +# subdir2 contains a second-level sub-directory subsubdir2 containing a file file2.ext. +# +# We are interested in finding the longest (number of characters) absolute path to a file within our file system. +# For example, in the second example above, the longest absolute path is "dir/subdir2/subsubdir2/file2.ext", +# and its length is 32 (not including the double quotes). +# +# Given a string representing the file system in the above format, +# return the length of the longest absolute path to file in the abstracted file system. +# If there is no file in the system, return 0. +# +# Note: +# The name of a file contains at least a . and an extension. +# The name of a directory or sub-directory will not contain a .. +# Time complexity required: O(n) where n is the size of the input string. +# +# Notice that a/aa/aaa/file1.txt is not the longest file path, if there is +# another path aaaaaaaaaaaaaaaaaaaaa/sth.png. + + +class Solution(object): + def lengthLongestPath(self, input): + """ + :type input: str + :rtype: int + """ + def split_iter(s, tok): + start = 0 + for i in xrange(len(s)): + if s[i] == tok: + yield s[start:i] + start = i + 1 + yield s[start:] + + + max_len = 0 + path_len = {0: 0} + for line in split_iter(input, '\n'): + name = line.lstrip('\t') + depth = len(line) - len(name) + if '.' in name: + max_len = max(max_len, path_len[depth] + len(name)) + else: + path_len[depth + 1] = path_len[depth] + len(name) + 1 + return max_len diff --git a/Python/longest-common-prefix.py b/Python/longest-common-prefix.py index 2ffa96cfb..f5a918469 100644 --- a/Python/longest-common-prefix.py +++ b/Python/longest-common-prefix.py @@ -1,22 +1,24 @@ -# Time: O(n1 + n2 + ...) +# Time: O(n * k), k is the length of the common prefix # Space: O(1) -# -# Write a function to find the longest common prefix string amongst an array of strings. -# -class Solution: - # @return a string +# Write a function to find the longest common prefix string +# amongst an array of strings. + +class Solution(object): def longestCommonPrefix(self, strs): - if len(strs) == 0: + """ + :type strs: List[str] + :rtype: str + """ + if not strs: return "" - longest = strs[0] - for string in strs[1:]: - i = 0 - while i < len(string) and i < len(longest) and string[i] == longest[i]: - i += 1 - longest = longest[:i] - return longest - + + for i in xrange(len(strs[0])): + for string in strs[1:]: + if i >= len(string) or string[i] != strs[0][i]: + return strs[0][:i] + return strs[0] + + if __name__ == "__main__": print Solution().longestCommonPrefix(["hello", "heaven", "heavy"]) - \ No newline at end of file diff --git a/Python/longest-continuous-increasing-subsequence.py b/Python/longest-continuous-increasing-subsequence.py new file mode 100644 index 000000000..c374bbea3 --- /dev/null +++ b/Python/longest-continuous-increasing-subsequence.py @@ -0,0 +1,32 @@ +# Time: O(n) +# Space: O(1) + +# Given an unsorted array of integers, +# find the length of longest continuous increasing subsequence. +# +# Example 1: +# Input: [1,3,5,4,7] +# Output: 3 +# Explanation: The longest continuous increasing subsequence is [1,3,5], its length is 3. +# Even though [1,3,5,7] is also an increasing subsequence, +# it's not a continuous one where 5 and 7 are separated by 4. +# Example 2: +# Input: [2,2,2,2,2] +# Output: 1 +# Explanation: The longest continuous increasing subsequence is [2], its length is 1. +# Note: Length of the array will not exceed 10,000. + +class Solution(object): + def findLengthOfLCIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result, count = 0, 0 + for i in xrange(len(nums)): + if i == 0 or nums[i-1] < nums[i]: + count += 1 + result = max(result, count) + else: + count = 1 + return result diff --git a/Python/longest-harmonious-subsequence.py b/Python/longest-harmonious-subsequence.py new file mode 100644 index 000000000..585179747 --- /dev/null +++ b/Python/longest-harmonious-subsequence.py @@ -0,0 +1,29 @@ +# Time: O(n) +# Space: O(n) + +# We define a harmonious array is an array where the difference +# between its maximum value and its minimum value is exactly 1. +# +# Now, given an integer array, you need to find the length of its +# longest harmonious subsequence among all its possible subsequences. +# +# Example 1: +# Input: [1,3,2,2,5,2,3,7] +# Output: 5 +# Explanation: The longest harmonious subsequence is [3,2,2,2,3]. +# Note: The length of the input array will not exceed 20,000. + +class Solution(object): + def findLHS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + lookup = collections.defaultdict(int) + result = 0 + for num in nums: + lookup[num] += 1 + for diff in [-1, 1]: + if (num + diff) in lookup: + result = max(result, lookup[num] + lookup[num + diff]) + return result diff --git a/Python/longest-increasing-path-in-a-matrix.py b/Python/longest-increasing-path-in-a-matrix.py new file mode 100644 index 000000000..f5685d3a7 --- /dev/null +++ b/Python/longest-increasing-path-in-a-matrix.py @@ -0,0 +1,60 @@ +# Time: O(m * n) +# Space: O(m * n) + +# Given an integer matrix, find the length of the longest increasing path. +# +# From each cell, you can either move to four directions: left, right, up +# or down. You may NOT move diagonally or move outside of the boundary +# (i.e. wrap-around is not allowed). +# +# Example 1: +# +# nums = [ +# [9,9,4], +# [6,6,8], +# [2,1,1] +# ] +# Return 4 +# The longest increasing path is [1, 2, 6, 9]. +# +# Example 2: +# +# nums = [ +# [3,4,5], +# [3,2,6], +# [2,2,1] +# ] +# Return 4 +# The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed. + +# DFS + Memorization solution. +class Solution(object): + def longestIncreasingPath(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: int + """ + if not matrix: + return 0 + + def longestpath(matrix, i, j, max_lengths): + if max_lengths[i][j]: + return max_lengths[i][j] + + max_depth = 0 + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + for d in directions: + x, y = i + d[0], j + d[1] + if 0 <= x < len(matrix) and 0 <= y < len(matrix[0]) and \ + matrix[x][y] < matrix[i][j]: + max_depth = max(max_depth, longestpath(matrix, x, y, max_lengths)); + max_lengths[i][j] = max_depth + 1 + return max_lengths[i][j] + + res = 0 + max_lengths = [[0 for _ in xrange(len(matrix[0]))] for _ in xrange(len(matrix))] + for i in xrange(len(matrix)): + for j in xrange(len(matrix[0])): + res = max(res, longestpath(matrix, i, j, max_lengths)) + + return res diff --git a/Python/longest-increasing-subsequence.py b/Python/longest-increasing-subsequence.py new file mode 100644 index 000000000..596fffaaf --- /dev/null +++ b/Python/longest-increasing-subsequence.py @@ -0,0 +1,61 @@ +# Time: O(nlogn) +# Space: O(n) +# +# Given an unsorted array of integers, +# find the length of longest increasing subsequence. +# +# For example, +# Given [10, 9, 2, 5, 3, 7, 101, 18], +# The longest increasing subsequence is [2, 3, 7, 101], +# therefore the length is 4. Note that there may be more +# than one LIS combination, it is only necessary for you to return the length. +# +# Your algorithm should run in O(n2) complexity. +# +# Follow up: Could you improve it to O(n log n) time complexity? +# + +# Binary search solution. +class Solution(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + LIS = [] + def insert(target): + left, right = 0, len(LIS) - 1 + # Find the first index "left" which satisfies LIS[left] >= target + while left <= right: + mid = left + (right - left) / 2; + if LIS[mid] >= target: + right = mid - 1 + else: + left = mid + 1 + # If not found, append the target. + if left == len(LIS): + LIS.append(target); + else: + LIS[left] = target + + for num in nums: + insert(num) + + return len(LIS) + +# Time: O(n^2) +# Space: O(n) +# Traditional DP solution. +class Solution2(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + dp = [] # dp[i]: the length of LIS ends with nums[i] + for i in xrange(len(nums)): + dp.append(1) + for j in xrange(i): + if nums[j] < nums[i]: + dp[i] = max(dp[i], dp[j] + 1) + return max(dp) if dp else 0 diff --git a/Python/longest-line-of-consecutive-one-in-a-matrix.py b/Python/longest-line-of-consecutive-one-in-a-matrix.py new file mode 100644 index 000000000..4f6845c00 --- /dev/null +++ b/Python/longest-line-of-consecutive-one-in-a-matrix.py @@ -0,0 +1,22 @@ +# Time: O(m * n) +# Space: O(n) + +class Solution(object): + def longestLine(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + if not M: return 0 + result = 0 + dp = [[[0] * 4 for _ in xrange(len(M[0]))] for _ in xrange(2)] + for i in xrange(len(M)): + for j in xrange(len(M[0])): + dp[i % 2][j][:] = [0] * 4 + if M[i][j] == 1: + dp[i % 2][j][0] = dp[i % 2][j - 1][0]+1 if j > 0 else 1 + dp[i % 2][j][1] = dp[(i-1) % 2][j][1]+1 if i > 0 else 1 + dp[i % 2][j][2] = dp[(i-1) % 2][j-1][2]+1 if (i > 0 and j > 0) else 1 + dp[i % 2][j][3] = dp[(i-1) % 2][j+1][3]+1 if (i > 0 and j < len(M[0])-1) else 1 + result = max(result, max(dp[i % 2][j])) + return result diff --git a/Python/longest-palindrome.py b/Python/longest-palindrome.py new file mode 100644 index 000000000..9f672acf5 --- /dev/null +++ b/Python/longest-palindrome.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# Given a string which consists of lowercase or uppercase letters, +# find the length of the longest palindromes that can be built with those letters. +# +# This is case sensitive, for example "Aa" is not considered a palindrome here. +# +# Note: +# Assume the length of given string will not exceed 1,010. +# +# Example: +# +# Input: +# "abccccdd" +# +# Output: +# 7 +# +# Explanation: +# One longest palindrome that can be built is "dccaccd", whose length is 7. +import collections + + +class Solution(object): + def longestPalindrome(self, s): + """ + :type s: str + :rtype: int + """ + odds = 0 + for k, v in collections.Counter(s).iteritems(): + odds += v & 1 + return len(s) - odds + int(odds > 0) + + def longestPalindrome2(self, s): + """ + :type s: str + :rtype: int + """ + odd = sum(map(lambda x: x & 1, collections.Counter(s).values())) + return len(s) - odd + int(odd > 0) diff --git a/Python/longest-palindromic-subsequence.py b/Python/longest-palindromic-subsequence.py new file mode 100644 index 000000000..2c0cd5f5c --- /dev/null +++ b/Python/longest-palindromic-subsequence.py @@ -0,0 +1,37 @@ +# Time: O(n^2) +# Space: O(n) + +# Given a string s, find the longest palindromic subsequence's length in s. +# You may assume that the maximum length of s is 1000. +# +# Example 1: +# Input: +# +# "bbbab" +# Output: +# 4 +# One possible longest palindromic subsequence is "bbbb". +# Example 2: +# Input: +# +# "cbbd" +# Output: +# 2 + +class Solution(object): + def longestPalindromeSubseq(self, s): + """ + :type s: str + :rtype: int + """ + if s == s[::-1]: + return len(s) + + dp = [[1] * len(s) for _ in xrange(2)] + for i in reversed(xrange(len(s))): + for j in xrange(i+1, len(s)): + if s[i] == s[j]: + dp[i%2][j] = 2 + dp[(i+1)%2][j-1] if i+1 <= j-1 else 2 + else: + dp[i%2][j] = max(dp[(i+1)%2][j], dp[i%2][j-1]) + return dp[0][-1] diff --git a/Python/longest-palindromic-substring.py b/Python/longest-palindromic-substring.py index e882d6bf6..2c0f238d9 100644 --- a/Python/longest-palindromic-substring.py +++ b/Python/longest-palindromic-substring.py @@ -8,40 +8,44 @@ # Manacher's Algorithm # http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html -class Solution: +class Solution(object): def longestPalindrome(self, s): - string = self.preProcess(s) - palindrome = [0] * len(string) + """ + :type s: str + :rtype: str + """ + def preProcess(s): + if not s: + return ['^', '$'] + T = ['^'] + for c in s: + T += ['#', c] + T += ['#', '$'] + return T + + T = preProcess(s) + P = [0] * len(T) center, right = 0, 0 - for i in xrange(1, len(string) - 1): + for i in xrange(1, len(T) - 1): i_mirror = 2 * center - i if right > i: - palindrome[i] = min(right - i, palindrome[i_mirror]) + P[i] = min(right - i, P[i_mirror]) else: - palindrome[i] = 0 + P[i] = 0 - while string[i + 1 + palindrome[i]] == string[i - 1 - palindrome[i]]: - palindrome[i] += 1 + while T[i + 1 + P[i]] == T[i - 1 - P[i]]: + P[i] += 1 - if i + palindrome[i] > right: - center, right = i, i + palindrome[i] + if i + P[i] > right: + center, right = i, i + P[i] - max_len, max_center = 0, 0 - for i in xrange(1, len(string) - 1): - if palindrome[i] > max_len: - max_len = palindrome[i] - max_center = i - start = (max_center - 1 - max_len) / 2 - return s[start : start + max_len] - - def preProcess(self, s): - if len(s) == 0: - return "^$" - string = "^" - for i in s: - string += "#" + i - string += "#$" - return string + max_i = 0 + for i in xrange(1, len(T) - 1): + if P[i] > P[max_i]: + max_i = i + start = (max_i - 1 - P[max_i]) / 2 + return s[start : start + P[max_i]] + if __name__ == "__main__": - print Solution().longestPalindrome("abb") \ No newline at end of file + print Solution().longestPalindrome("abb") diff --git a/Python/longest-repeating-character-replacement.py b/Python/longest-repeating-character-replacement.py new file mode 100644 index 000000000..64810432f --- /dev/null +++ b/Python/longest-repeating-character-replacement.py @@ -0,0 +1,57 @@ +# Time: O(n) +# Space: O(1) + +# Given a string that consists of only uppercase English letters, +# you can replace any letter in the string with another letter at most k times. +# Find the length of a longest substring containing all repeating letters +# you can get after performing the above operations. +# +# Note: +# Both the string's length and k will not exceed 104. +# +# Example 1: +# +# Input: +# s = "ABAB", k = 2 +# +# Output: +# 4 +# +# Explanation: +# Replace the two 'A's with two 'B's or vice versa. +# Example 2: +# +# Input: +# s = "AABABBA", k = 1 +# +# Output: +# 4 +# +# Explanation: +# Replace the one 'A' in the middle with 'B' and form "AABBBBA". +# The substring "BBBB" has the longest repeating letters, which is 4. + +class Solution(object): + def characterReplacement(self, s, k): + """ + :type s: str + :type k: int + :rtype: int + """ + res = 0 + + cnts = [0] * 26 + times, i, j = k, 0, 0 + while j < len(s): + cnts[ord(s[j]) - ord('A')] += 1 + if s[j] != s[i]: + times -= 1 + if times < 0: + res = max(res, j - i) + while i < j and times < 0: + cnts[ord(s[i]) - ord('A')] -= 1 + i += 1 + times = k - (j - i + 1 - cnts[ord(s[i]) - ord('A')]) + j += 1 + + return max(res, j - i + min(i, times)) diff --git a/Python/longest-substring-with-at-least-k-repeating-characters.py b/Python/longest-substring-with-at-least-k-repeating-characters.py new file mode 100644 index 000000000..d17bae4d2 --- /dev/null +++ b/Python/longest-substring-with-at-least-k-repeating-characters.py @@ -0,0 +1,55 @@ +# Time: O(26 * n) = O(n) +# Space: O(26) = O(1) + +# Find the length of the longest substring T of a given string +# (consists of lowercase letters only) such that every character in T +# appears no less than k times. +# +# Example 1: +# +# Input: +# s = "aaabb", k = 3 +# +# Output: +# 3 +# +# The longest substring is "aaa", as 'a' is repeated 3 times. +# Example 2: +# +# Input: +# s = "ababbc", k = 2 +# +# Output: +# 5 +# +# The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times. + +# Recursive solution. +class Solution(object): + def longestSubstring(self, s, k): + """ + :type s: str + :type k: int + :rtype: int + """ + def longestSubstringHelper(s, k, start, end): + count = [0] * 26 + for i in xrange(start, end): + count[ord(s[i]) - ord('a')] += 1 + max_len = 0 + i = start + while i < end: + while i < end and count[ord(s[i]) - ord('a')] < k: + i += 1 + j = i + while j < end and count[ord(s[j]) - ord('a')] >= k: + j += 1 + + if i == start and j == end: + return end - start + + max_len = max(max_len, longestSubstringHelper(s, k, i, j)) + i = j + return max_len + + return longestSubstringHelper(s, k, 0, len(s)) diff --git a/Python/longest-substring-with-at-most-k-distinct-characters.py b/Python/longest-substring-with-at-most-k-distinct-characters.py new file mode 100644 index 000000000..a5f6d0c45 --- /dev/null +++ b/Python/longest-substring-with-at-most-k-distinct-characters.py @@ -0,0 +1,24 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def lengthOfLongestSubstringKDistinct(self, s, k): + """ + :type s: str + :type k: int + :rtype: int + """ + longest, start, distinct_count, visited = 0, 0, 0, [0 for _ in xrange(256)] + for i, char in enumerate(s): + if visited[ord(char)] == 0: + distinct_count += 1 + visited[ord(char)] += 1 + + while distinct_count > k: + visited[ord(s[start])] -= 1 + if visited[ord(s[start])] == 0: + distinct_count -= 1 + start += 1 + + longest = max(longest, i - start + 1) + return longest diff --git a/Python/longest-substring-with-at-most-two-distinct-characters.py b/Python/longest-substring-with-at-most-two-distinct-characters.py index 6ffc113c2..3a58b3024 100644 --- a/Python/longest-substring-with-at-most-two-distinct-characters.py +++ b/Python/longest-substring-with-at-most-two-distinct-characters.py @@ -1,4 +1,4 @@ -# Time: O(n^2) +# Time: O(n) # Space: O(1) # # Given a string, find the length of the longest substring T @@ -29,4 +29,4 @@ def lengthOfLongestSubstringTwoDistinct(self, s): return longest if __name__ == "__main__": - print Solution().lengthOfLongestSubstringTwoDistinct("eceba") \ No newline at end of file + print Solution().lengthOfLongestSubstringTwoDistinct("eceba") diff --git a/Python/longest-uncommon-subsequence-i.py b/Python/longest-uncommon-subsequence-i.py new file mode 100644 index 000000000..007cee665 --- /dev/null +++ b/Python/longest-uncommon-subsequence-i.py @@ -0,0 +1,35 @@ +# Time: O(min(a, b)) +# Space: O(1) + +# Given a group of two strings, you need to find the longest uncommon subsequence of this group of two strings. +# The longest uncommon subsequence is defined as the longest subsequence of one of these strings +# and this subsequence should not be any subsequence of the other strings. +# +# A subsequence is a sequence that can be derived from one sequence +# by deleting some characters without changing the order of the remaining elements. +# Trivially, any string is a subsequence of itself and an empty string is a subsequence of any string. +# +# The input will be two strings, and the output needs to be the length of the longest uncommon subsequence. +# If the longest uncommon subsequence doesn't exist, return -1. +# +# Example 1: +# Input: "aba", "cdc" +# Output: 3 +# Explanation: The longest uncommon subsequence is "aba" (or "cdc"), +# because "aba" is a subsequence of "aba", +# but not a subsequence of any other strings in the group of two strings. +# Note: +# +# Both strings' lengths will not exceed 100. +# Only letters from a ~ z will appear in input strings. + +class Solution(object): + def findLUSlength(self, a, b): + """ + :type a: str + :type b: str + :rtype: int + """ + if a == b: + return -1 + return max(len(a), len(b)) diff --git a/Python/longest-uncommon-subsequence-ii.py b/Python/longest-uncommon-subsequence-ii.py new file mode 100644 index 000000000..c73d74a3f --- /dev/null +++ b/Python/longest-uncommon-subsequence-ii.py @@ -0,0 +1,49 @@ +# Time: O(l * n^2) +# Space: O(1) + +# Given a list of strings, you need to find the longest uncommon subsequence among them. +# The longest uncommon subsequence is defined as the longest subsequence of one of these strings +# and this subsequence should not be any subsequence of the other strings. +# +# A subsequence is a sequence that can be derived from one sequence +# by deleting some characters without changing the order of the remaining elements. +# Trivially, any string is a subsequence of itself and an empty string is a subsequence of any string. +# +# The input will be a list of strings, and the output needs to be the length of the longest uncommon subsequence. +# If the longest uncommon subsequence doesn't exist, return -1. +# +# Example 1: +# Input: "aba", "cdc", "eae" +# Output: 3 +# Note: +# +# All the given strings' lengths will not exceed 10. +# The length of the given list will be in the range of [2, 50]. + +class Solution(object): + def findLUSlength(self, strs): + """ + :type strs: List[str] + :rtype: int + """ + def isSubsequence(a, b): + i = 0 + for j in xrange(len(b)): + if i >= len(a): + break + if a[i] == b[j]: + i += 1 + return i == len(a) + + strs.sort(key=len, reverse=True) + for i in xrange(len(strs)): + all_of = True + for j in xrange(len(strs)): + if len(strs[j]) < len(strs[i]): + break + if i != j and isSubsequence(strs[i], strs[j]): + all_of = False + break + if all_of: + return len(strs[i]) + return -1 diff --git a/Python/longest-univalue-path.py b/Python/longest-univalue-path.py new file mode 100644 index 000000000..795f4d485 --- /dev/null +++ b/Python/longest-univalue-path.py @@ -0,0 +1,57 @@ +# Time: O(n) +# Space: O(h) + +# Given a binary tree, find the length of the longest path +# where each node in the path has the same value. This path may or may not pass through the root. +# +# Note: The length of path between two nodes is represented by the number of edges between them. +# +# Example 1: +# Input: +# +# 5 +# / \ +# 4 5 +# / \ \ +# 1 1 5 +# Output: +# 2 +# +# Example 2: +# Input: +# +# 1 +# / \ +# 4 5 +# / \ \ +# 4 4 5 +# Output: +# 2 +# +# Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestUnivaluePath(self, root): + """ + :type root: TreeNode + :rtype: int + """ + result = [0] + def dfs(node): + if not node: + return 0 + left, right = dfs(node.left), dfs(node.right) + left = (left+1) if node.left and node.left.val == node.val else 0 + right = (right+1) if node.right and node.right.val == node.val else 0 + result[0] = max(result[0], left+right) + return max(left, right) + + dfs(root) + return result[0] diff --git a/Python/longest-valid-parentheses.py b/Python/longest-valid-parentheses.py index 8d8b1647e..dd0376eb8 100644 --- a/Python/longest-valid-parentheses.py +++ b/Python/longest-valid-parentheses.py @@ -9,35 +9,28 @@ # Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4. # -class Solution: - # @param s, a string - # @return an integer +class Solution(object): def longestValidParentheses(self, s): - longest = 0 - - start, depth = -1, 0 - for i in xrange(len(s)): - if s[i] == "(": - depth += 1 - else: - depth -= 1 - if depth < 0: - start, depth = i, 0 - elif depth == 0: - longest = max(longest, i - start) - - start, depth = len(s), 0 - for i in reversed(xrange(len(s))): - if s[i] == ")": - depth += 1 - else: - depth -= 1 - if depth < 0: - start, depth = i, 0 - elif depth == 0: - longest = max(longest, start - i) - - return longest + """ + :type s: str + :rtype: int + """ + def length(it, start, c): + depth, longest = 0, 0 + for i in it: + if s[i] == c: + depth += 1 + else: + depth -= 1 + if depth < 0: + start, depth = i, 0 + elif depth == 0: + longest = max(longest, abs(i - start)) + return longest + + return max(length(xrange(len(s)), -1, '('), \ + length(reversed(xrange(len(s))), len(s), ')')) + # Time: O(n) # Space: O(n) @@ -49,11 +42,11 @@ def longestValidParentheses(self, s): for i in xrange(len(s)): if s[i] == '(': indices.append(i) - elif len(indices) == 0: + elif not indices: last = i else: indices.pop() - if len(indices) == 0: + if not indices: longest = max(longest, i - last) else: longest = max(longest, i - indices[-1]) diff --git a/Python/longest-word-in-dictionary-through-deleting.py b/Python/longest-word-in-dictionary-through-deleting.py new file mode 100644 index 000000000..7b69a39d0 --- /dev/null +++ b/Python/longest-word-in-dictionary-through-deleting.py @@ -0,0 +1,43 @@ +# Time: O(dlogd) +# Space: O(1) + +# Given a string and a string dictionary, +# find the longest string in the dictionary +# that can be formed by deleting some characters of the given string. +# If there are more than one possible results, +# return the longest word with the smallest lexicographical order. +# If there is no possible result, return the empty string. +# +# Example 1: +# Input: +# s = "abpcplea", d = ["ale","apple","monkey","plea"] +# +# Output: +# "apple" +# Example 2: +# Input: +# s = "abpcplea", d = ["a","b","c"] +# +# Output: +# "a" +# Note: +# All the strings in the input will only contain lower-case letters. +# The size of the dictionary won't exceed 1,000. +# The length of all the strings in the input won't exceed 1,000. + +class Solution(object): + def findLongestWord(self, s, d): + """ + :type s: str + :type d: List[str] + :rtype: str + """ + d.sort(key = lambda x: (-len(x), x)) + for word in d: + i = 0 + for c in s: + if i < len(word) and word[i] == c: + i += 1 + if i == len(word): + return word + return "" diff --git a/Python/longest-word-in-dictionary.py b/Python/longest-word-in-dictionary.py new file mode 100644 index 000000000..b6f900c14 --- /dev/null +++ b/Python/longest-word-in-dictionary.py @@ -0,0 +1,50 @@ +# Time: O(n), n is the total sum of the lengths of words +# Space: O(t), t is the number of nodes in trie + +# Given a list of strings words representing an English Dictionary, +# find the longest word in words that can be built one character at a time by other words in words. +# If there is more than one possible answer, return the longest word with the smallest lexicographical order. +# +# If there is no answer, return the empty string. +# Example 1: +# Input: +# words = ["w","wo","wor","worl", "world"] +# Output: "world" +# Explanation: +# The word "world" can be built one character at a time by "w", "wo", "wor", and "worl". +# +# Example 2: +# Input: +# words = ["a", "banana", "app", "appl", "ap", "apply", "apple"] +# Output: "apple" +# Explanation: +# Both "apply" and "apple" can be built from other words in the dictionary. +# However, "apple" is lexicographically smaller than "apply". +# +# Note: +# - All the strings in the input will only contain lowercase letters. +# - The length of words will be in the range [1, 1000]. +# - The length of words[i] will be in the range [1, 30]. + +class Solution(object): + def longestWord(self, words): + """ + :type words: List[str] + :rtype: str + """ + _trie = lambda: collections.defaultdict(_trie) + trie = _trie() + for i, word in enumerate(words): + reduce(dict.__getitem__, word, trie)["_end"] = i + + # DFS + stack = trie.values() + result = "" + while stack: + curr = stack.pop() + if "_end" in curr: + word = words[curr["_end"]] + if len(word) > len(result) or (len(word) == len(result) and word < result): + result = word + stack += [curr[letter] for letter in curr if letter != "_end"] + return result diff --git a/Python/lowest-common-ancestor-of-a-binary-search-tree.py b/Python/lowest-common-ancestor-of-a-binary-search-tree.py new file mode 100644 index 000000000..fab9e33a7 --- /dev/null +++ b/Python/lowest-common-ancestor-of-a-binary-search-tree.py @@ -0,0 +1,40 @@ +# Time: O(n) +# Space: O(1) +# +# Given a binary search tree (BST), find the lowest common ancestor (LCA) +# of two given nodes in the BST. +# +# According to the definition of LCA on Wikipedia: “The lowest common ancestor +# is defined between two nodes v and w as the lowest node in T that has both v +# and w as descendants (where we allow a node to be a descendant of itself).” +# +# _______6______ +# / \ +# ___2__ ___8__ +# / \ / \ +# 0 _4 7 9 +# / \ +# 3 5 +# For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. +# Another example is LCA of nodes 2 and 4 is 2, since a node can be a +# descendant of itself according to the LCA definition. +# +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @param {TreeNode} p + # @param {TreeNode} q + # @return {TreeNode} + def lowestCommonAncestor(self, root, p, q): + s, b = sorted([p.val, q.val]) + while not s <= root.val <= b: + # Keep searching since root is outside of [s, b]. + root = root.left if s <= root.val else root.right + # s <= root.val <= b. + return root diff --git a/Python/lowest-common-ancestor-of-a-binary-tree.py b/Python/lowest-common-ancestor-of-a-binary-tree.py new file mode 100644 index 000000000..190662c69 --- /dev/null +++ b/Python/lowest-common-ancestor-of-a-binary-tree.py @@ -0,0 +1,47 @@ +# Time: O(n) +# Space: O(h) +# +# Given a binary tree, find the lowest common ancestor (LCA) +# of two given nodes in the tree. +# +# According to the definition of LCA on Wikipedia: “The lowest +# common ancestor is defined between two nodes v and w as the +# lowest node in T that has both v and w as descendants (where we +# allow a node to be a descendant of itself).” +# +# _______3______ +# / \ +# ___5__ ___1__ +# / \ / \ +# 6 _2 0 8 +# / \ +# 7 4 +# For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. +# Another example is LCA of nodes 5 and 4 is 5, since a node can be a +# descendant of itself according to the LCA definition. +# +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @param {TreeNode} p + # @param {TreeNode} q + # @return {TreeNode} + def lowestCommonAncestor(self, root, p, q): + if root in (None, p, q): + return root + + left, right = [self.lowestCommonAncestor(child, p, q) \ + for child in (root.left, root.right)] + # 1. If the current subtree contains both p and q, + # return their LCA. + # 2. If only one of them is in that subtree, + # return that one of them. + # 3. If neither of them is in that subtree, + # return the node of that subtree. + return root if left and right else left or right diff --git a/Python/lru-cache.py b/Python/lru-cache.py index b0aa97aa1..bc618fd31 100644 --- a/Python/lru-cache.py +++ b/Python/lru-cache.py @@ -1,23 +1,39 @@ -# Time: O(1) -# Space: O(n) +# Time: O(1), per operation. +# Space: O(k), k is the capacity of cache. + +# Design and implement a data structure for Least Recently Used (LRU) cache. +# It should support the following operations: get and put. +# +# get(key) - Get the value (will always be positive) of the key if the key exists in the cache, +# otherwise return -1. +# put(key, value) - Set or insert the value if the key is not already present. +# When the cache reached its capacity, +# it should invalidate the least recently used item before inserting a new item. +# +# Follow up: +# Could you do both operations in O(1) time complexity? # -# Design and implement a data structure for Least Recently Used (LRU) cache. -# It should support the following operations: get and set. -# -# get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. -# -# set(key, value) - Set or insert the value if the key is not already present. -# When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. +# Example: # +# LRUCache cache = new LRUCache( 2 /* capacity */ ); +# +# cache.put(1, 1); +# cache.put(2, 2); +# cache.get(1); // returns 1 +# cache.put(3, 3); // evicts key 2 +# cache.get(2); // returns -1 (not found) +# cache.put(4, 4); // evicts key 1 +# cache.get(1); // returns -1 (not found) +# cache.get(3); // returns 3 -class ListNode: +class ListNode(object): def __init__(self, key, val): self.val = val self.key = key self.next = None self.prev = None -class LinkedList: +class LinkedList(object): def __init__(self): self.head = None self.tail = None @@ -41,7 +57,7 @@ def delete(self, node): self.tail = node.prev del node -class LRUCache: +class LRUCache(object): # @param capacity, an integer def __init__(self, capacity): @@ -68,7 +84,7 @@ def get(self, key): # @param key, an integer # @param value, an integer # @return nothing - def set(self, key, val): + def put(self, key, val): if key in self.dict: self.list.delete(self.dict[key]) elif len(self.dict) == self.capacity: @@ -78,7 +94,7 @@ def set(self, key, val): import collections -class LRUCache2: +class LRUCache2(object): def __init__(self, capacity): self.cache = collections.OrderedDict() self.capacity = capacity @@ -91,12 +107,13 @@ def get(self, key): self.cache[key] = val return val - def set(self, key, value): + def put(self, key, value): if key in self.cache: del self.cache[key] elif len(self.cache) == self.capacity: self.cache.popitem(last=False) - self.cache[key] = value + self.cache[key] = value + if __name__ == "__main__": cache = LRUCache(3) @@ -106,4 +123,4 @@ def set(self, key, value): print cache.get(1) cache.set(4, 4) print cache.get(2) - \ No newline at end of file + diff --git a/Python/magical-string.py b/Python/magical-string.py new file mode 100644 index 000000000..299d6b842 --- /dev/null +++ b/Python/magical-string.py @@ -0,0 +1,45 @@ +# Time: O(n) +# Space: O(logn) + +# A magical string S consists of only '1' and '2' and obeys the following rules: +# +# The string S is magical because concatenating +# the number of contiguous occurrences of characters '1' and '2' generates the string S itself. +# +# The first few elements of string S is the following: S = "1221121221221121122……" +# +# If we group the consecutive '1's and '2's in S, it will be: +# +# 1 22 11 2 1 22 1 22 11 2 11 22 ...... +# +# and the occurrences of '1's or '2's in each group are: +# +# 1 2 2 1 1 2 1 2 2 1 2 2 ...... +# +# You can see that the occurrence sequence above is the S itself. +# +# Given an integer N as input, return the number of '1's in the first N number in the magical string S. +# +# Note: N will not exceed 100,000. +# +# Example 1: +# Input: 6 +# Output: 3 +# Explanation: The first 6 elements of magical string S is "12211" and it contains three 1's, so return 3. + +# the solution comes from https://discuss.leetcode.com/topic/75242/o-log-n-space-using-recursive-generators +class Solution(object): + def magicalString(self, n): + """ + :type n: int + :rtype: int + """ + def gen(): # see figure 1 on page 3 of http://www.emis.ams.org/journals/JIS/VOL15/Nilsson/nilsson5.pdf + for c in 1, 2, 2: + yield c + for i, c in enumerate(gen()): + if i > 1: + for _ in xrange(c): + yield i % 2 + 1 + + return sum(c & 1 for c in itertools.islice(gen(), n)) diff --git a/Python/majority-element-ii.py b/Python/majority-element-ii.py new file mode 100644 index 000000000..849bde6cb --- /dev/null +++ b/Python/majority-element-ii.py @@ -0,0 +1,52 @@ +# Time: O(n) +# Space: O(1) + +# Given an integer array of size n, +# find all elements that appear more than [n/3] times. +# The algorithm should run in linear time and in O(1) space. +import collections + + +class Solution(object): + def majorityElement(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + k, n, cnts = 3, len(nums), collections.defaultdict(int) + + for i in nums: + cnts[i] += 1 + # Detecting k items in cnts, at least one of them must have exactly + # one in it. We will discard those k items by one for each. + # This action keeps the same mojority numbers in the remaining numbers. + # Because if x / n > 1 / k is true, then (x - 1) / (n - k) > 1 / k is also true. + if len(cnts) == k: + for j in cnts.keys(): + cnts[j] -= 1 + if cnts[j] == 0: + del cnts[j] + + # Resets cnts for the following counting. + for i in cnts.keys(): + cnts[i] = 0 + + # Counts the occurrence of each candidate integer. + for i in nums: + if i in cnts: + cnts[i] += 1 + + # Selects the integer which occurs > [n / k] times. + result = [] + for i in cnts.keys(): + if cnts[i] > n / k: + result.append(i) + + return result + + def majorityElement2(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + return [i[0] for i in collections.Counter(nums).items() if i[1] > len(nums) / 3] diff --git a/Python/majority-element.py b/Python/majority-element.py index bfd6f0dc0..f39f2c0d7 100644 --- a/Python/majority-element.py +++ b/Python/majority-element.py @@ -5,16 +5,19 @@ # The majority element is the element that appears more than [n/2] times. # # You may assume that the array is non-empty and the majority element always exist in the array. -# +import collections + class Solution: - # @param num, a list of integers - # @return an integer - def majorityElement(self, num): + def majorityElement(self, nums): + """ + :type nums: List[int] + :rtype: int + """ idx, cnt = 0, 1 - for i in xrange(1, len(num)): - if num[idx] == num[i]: + for i in xrange(1, len(nums)): + if nums[idx] == nums[i]: cnt += 1 else: cnt -= 1 @@ -22,7 +25,14 @@ def majorityElement(self, num): idx = i cnt = 1 - return num[idx] + return nums[idx] + + def majorityElement2(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return sorted(collections.Counter(nums).items(), key=lambda a: a[1], reverse=True)[0][0] if __name__ == "__main__": print Solution().majorityElement([1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 6]) \ No newline at end of file diff --git a/Python/map-sum-pairs.py b/Python/map-sum-pairs.py new file mode 100644 index 000000000..391bff1c1 --- /dev/null +++ b/Python/map-sum-pairs.py @@ -0,0 +1,70 @@ +# Time: O(n), n is the length of key +# Space: O(t), t is the number of nodes in trie + +# Implement a MapSum class with insert, and sum methods. +# +# For the method insert, you'll be given a pair of (string, integer). +# The string represents the key and the integer represents the value. +# If the key already existed, then the original key-value pair will be overridden to the new one. +# +# For the method sum, you'll be given a string representing the prefix, +# and you need to return the sum of all the pairs' value whose key starts with the prefix. +# +# Example 1: +# Input: insert("apple", 3), Output: Null +# Input: sum("ap"), Output: 3 +# Input: insert("app", 2), Output: Null +# Input: sum("ap"), Output: 5 + +class MapSum(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + _trie = lambda: collections.defaultdict(_trie) + self.__root = _trie() + + + def insert(self, key, val): + """ + :type key: str + :type val: int + :rtype: void + """ + # Time: O(n) + curr = self.__root + for c in key: + curr = curr[c] + delta = val + if "_end" in curr: + delta -= curr["_end"] + + curr = self.__root + for c in key: + curr = curr[c] + if "_count" in curr: + curr["_count"] += delta + else: + curr["_count"] = delta + curr["_end"] = val + + + def sum(self, prefix): + """ + :type prefix: str + :rtype: int + """ + # Time: O(n) + curr = self.__root + for c in prefix: + if c not in curr: + return 0 + curr = curr[c] + return curr["_count"] + + +# Your MapSum object will be instantiated and called as such: +# obj = MapSum() +# obj.insert(key,val) +# param_2 = obj.sum(prefix) diff --git a/Python/matchsticks-to-square.py b/Python/matchsticks-to-square.py new file mode 100644 index 000000000..9728cccff --- /dev/null +++ b/Python/matchsticks-to-square.py @@ -0,0 +1,60 @@ +# Time: O(n * s * 2^n), s is the number of subset of which sum equals to side length. +# Space: O(n * (2^n + s)) + +# Remember the story of Little Match Girl? By now, you know exactly +# what matchsticks the little match girl has, please find out a way +# you can make one square by using up all those matchsticks. +# You should not break any stick, but you can link them up, +# and each matchstick must be used exactly one time. +# +# Your input will be several matchsticks the girl has, +# represented with their stick length. +# Your output will either be true or false, +# to represent whether you could make one square using all the matchsticks the little match girl has. +# +# Example 1: +# Input: [1,1,2,2,2] +# Output: true +# +# Explanation: You can form a square with length 2, one side of the square came two sticks with length 1. +# Example 2: +# Input: [3,3,3,3,4] +# Output: false +# +# Explanation: You cannot find a way to form a square with all the matchsticks. +# Note: +# The length sum of the given matchsticks is in the range of 0 to 10^9. +# The length of the given matchstick array will not exceed 15. + +class Solution(object): + def makesquare(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + total_len = sum(nums) + if total_len % 4: + return False + + side_len = total_len / 4 + fullset = (1 << len(nums)) - 1 + + used_subsets = [] + valid_half_subsets = [0] * (1 << len(nums)) + + for subset in xrange(fullset+1): + subset_total_len = 0 + for i in xrange(len(nums)): + if subset & (1 << i): + subset_total_len += nums[i] + + if subset_total_len == side_len: + for used_subset in used_subsets: + if (used_subset & subset) == 0: + valid_half_subset = used_subset | subset + valid_half_subsets[valid_half_subset] = True + if valid_half_subsets[fullset ^ valid_half_subset]: + return True + used_subsets.append(subset) + + return False diff --git a/Python/max-area-of-island.py b/Python/max-area-of-island.py new file mode 100644 index 000000000..ee8db6201 --- /dev/null +++ b/Python/max-area-of-island.py @@ -0,0 +1,55 @@ +# Time: O(m * n) +# Space: O(m * n), the max depth of dfs may be m * n + +# Given a non-empty 2D array grid of 0's and 1's, +# an island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) +# You may assume all four edges of the grid are surrounded by water. +# +# Find the maximum area of an island in the given 2D array. (If there is no island, the maximum area is 0.) +# +# Example 1: +# [[0,0,1,0,0,0,0,1,0,0,0,0,0], +# [0,0,0,0,0,0,0,1,1,1,0,0,0], +# [0,1,1,0,1,0,0,0,0,0,0,0,0], +# [0,1,0,0,1,1,0,0,1,0,1,0,0], +# [0,1,0,0,1,1,0,0,1,1,1,0,0], +# [0,0,0,0,0,0,0,0,0,0,1,0,0], +# [0,0,0,0,0,0,0,1,1,1,0,0,0], +# [0,0,0,0,0,0,0,1,1,0,0,0,0]] +# +# Given the above grid, return 6. Note the answer is not 11, +# because the island must be connected 4-directionally. +# +# Example 2: +# [[0,0,0,0,0,0,0,0]] +# +# Given the above grid, return 0. +# +# Note: The length of each dimension in the given grid does not exceed 50. + +class Solution(object): + def maxAreaOfIsland(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + directions = [[-1, 0], [ 1, 0], [ 0, 1], [ 0, -1]] + + def dfs(i, j, grid, area): + if not (0 <= i < len(grid) and \ + 0 <= j < len(grid[0]) and \ + grid[i][j] > 0): + return False + grid[i][j] *= -1 + area[0] += 1 + for d in directions: + dfs(i+d[0], j+d[1], grid, area) + return True + + result = 0 + for i in xrange(len(grid)): + for j in xrange(len(grid[0])): + area = [0] + if dfs(i, j, grid, area): + result = max(result, area[0]) + return result diff --git a/Python/max-consecutive-ones-ii.py b/Python/max-consecutive-ones-ii.py new file mode 100644 index 000000000..a674080fd --- /dev/null +++ b/Python/max-consecutive-ones-ii.py @@ -0,0 +1,17 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def findMaxConsecutiveOnes(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result, prev, curr = 0, 0, 0 + for n in nums: + if n == 0: + result = max(result, prev+curr+1) + prev, curr = curr, 0 + else: + curr += 1 + return min(max(result, prev+curr+1), len(nums)) diff --git a/Python/max-consecutive-ones.py b/Python/max-consecutive-ones.py new file mode 100644 index 000000000..88f26e1f2 --- /dev/null +++ b/Python/max-consecutive-ones.py @@ -0,0 +1,26 @@ +# Time: O(n) +# Space: O(1) + +# Given a binary array, find the maximum number of consecutive 1s in this array. +# +# Example 1: +# Input: [1,1,0,1,1,1] +# Output: 3 +# Explanation: The first two digits or the last three digits are consecutive 1s. +# The maximum number of consecutive 1s is 3. +# Note: +# +# The input array will only contain 0 and 1. +# The length of input array is a positive integer and will not exceed 10,000 + +class Solution(object): + def findMaxConsecutiveOnes(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result, local_max = 0, 0 + for n in nums: + local_max = (local_max + 1 if n else 0) + result = max(result, local_max) + return result diff --git a/Python/max-points-on-a-line.py b/Python/max-points-on-a-line.py index cf47fa2ac..67b31f245 100644 --- a/Python/max-points-on-a-line.py +++ b/Python/max-points-on-a-line.py @@ -10,14 +10,16 @@ def __init__(self, a=0, b=0): self.x = a self.y = b -class Solution: - # @param points, a list of Points - # @return an integer +class Solution(object): def maxPoints(self, points): + """ + :type points: List[Point] + :rtype: int + """ max_points = 0 for i, start in enumerate(points): - slope_count, same, current_max = {}, 1, 0 - for j in range(i + 1, len(points)): + slope_count, same = collections.defaultdict(int), 1 + for j in xrange(i + 1, len(points)): end = points[j] if start.x == end.x and start.y == end.y: same += 1 @@ -25,15 +27,13 @@ def maxPoints(self, points): slope = float("inf") if start.x - end.x != 0: slope = (start.y - end.y) * 1.0 / (start.x - end.x) - if slope not in slope_count: - slope_count[slope] = 1 - else: - slope_count[slope] += 1 - + slope_count[slope] += 1 + + current_max = same for slope in slope_count: current_max = max(current_max, slope_count[slope] + same) - max_points = max(max_points, current_max, same) + max_points = max(max_points, current_max) return max_points diff --git a/Python/max-stack.py b/Python/max-stack.py new file mode 100644 index 000000000..ee10bd1d8 --- /dev/null +++ b/Python/max-stack.py @@ -0,0 +1,82 @@ +# Time: push: O(1) +# pop: O(n), there is no built-in SortedDict in python. If applied, it could be reduced to O(logn) +# popMax: O(n) +# top: O(1) +# peekMax: O(1) +# Space: O(n), n is the number of values in the current stack + +class MaxStack(object): + + def __init__(self): + """ + initialize your data structure here. + """ + self.__idx_to_val = collections.defaultdict(int) + self.__val_to_idxs = collections.defaultdict(list) + self.__top = None + self.__max = None + + + def push(self, x): + """ + :type x: int + :rtype: void + """ + idx = self.__val_to_idxs[self.__top][-1]+1 if self.__val_to_idxs else 0 + self.__idx_to_val[idx] = x + self.__val_to_idxs[x].append(idx) + self.__top = x + self.__max = max(self.__max, x) + + + def pop(self): + """ + :rtype: int + """ + val = self.__top + self.__remove(val) + return val + + + def top(self): + """ + :rtype: int + """ + return self.__top + + + def peekMax(self): + """ + :rtype: int + """ + return self.__max + + + def popMax(self): + """ + :rtype: int + """ + val = self.__max + self.__remove(val) + return val + + + def __remove(self, val): + idx = self.__val_to_idxs[val][-1] + self.__val_to_idxs[val].pop(); + if not self.__val_to_idxs[val]: + del self.__val_to_idxs[val] + del self.__idx_to_val[idx] + if val == self.__top: + self.__top = self.__idx_to_val[max(self.__idx_to_val.keys())] if self.__idx_to_val else None + if val == self.__max: + self.__max = max(self.__val_to_idxs.keys()) if self.__val_to_idxs else None + + +# Your MaxStack object will be instantiated and called as such: +# obj = MaxStack() +# obj.push(x) +# param_2 = obj.pop() +# param_3 = obj.top() +# param_4 = obj.peekMax() +# param_5 = obj.popMax() diff --git a/Python/max-sum-of-sub-matrix-no-larger-than-k.py b/Python/max-sum-of-sub-matrix-no-larger-than-k.py new file mode 100644 index 000000000..d21b3fe78 --- /dev/null +++ b/Python/max-sum-of-sub-matrix-no-larger-than-k.py @@ -0,0 +1,139 @@ +# Time: O(min(m, n)^2 * max(m, n) * log(max(m, n))) +# Space: O(max(m, n)) + +# Given a non-empty 2D matrix matrix and an integer k, +# find the max sum of a rectangle in the matrix such that its sum is no larger than k. +# +# Example: +# Given matrix = [ +# [1, 0, 1], +# [0, -2, 3] +# ] +# k = 2 +# The answer is 2. Because the sum of rectangle [[0, 1], [-2, 3]] +# is 2 and 2 is the max number no larger than k (k = 2). +# +# Note: +# The rectangle inside the matrix must have an area > 0. +# What if the number of rows is much larger than the number of columns? + +# Time: O(min(m, n)^2 * max(m, n)^2) +# Space: O(max(m, n)) + +# Given a non-empty 2D matrix matrix and an integer k, +# find the max sum of a rectangle in the matrix such that its sum is no larger than k. +# +# Example: +# Given matrix = [ +# [1, 0, 1], +# [0, -2, 3] +# ] +# k = 2 +# The answer is 2. Because the sum of rectangle [[0, 1], [-2, 3]] +# is 2 and 2 is the max number no larger than k (k = 2). +# +# Note: +# The rectangle inside the matrix must have an area > 0. +# What if the number of rows is much larger than the number of columns? + +# Time: O(min(m, n)^2 * max(m, n)^2) +# Space: O(max(m, n)) +from bisect import bisect_left, insort + +class Solution(object): + def maxSumSubmatrix(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + if not matrix: + return 0 + + m = min(len(matrix), len(matrix[0])) + n = max(len(matrix), len(matrix[0])) + result = float("-inf") + + for i in xrange(m): + sums = [0] * n + for j in xrange(i, m): + for l in xrange(n): + sums[l] += matrix[j][l] if m == len(matrix) else matrix[l][j] + + # Find the max subarray no more than K. + accu_sum_set, accu_sum = [0], 0 + for sum in sums: + accu_sum += sum + it = bisect_left(accu_sum_set, accu_sum - k) # Time: O(logn) + if it != len(accu_sum_set): + result = max(result, accu_sum - accu_sum_set[it]) + insort(accu_sum_set, accu_sum) # Time: O(n) + + return result + + +# Time: O(min(m, n)^2 * max(m, n) * log(max(m, n))) ~ O(min(m, n)^2 * max(m, n)^2) +# Space: O(max(m, n)) +class Solution_TLE(object): + def maxSumSubmatrix(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + class BST(object): # not avl, rbtree + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + def insert(self, val): # Time: O(h) = O(logn) ~ O(n) + curr = self + while curr: + if curr.val >= val: + if curr.left: + curr = curr.left + else: + curr.left = BST(val) + return + else: + if curr.right: + curr = curr.right + else: + curr.right = BST(val) + return + + def lower_bound(self, val): # Time: O(h) = O(logn) ~ O(n) + result, curr = None, self + while curr: + if curr.val >= val: + result, curr = curr, curr.left + else: + curr = curr.right + return result + + + if not matrix: + return 0 + + m = min(len(matrix), len(matrix[0])) + n = max(len(matrix), len(matrix[0])) + result = float("-inf") + + for i in xrange(m): + sums = [0] * n + for j in xrange(i, m): + for l in xrange(n): + sums[l] += matrix[j][l] if m == len(matrix) else matrix[l][j] + + # Find the max subarray no more than K. + accu_sum_set = BST(0) + accu_sum = 0 + for sum in sums: + accu_sum += sum + node = accu_sum_set.lower_bound(accu_sum - k); + if node: + result = max(result, accu_sum - node.val) + accu_sum_set.insert(accu_sum) + + return result diff --git a/Python/maximal-rectangle.py b/Python/maximal-rectangle.py index 05a99c943..85420c608 100644 --- a/Python/maximal-rectangle.py +++ b/Python/maximal-rectangle.py @@ -1,15 +1,53 @@ # Time: O(n^2) # Space: O(n) -# + # Given a 2D binary matrix filled with 0's and 1's, # find the largest rectangle containing all ones and return its area. -# -class Solution: - # @param matrix, a list of lists of 1 length string - # @return an integer +# Ascending stack solution. +class Solution(object): + def maximalRectangle(self, matrix): + """ + :type matrix: List[List[str]] + :rtype: int + """ + def largestRectangleArea(heights): + increasing, area, i = [], 0, 0 + while i <= len(heights): + if not increasing or (i < len(heights) and heights[i] > heights[increasing[-1]]): + increasing.append(i) + i += 1 + else: + last = increasing.pop() + if not increasing: + area = max(area, heights[last] * i) + else: + area = max(area, heights[last] * (i - increasing[-1] - 1 )) + return area + + if not matrix: + return 0 + + result = 0 + heights = [0] * len(matrix[0]) + for i in xrange(len(matrix)): + for j in xrange(len(matrix[0])): + heights[j] = heights[j] + 1 if matrix[i][j] == '1' else 0 + result = max(result, largestRectangleArea(heights)) + + return result + + +# Time: O(n^2) +# Space: O(n) +# DP solution. +class Solution2(object): def maximalRectangle(self, matrix): - if len(matrix) == 0: + """ + :type matrix: List[List[str]] + :rtype: int + """ + if not matrix: return 0 result = 0 diff --git a/Python/maximal-square.py b/Python/maximal-square.py new file mode 100644 index 000000000..2f95f9b99 --- /dev/null +++ b/Python/maximal-square.py @@ -0,0 +1,127 @@ +# Time: O(n^2) +# Space: O(n) +# +# Given a 2D binary matrix filled with 0's and 1's, +# find the largest square containing all 1's and return its area. +# +# For example, given the following matrix: +# +# 1 0 1 0 0 +# 1 0 1 1 1 +# 1 1 1 1 1 +# 1 0 0 1 0 +# Return 4. +# + +# DP with sliding window. +class Solution: + # @param {character[][]} matrix + # @return {integer} + def maximalSquare(self, matrix): + if not matrix: + return 0 + + m, n = len(matrix), len(matrix[0]) + size = [[0 for j in xrange(n)] for i in xrange(2)] + max_size = 0 + + for j in xrange(n): + if matrix[0][j] == '1': + size[0][j] = 1 + max_size = max(max_size, size[0][j]) + + for i in xrange(1, m): + if matrix[i][0] == '1': + size[i % 2][0] = 1 + else: + size[i % 2][0] = 0 + for j in xrange(1, n): + if matrix[i][j] == '1': + size[i % 2][j] = min(size[i % 2][j - 1], \ + size[(i - 1) % 2][j], \ + size[(i - 1) % 2][j - 1]) + 1 + max_size = max(max_size, size[i % 2][j]) + else: + size[i % 2][j] = 0 + + return max_size * max_size + + +# Time: O(n^2) +# Space: O(n^2) +# DP. +class Solution2: + # @param {character[][]} matrix + # @return {integer} + def maximalSquare(self, matrix): + if not matrix: + return 0 + + m, n = len(matrix), len(matrix[0]) + size = [[0 for j in xrange(n)] for i in xrange(m)] + max_size = 0 + + for j in xrange(n): + if matrix[0][j] == '1': + size[0][j] = 1 + max_size = max(max_size, size[0][j]) + + for i in xrange(1, m): + if matrix[i][0] == '1': + size[i][0] = 1 + else: + size[i][0] = 0 + for j in xrange(1, n): + if matrix[i][j] == '1': + size[i][j] = min(size[i][j - 1], \ + size[i - 1][j], \ + size[i - 1][j - 1]) + 1 + max_size = max(max_size, size[i][j]) + else: + size[i][j] = 0 + + return max_size * max_size + + +# Time: O(n^2) +# Space: O(n^2) +# DP. +class Solution3: + # @param {character[][]} matrix + # @return {integer} + def maximalSquare(self, matrix): + if not matrix: + return 0 + + H, W = 0, 1 + # DP table stores (h, w) for each (i, j). + table = [[[0, 0] for j in xrange(len(matrix[0]))] \ + for i in xrange(len(matrix))] + for i in reversed(xrange(len(matrix))): + for j in reversed(xrange(len(matrix[i]))): + # Find the largest h such that (i, j) to (i + h - 1, j) are feasible. + # Find the largest w such that (i, j) to (i, j + w - 1) are feasible. + if matrix[i][j] == '1': + h, w = 1, 1 + if i + 1 < len(matrix): + h = table[i + 1][j][H] + 1 + if j + 1 < len(matrix[i]): + w = table[i][j + 1][W] + 1 + table[i][j] = [h, w] + + # A table stores the length of largest square for each (i, j). + s = [[0 for j in xrange(len(matrix[0]))] \ + for i in xrange(len(matrix))] + max_square_area = 0 + for i in reversed(xrange(len(matrix))): + for j in reversed(xrange(len(matrix[i]))): + side = min(table[i][j][H], table[i][j][W]) + if matrix[i][j] == '1': + # Get the length of largest square with bottom-left corner (i, j). + if i + 1 < len(matrix) and j + 1 < len(matrix[i + 1]): + side = min(s[i + 1][j + 1] + 1, side) + s[i][j] = side + max_square_area = max(max_square_area, side * side) + + return max_square_area; + diff --git a/Python/maximum-average-subarray-i.py b/Python/maximum-average-subarray-i.py new file mode 100644 index 000000000..7f39cf7a6 --- /dev/null +++ b/Python/maximum-average-subarray-i.py @@ -0,0 +1,30 @@ +# Time: O(n) +# Space: O(1) + +# Given an array consisting of n integers, +# find the contiguous subarray of given length k that has the maximum average value. +# And you need to output the maximum average value. +# +# Example 1: +# Input: [1,12,-5,-6,50,3], k = 4 +# Output: 12.75 +# Explanation: Maximum average is (12-5-6+50)/4 = 51/4 = 12.75 +# Note: +# 1 <= k <= n <= 30,000. +# Elements of the given array will be in the range [-10,000, 10,000]. + +class Solution(object): + def findMaxAverage(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: float + """ + total = 0 + for i in xrange(k): + total += nums[i] + result = total + for i in xrange(k, len(nums)): + total += nums[i] - nums[i-k] + result = max(result, total) + return float(result) / k diff --git a/Python/maximum-average-subarray-ii.py b/Python/maximum-average-subarray-ii.py new file mode 100644 index 000000000..1c2ae6a50 --- /dev/null +++ b/Python/maximum-average-subarray-ii.py @@ -0,0 +1,28 @@ +# Time: O(n) +# Space: O(n) + +class Solution(object): + def findMaxAverage(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: float + """ + def getDelta(avg, nums, k): + accu = [0.0] * (len(nums) + 1) + minval_pos = None + delta = 0.0 + for i in xrange(len(nums)): + accu[i+1] = nums[i] + accu[i] - avg + if i >= (k-1): + if minval_pos == None or accu[i-k+1] < accu[minval_pos]: + minval_pos = i-k+1 + if accu[i+1] - accu[minval_pos] >= 0: + delta = max(delta, (accu[i+1] - accu[minval_pos]) / (i+1 - minval_pos)) + return delta + + left, delta = min(nums), float("inf") + while delta > 1e-5: + delta = getDelta(left, nums, k) + left += delta + return left diff --git a/Python/maximum-binary-tree.py b/Python/maximum-binary-tree.py new file mode 100644 index 000000000..e32134c97 --- /dev/null +++ b/Python/maximum-binary-tree.py @@ -0,0 +1,49 @@ +# Time: O(n) +# Space: O(n) + +# Given an integer array with no duplicates. +# A maximum tree building on this array is defined as follow: +# +# The root is the maximum number in the array. +# The left subtree is the maximum tree constructed from left part subarray divided by the maximum number. +# The right subtree is the maximum tree constructed from right part subarray divided by the maximum number. +# Construct the maximum tree by the given array and output the root node of this tree. +# +# Example 1: +# Input: [3,2,1,6,0,5] +# Output: return the tree root node representing the following tree: +# +# 6 +# / \ +# 3 5 +# \ / +# 2 0 +# \ +# 1 +# Note: +# The size of the given array will be in the range [1,1000]. + + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def constructMaximumBinaryTree(self, nums): + """ + :type nums: List[int] + :rtype: TreeNode + """ + # https://github.com/kamyu104/LintCode/blob/master/C++/max-tree.cpp + nodeStack = [] + for num in nums: + node = TreeNode(num); + while nodeStack and num > nodeStack[-1].val: + node.left = nodeStack.pop() + if nodeStack: + nodeStack[-1].right = node + nodeStack.append(node) + return nodeStack[0] diff --git a/Python/maximum-depth-of-binary-tree.py b/Python/maximum-depth-of-binary-tree.py index 14c258da1..016f720a6 100644 --- a/Python/maximum-depth-of-binary-tree.py +++ b/Python/maximum-depth-of-binary-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, find its maximum depth. # @@ -27,4 +27,4 @@ def maxDepth(self, root): root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) - print Solution().maxDepth(root) \ No newline at end of file + print Solution().maxDepth(root) diff --git a/Python/maximum-distance-in-arrays.py b/Python/maximum-distance-in-arrays.py new file mode 100644 index 000000000..8f300bca8 --- /dev/null +++ b/Python/maximum-distance-in-arrays.py @@ -0,0 +1,17 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def maxDistance(self, arrays): + """ + :type arrays: List[List[int]] + :rtype: int + """ + result, min_val, max_val = 0, arrays[0][0], arrays[0][-1] + for i in xrange(1, len(arrays)): + result = max(result, \ + max(max_val - arrays[i][0], \ + arrays[i][-1] - min_val)) + min_val = min(min_val, arrays[i][0]) + max_val = max(max_val, arrays[i][-1]) + return result diff --git a/Python/maximum-gap.py b/Python/maximum-gap.py index 6bc30d14f..2003ab711 100644 --- a/Python/maximum-gap.py +++ b/Python/maximum-gap.py @@ -1,6 +1,6 @@ # Time: O(n) # Space: O(n) -# + # Given an unsorted array, find the maximum difference between # # the successive elements in its sorted form. @@ -12,68 +12,71 @@ # You may assume all elements in the array are non-negative integers # # and fit in the 32-bit signed integer range. -# # bucket sort -class Solution: - # @param num, a list of integer - # @return an integer - def maximumGap(self, num): - if len(num) < 2: +# Time: O(n) +# Space: O(n) +class Solution(object): + def maximumGap(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if len(nums) < 2: return 0 - unique_num = self.removeDuplicate(num) - - max_val, min_val = max(unique_num), min(unique_num) - gap = (max_val - min_val) / (len(unique_num) - 1) + # Init bucket. + max_val, min_val = max(nums), min(nums) + gap = max(1, (max_val - min_val) / (len(nums) - 1)) bucket_size = (max_val - min_val) / gap + 1 - max_bucket = [float("-inf") for _ in xrange(bucket_size)] - min_bucket = [float("inf") for _ in xrange(bucket_size)] + bucket = [{'min':float("inf"), 'max':float("-inf")} \ + for _ in xrange(bucket_size)] - for i in unique_num: - if i in (max_val, min_val): + # Find the bucket where the n should be put. + for n in nums: + # min_val / max_val is in the first / last bucket. + if n in (max_val, min_val): continue - idx = (i - min_val) / gap - max_bucket[idx] = max(max_bucket[idx], i) - min_bucket[idx] = min(min_bucket[idx], i) + i = (n - min_val) / gap + bucket[i]['min'] = min(bucket[i]['min'], n) + bucket[i]['max'] = max(bucket[i]['max'], n) - max_gap = 0 - pre = min_val + # Count each bucket gap between the first and the last bucket. + max_gap, pre_bucket_max = 0, min_val for i in xrange(bucket_size): - if max_bucket[i] == float("-inf") and min_bucket[i] == float("inf"): + # Skip the bucket it empty. + if bucket[i]['min'] == float("inf") and \ + bucket[i]['max'] == float("-inf"): continue - max_gap = max(max_gap, min_bucket[i] - pre) - pre = max_bucket[i] - max_gap = max(max_gap, max_val - pre) + max_gap = max(max_gap, bucket[i]['min'] - pre_bucket_max) + pre_bucket_max = bucket[i]['max'] + # Count the last bucket. + max_gap = max(max_gap, max_val - pre_bucket_max) return max_gap - - def removeDuplicate(self, num): - dict = {} - unique_num = [] - for i in num: - if i not in dict: - unique_num.append(i) - dict[i] = True - return unique_num + # Time: O(nlogn) # Space: O(n) -class Solution2: - # @param num, a list of integer - # @return an integer - def maximumGap(self, num): - if len(num) < 2: +class Solution2(object): + def maximumGap(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + + if len(nums) < 2: return 0 - num.sort() - pre = num[0] + nums.sort() + pre = nums[0] max_gap = float("-inf") - for i in num: + for i in nums: max_gap = max(max_gap, i - pre) pre = i return max_gap - + + if __name__ == "__main__": print Solution().maximumGap([3, 1, 1, 1, 5, 5, 5, 5]) diff --git a/Python/maximum-length-of-pair-chain.py b/Python/maximum-length-of-pair-chain.py new file mode 100644 index 000000000..c6586aa3c --- /dev/null +++ b/Python/maximum-length-of-pair-chain.py @@ -0,0 +1,32 @@ +# Time: O(nlogn) +# Space: O(1) + +# You are given n pairs of numbers. +# In every pair, the first number is always smaller than the second number. +# +# Now, we define a pair (c, d) can follow another pair (a, b) +# if and only if b < c. Chain of pairs can be formed in this fashion. +# +# Given a set of pairs, find the length longest chain which can be formed. +# You needn't use up all the given pairs. You can select pairs in any order. +# +# Example 1: +# Input: [[1,2], [2,3], [3,4]] +# Output: 2 +# Explanation: The longest chain is [1,2] -> [3,4] +# Note: +# The number of given pairs will be in the range [1, 1000]. + +class Solution(object): + def findLongestChain(self, pairs): + """ + :type pairs: List[List[int]] + :rtype: int + """ + pairs.sort(key=lambda x: x[1]) + cnt, i = 0, 0 + for j in xrange(len(pairs)): + if j == 0 or pairs[i][1] < pairs[j][0]: + cnt += 1 + i = j + return cnt diff --git a/Python/maximum-length-of-repeated-subarray.py b/Python/maximum-length-of-repeated-subarray.py new file mode 100644 index 000000000..be588aa9c --- /dev/null +++ b/Python/maximum-length-of-repeated-subarray.py @@ -0,0 +1,112 @@ +# Time: O(m * n) +# Space: O(min(m, n)) + +# Given two integer arrays A and B, +# return the maximum length of an subarray that appears in both arrays. +# +# Example 1: +# Input: +# A: [1,2,3,2,1] +# B: [3,2,1,4,7] +# Output: 3 +# Explanation: +# The repeated subarray with maximum length is [3, 2, 1]. +# Note: +# 1 <= len(A), len(B) <= 1000 +# 0 <= A[i], B[i] < 100 + +# dp solution (3752 ms) +class Solution(object): + def findLength(self, A, B): + """ + :type A: List[int] + :type B: List[int] + :rtype: int + """ + if len(A) < len(B): return findLength(B, A) + result = 0 + dp = [[0] * (len(B)+1) for _ in xrange(2)] + for i in xrange(len(A)): + for j in xrange(len(B)): + if A[i] == B[j]: + dp[(i+1)%2][j+1] = dp[i%2][j]+1 + else: + dp[(i+1)%2][j+1] = 0 + result = max(result, max(dp[(i+1)%2])) + return result + + +# Time: O(m * n * log(min(m, n))) +# Space: O(min(m, n)) +# Binary search + rolling hash solution (226 ms) +class Solution2(object): + def findLength(self, A, B): + """ + :type A: List[int] + :type B: List[int] + :rtype: int + """ + if len(A) > len(B): return findLength(B, A) + M, p = 10**9+7, 113 + p_inv = pow(p, M-2, M) + def check(guess): + def rolling_hashes(source, length): + if length == 0: + yield 0, 0 + return + + val, power = 0, 1 + for i, x in enumerate(source): + val = (val + x*power) % M + if i < length - 1: + power = (power*p) % M + else: + yield val, i-(length-1) + val = (val-source[i-(length-1)])*p_inv % M + + hashes = collections.defaultdict(list) + for hash_val, i in rolling_hashes(A, guess): + hashes[hash_val].append(i) + for hash_val, j in rolling_hashes(B, guess): + if any(A[i:i+guess] == B[j:j+guess] for i in hashes[hash_val]): + return True + return False + + left, right = 0, min(len(A), len(B)) + 1 + while left < right: + mid = left + (right-left)/2 + if not check(mid): # find the min idx such that check(idx) == false + right = mid + else: + left = mid+1 + return left-1 + + +# Time: O(m * n * min(m, n) * log(min(m, n))) +# Space: O(min(m^2, n^2)) +# Binary search (122 ms) +class Solution3(object): + def findLength(self, A, B): + """ + :type A: List[int] + :type B: List[int] + :rtype: int + """ + if len(A) > len(B): return findLength(B, A) + + def check(length): + lookup = set(A[i:i+length] \ + for i in xrange(len(A)-length+1)) + return any(B[j:j+length] in lookup \ + for j in xrange(len(B)-length+1)) + + A = ''.join(map(chr, A)) + B = ''.join(map(chr, B)) + left, right = 0, min(len(A), len(B)) + 1 + while left < right: + mid = left + (right-left)/2 + if not check(mid): # find the min idx such that check(idx) == false + right = mid + else: + left = mid+1 + return left-1 diff --git a/Python/maximum-product-of-three-numbers.py b/Python/maximum-product-of-three-numbers.py new file mode 100644 index 000000000..73a618c2d --- /dev/null +++ b/Python/maximum-product-of-three-numbers.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# Given an integer array, find three numbers whose product is maximum and output the maximum product. +# +# Example 1: +# Input: [1,2,3] +# Output: 6 +# Example 2: +# Input: [1,2,3,4] +# Output: 24 +# Note: +# The length of the given array will be in range [3,104] and all elements are in the range [-1000, 1000]. +# Multiplication of any three numbers in the input won't exceed the range of 32-bit signed integer. + +class Solution(object): + def maximumProduct(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + min1, min2 = float("inf"), float("inf") + max1, max2, max3 = float("-inf"), float("-inf"), float("-inf") + + for n in nums: + if n <= min1: + min2 = min1 + min1 = n + elif n <= min2: + min2 = n + + if n >= max1: + max3 = max2 + max2 = max1 + max1 = n + elif n >= max2: + max3 = max2 + max2 = n + elif n >= max3: + max3 = n + + return max(min1 * min2 * max1, max1 * max2 * max3) diff --git a/Python/maximum-product-of-word-lengths.py b/Python/maximum-product-of-word-lengths.py new file mode 100644 index 000000000..ddc03bd4b --- /dev/null +++ b/Python/maximum-product-of-word-lengths.py @@ -0,0 +1,87 @@ +# Time: O(n) ~ O(n^2) +# Space: O(n) + +# Given a string array words, find the maximum value of +# length(word[i]) * length(word[j]) where the two words +# do not share common letters. You may assume that each +# word will contain only lower case letters. If no such +# two words exist, return 0. +# +# Example 1: +# Given ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"] +# Return 16 +# The two words can be "abcw", "xtfn". +# +# Example 2: +# Given ["a", "ab", "abc", "d", "cd", "bcd", "abcd"] +# Return 4 +# The two words can be "ab", "cd". +# +# Example 3: +# Given ["a", "aa", "aaa", "aaaa"] +# Return 0 +# No such pair of words. +# +# Follow up: +# Could you do better than O(n2), where n is the number of words? + +# Counting Sort + Pruning + Bit Manipulation +class Solution(object): + def maxProduct(self, words): + """ + :type words: List[str] + :rtype: int + """ + def counting_sort(words): + k = 1000 # k is max length of words in the dictionary + buckets = [[] for _ in xrange(k)] + for word in words: + buckets[len(word)].append(word) + res = [] + for i in reversed(xrange(k)): + if buckets[i]: + res += buckets[i] + return res + + words = counting_sort(words) + bits = [0] * len(words) + for i, word in enumerate(words): + for c in word: + bits[i] |= (1 << (ord(c) - ord('a'))) + + max_product = 0 + for i in xrange(len(words) - 1): + if len(words[i]) ** 2 <= max_product: + break + for j in xrange(i + 1, len(words)): + if len(words[i]) * len(words[j]) <= max_product: + break + if not (bits[i] & bits[j]): + max_product = len(words[i]) * len(words[j]) + return max_product + +# Time: O(nlogn) ~ O(n^2) +# Space: O(n) +# Sorting + Pruning + Bit Manipulation +class Solution2(object): + def maxProduct(self, words): + """ + :type words: List[str] + :rtype: int + """ + words.sort(key=lambda x: len(x), reverse=True) + bits = [0] * len(words) + for i, word in enumerate(words): + for c in word: + bits[i] |= (1 << (ord(c) - ord('a'))) + + max_product = 0 + for i in xrange(len(words) - 1): + if len(words[i]) ** 2 <= max_product: + break + for j in xrange(i + 1, len(words)): + if len(words[i]) * len(words[j]) <= max_product: + break + if not (bits[i] & bits[j]): + max_product = len(words[i]) * len(words[j]) + return max_product diff --git a/Python/maximum-size-subarray-sum-equals-k.py b/Python/maximum-size-subarray-sum-equals-k.py new file mode 100644 index 000000000..393505529 --- /dev/null +++ b/Python/maximum-size-subarray-sum-equals-k.py @@ -0,0 +1,21 @@ +# Time: O(n) +# Space: O(n) + +class Solution(object): + def maxSubArrayLen(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + sums = {} + cur_sum, max_len = 0, 0 + for i in xrange(len(nums)): + cur_sum += nums[i] + if cur_sum == k: + max_len = i + 1 + elif cur_sum - k in sums: + max_len = max(max_len, i - sums[cur_sum - k]) + if cur_sum not in sums: + sums[cur_sum] = i # Only keep the smallest index. + return max_len diff --git a/Python/maximum-subarray.py b/Python/maximum-subarray.py index 50ff72130..9c5f5ede9 100644 --- a/Python/maximum-subarray.py +++ b/Python/maximum-subarray.py @@ -12,15 +12,20 @@ # If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle. # -class Solution: - # @param A, a list of integers - # @return an integer - def maxSubArray(self, A): +class Solution(object): + def maxSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if max(nums) < 0: + return max(nums) global_max, local_max = float("-inf"), 0 - for x in A: + for x in nums: local_max = max(0, local_max + x) global_max = max(global_max, local_max) return global_max + if __name__ == "__main__": - print Solution().maxSubArray([-2,1,-3,4,-1,2,1,-5,4]) \ No newline at end of file + print Solution().maxSubArray([-2,1,-3,4,-1,2,1,-5,4]) diff --git a/Python/maximum-sum-of-3-non-overlapping-subarrays.py b/Python/maximum-sum-of-3-non-overlapping-subarrays.py new file mode 100644 index 000000000..7defc2939 --- /dev/null +++ b/Python/maximum-sum-of-3-non-overlapping-subarrays.py @@ -0,0 +1,62 @@ +# Time: O(n) +# Space: O(n) + +# In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum. +# +# Each subarray will be of size k, and we want to maximize the sum of all 3*k entries. +# +# Return the result as a list of indices representing the starting position of each interval (0-indexed). +# If there are multiple answers, return the lexicographically smallest one. +# +# Example: +# Input: [1,2,1,2,6,7,5,1], 2 +# Output: [0, 3, 5] + # +# Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5]. +# We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger. +# +# Note: +# - nums.length will be between 1 and 20000. +# - nums[i] will be between 1 and 65535. +# - k will be between 1 and floor(nums.length / 3). + +class Solution(object): + def maxSumOfThreeSubarrays(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + n = len(nums) + accu = [0] + for num in nums: + accu.append(accu[-1]+num) + + left_pos = [0] * n + total = accu[k]-accu[0] + for i in xrange(k, n): + if accu[i+1]-accu[i+1-k] > total: + left_pos[i] = i+1-k + total = accu[i+1]-accu[i+1-k] + else: + left_pos[i] = left_pos[i-1] + + right_pos = [n-k] * n + total = accu[n]-accu[n-k] + for i in reversed(xrange(n-k)): + if accu[i+k]-accu[i] > total: + right_pos[i] = i; + total = accu[i+k]-accu[i] + else: + right_pos[i] = right_pos[i+1] + + result, max_sum = [], 0 + for i in xrange(k, n-2*k+1): + left, right = left_pos[i-1], right_pos[i+k] + total = (accu[i+k]-accu[i]) + \ + (accu[left+k]-accu[left]) + \ + (accu[right+k]-accu[right]) + if total > max_sum: + max_sum = total + result = [left, i, right] + return result diff --git a/Python/maximum-swap.py b/Python/maximum-swap.py new file mode 100644 index 000000000..c82f48198 --- /dev/null +++ b/Python/maximum-swap.py @@ -0,0 +1,33 @@ +# Time: O(logn), logn is the length of the number string +# Space: O(logn) + +# Given a non-negative integer, you could swap two digits at most once +# to get the maximum valued number. Return the maximum valued number you could get. +# +# Example 1: +# Input: 2736 +# Output: 7236 +# Explanation: Swap the number 2 and the number 7. +# Example 2: +# Input: 9973 +# Output: 9973 +# Explanation: No swap. +# Note: +# The given number is in the range [0, 10^8] + +class Solution(object): + def maximumSwap(self, num): + """ + :type num: int + :rtype: int + """ + digits = list(str(num)) + left, right = 0, 0 + max_idx = len(digits)-1 + for i in reversed(xrange(len(digits))): + if digits[i] > digits[max_idx]: + max_idx = i + elif digits[max_idx] > digits[i]: + left, right = i, max_idx + digits[left], digits[right] = digits[right], digits[left] + return int("".join(digits)) diff --git a/Python/maximum-vacation-days.py b/Python/maximum-vacation-days.py new file mode 100644 index 000000000..ad87e5d9c --- /dev/null +++ b/Python/maximum-vacation-days.py @@ -0,0 +1,21 @@ +# Time: O(n^2 * k) +# Space: O(k) + +class Solution(object): + def maxVacationDays(self, flights, days): + """ + :type flights: List[List[int]] + :type days: List[List[int]] + :rtype: int + """ + if not days or not flights: + return 0 + dp = [[0] * len(days) for _ in xrange(2)] + for week in reversed(xrange(len(days[0]))): + for cur_city in xrange(len(days)): + dp[week % 2][cur_city] = days[cur_city][week] + dp[(week+1) % 2][cur_city] + for dest_city in xrange(len(days)): + if flights[cur_city][dest_city] == 1: + dp[week % 2][cur_city] = max(dp[week % 2][cur_city], \ + days[dest_city][week] + dp[(week+1) % 2][dest_city]) + return dp[0][0] diff --git a/Python/maximum-width-of-binary-tree.py b/Python/maximum-width-of-binary-tree.py new file mode 100644 index 000000000..4bb5125c0 --- /dev/null +++ b/Python/maximum-width-of-binary-tree.py @@ -0,0 +1,83 @@ +# Time: O(n) +# Space: O(h) + +# Given a binary tree, write a function to get the maximum width of the given tree. +# The width of a tree is the maximum width among all levels. The binary tree has the same structure +# as a full binary tree, but some nodes are null. +# +# The width of one level is defined as the length between the end-nodes +# (the leftmost and right most non-null nodes in the level, +# where the null nodes between the end-nodes are also counted into the length calculation. +# +# Example 1: +# Input: +# +# 1 +# / \ +# 3 2 +# / \ \ +# 5 3 9 +# +# Output: 4 +# Explanation: The maximum width existing in the third level with the length 4 (5,3,null,9). +# Example 2: +# Input: +# +# 1 +# / +# 3 +# / \ +# 5 3 +# +# Output: 2 +# Explanation: The maximum width existing in the third level with the length 2 (5,3). +# Example 3: +# Input: +# +# 1 +# / \ +# 3 2 +# / +# 5 +# +# Output: 2 +# Explanation: The maximum width existing in the second level with the length 2 (3,2). +# Example 4: +# Input: +# +# 1 +# / \ +# 3 2 +# / \ +# 5 9 +# / \ +# 6 7 +# Output: 8 +# Explanation:The maximum width existing in the fourth level with the length 8 (6,null,null,null,null,null,null,7). +# +# Note: Answer will in the range of 32-bit signed integer. +# +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def widthOfBinaryTree(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def dfs(node, i, depth, leftmosts): + if not node: + return 0 + if depth >= len(leftmosts): + leftmosts.append(i) + return max(i-leftmosts[depth]+1, \ + dfs(node.left, i*2, depth+1, leftmosts), \ + dfs(node.right, i*2+1, depth+1, leftmosts)) + + leftmosts = [] + return dfs(root, 1, 0, leftmosts) diff --git a/Python/maximum-xor-of-two-numbers-in-an-array.py b/Python/maximum-xor-of-two-numbers-in-an-array.py new file mode 100644 index 000000000..20f541afe --- /dev/null +++ b/Python/maximum-xor-of-two-numbers-in-an-array.py @@ -0,0 +1,36 @@ +# Time: O(n) +# Space: O(n) + +# Given a non-empty array of numbers, a0, a1, a2, ... , an-1, where 0 <= ai < 231. +# +# Find the maximum result of ai XOR aj, where 0 <= i, j < n. +# +# Could you do this in O(n) runtime? +# +# Example: +# +# Input: [3, 10, 5, 25, 2, 8] +# +# Output: 28 +# +# Explanation: The maximum result is 5 ^ 25 = 28. + +class Solution(object): + def findMaximumXOR(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result = 0 + + for i in reversed(xrange(32)): + result <<= 1 + prefixes = set() + for n in nums: + prefixes.add(n >> i) + for p in prefixes: + if (result | 1) ^ p in prefixes: + result += 1 + break + + return result diff --git a/Python/median-of-two-sorted-arrays.py b/Python/median-of-two-sorted-arrays.py index 47f6c6862..14ce80108 100644 --- a/Python/median-of-two-sorted-arrays.py +++ b/Python/median-of-two-sorted-arrays.py @@ -1,72 +1,88 @@ -# Time: O(log(m + n)) -# Space: O(log(m + n)) -# -# There are two sorted arrays A and B of size m and n respectively. -# Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). -# +# Time: O(log(min(m, n))) +# Space: O(1) + +# There are two sorted arrays nums1 and nums2 of size m and n respectively. +# Find the median of the two sorted arrays. +# The overall run time complexity should be O(log (m+n)). -class Solution: - # @return a float - def findMedianSortedArrays(self, A, B): - lenA, lenB = len(A), len(B) - if (lenA + lenB) % 2 == 1: - return self.getKth(A, 0, B, 0, (lenA + lenB)/2 + 1) +class Solution(object): + def findMedianSortedArrays(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: float + """ + len1, len2 = len(nums1), len(nums2) + if (len1 + len2) % 2 == 1: + return self.getKth(nums1, nums2, (len1 + len2)/2 + 1) else: - return (self.getKth(A, 0, B, 0, (lenA + lenB)/2) + self.getKth(A, 0, B, 0, (lenA + lenB)/2 + 1)) * 0.5 - - def getKth(self, A, i, B, j, k): - lenA, lenB = len(A) - i, len(B) - j - if lenA > lenB: - return self.getKth(B, j, A, i, k) - - if lenA == 0: - return B[j + k - 1] - - if k == 1: - return min(A[i], B[j]) - - pa = min(k/2, lenA) - pb = k - pa - - if A[i + pa - 1] < B[j + pb - 1]: - return self.getKth(A, i + pa, B, j , k - pa) - elif A[i + pa - 1] > B[j + pb - 1]: - return self.getKth(A, i, B, j + pb, k - pb) - else: - return A[i + pa - 1] + return (self.getKth(nums1, nums2, (len1 + len2)/2) + \ + self.getKth(nums1, nums2, (len1 + len2)/2 + 1)) * 0.5 -# using list slicing (O(k)) may be slower than solution1 -class Solution2: - # @return a float - def findMedianSortedArrays(self, A, B): - lenA, lenB = len(A), len(B) - if (lenA + lenB) % 2 == 1: - return self.getKth(A, B, (lenA + lenB)/2 + 1) - else: - return (self.getKth(A, B, (lenA + lenB)/2) + self.getKth(A, B, (lenA + lenB)/2 + 1)) * 0.5 - def getKth(self, A, B, k): - lenA, lenB = len(A), len(B) - if lenA > lenB: + m, n = len(A), len(B) + if m > n: return self.getKth(B, A, k) - - if lenA == 0: - return B[k - 1] - - if k == 1: - return min(A[0], B[0]) - - pa = min(k/2, lenA) - pb = k - pa - - if A[pa - 1] < B[pb - 1]: - return self.getKth(A[pa:], B, k - pa) - elif A[pa - 1] > B[pb - 1]: - return self.getKth(A, B[pb:], k - pb) + + left, right = 0, m + while left < right: + mid = left + (right - left) / 2 + if 0 <= k - 1 - mid < n and A[mid] >= B[k - 1 - mid]: + right = mid + else: + left = mid + 1 + + Ai_minus_1 = A[left - 1] if left - 1 >= 0 else float("-inf") + Bj = B[k - 1 - left] if k - 1 - left >= 0 else float("-inf") + + return max(Ai_minus_1, Bj) + + +# Time: O(log(max(m, n)) * log(max_val - min_val)) +# Space: O(1) +# Generic solution. +class Solution_Generic(object): + def findMedianSortedArrays(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: float + """ + len1, len2 = len(nums1), len(nums2) + if (len1 + len2) % 2 == 1: + return self.getKth([nums1, nums2], (len1 + len2)/2 + 1) else: - return A[pa - 1] - + return (self.getKth([nums1, nums2], (len1 + len2)/2) + \ + self.getKth([nums1, nums2], (len1 + len2)/2 + 1)) * 0.5 + + def getKth(self, arrays, k): + def binary_search(array, left, right, target, compare): + while left <= right: + mid = left + (right - left) / 2 + if compare(array, mid, target): + right = mid - 1 + else: + left = mid + 1 + return left + + def match(arrays, num, target): + res = 0 + for array in arrays: + if array: + res += len(array) - binary_search(array, 0, len(array) - 1, num, \ + lambda array, x, y: array[x] > y) + return res < target + + left, right = float("inf"), float("-inf") + for array in arrays: + if array: + left = min(left, array[0]) + right = max(right, array[-1]) + + return binary_search(arrays, left, right, k, match) + + if __name__ == "__main__": print Solution().findMedianSortedArrays([1, 3, 5, 7], [2, 4, 6]) print Solution().findMedianSortedArrays([1, 3, 5], [2, 4, 6]) - \ No newline at end of file + diff --git a/Python/meeting-rooms-ii.py b/Python/meeting-rooms-ii.py new file mode 100644 index 000000000..5d6903447 --- /dev/null +++ b/Python/meeting-rooms-ii.py @@ -0,0 +1,34 @@ +# Time: O(nlogn) +# Space: O(n) + +# Definition for an interval. +# class Interval: +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution: + # @param {Interval[]} intervals + # @return {integer} + def minMeetingRooms(self, intervals): + starts, ends = [], [] + for i in intervals: + starts.append(i.start) + ends.append(i.end) + + starts.sort() + ends.sort() + + s, e = 0, 0 + min_rooms, cnt_rooms = 0, 0 + while s < len(starts): + if starts[s] < ends[e]: + cnt_rooms += 1 # Acquire a room. + # Update the min number of rooms. + min_rooms = max(min_rooms, cnt_rooms) + s += 1 + else: + cnt_rooms -= 1 # Release a room. + e += 1 + + return min_rooms diff --git a/Python/meeting-rooms.py b/Python/meeting-rooms.py new file mode 100644 index 000000000..f8ef52f66 --- /dev/null +++ b/Python/meeting-rooms.py @@ -0,0 +1,19 @@ +# Time: O(nlogn) +# Space: O(n) +# +# Definition for an interval. +# class Interval: +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution: + # @param {Interval[]} intervals + # @return {boolean} + def canAttendMeetings(self, intervals): + intervals.sort(key=lambda x: x.start) + + for i in xrange(1, len(intervals)): + if intervals[i].start < intervals[i-1].end: + return False + return True diff --git a/Python/merge-intervals.py b/Python/merge-intervals.py index 49641bb7d..953798275 100644 --- a/Python/merge-intervals.py +++ b/Python/merge-intervals.py @@ -1,4 +1,4 @@ -# Time: O(n^2) +# Time: O(nlogn) # Space: O(1) # # Given a collection of intervals, merge all overlapping intervals. @@ -17,15 +17,18 @@ def __init__(self, s=0, e=0): def __repr__(self): return "[{}, {}]".format(self.start, self.end) -class Solution: - # @param intervals, a list of Interval - # @return a list of Interval + +class Solution(object): def merge(self, intervals): - if len(intervals) == 0: + """ + :type intervals: List[Interval] + :rtype: List[Interval] + """ + if not intervals: return intervals - intervals.sort(key = lambda x: x.start) + intervals.sort(key=lambda x: x.start) result = [intervals[0]] - for i in range(1, len(intervals)): + for i in xrange(1, len(intervals)): prev, current = result[-1], intervals[i] if current.start <= prev.end: prev.end = max(prev.end, current.end) @@ -33,5 +36,6 @@ def merge(self, intervals): result.append(current) return result + if __name__ == "__main__": print Solution().merge([Interval(1, 3), Interval(2, 6), Interval(8, 10), Interval(15,18)]) diff --git a/Python/merge-k-sorted-lists.py b/Python/merge-k-sorted-lists.py index 0cd4e311b..edc3c9d4a 100644 --- a/Python/merge-k-sorted-lists.py +++ b/Python/merge-k-sorted-lists.py @@ -1,20 +1,89 @@ # Time: O(nlogk) # Space: O(1) -# -# Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. -import heapq + +# Merge k sorted linked lists and return it as one sorted list. +# Analyze and describe its complexity. # Definition for singly-linked list. -class ListNode: +class ListNode(object): def __init__(self, x): self.val = x self.next = None + + def __repr__(self): + if self: + return "{} -> {}".format(self.val, self.next) + + +# Merge two by two solution. +class Solution(object): + def mergeKLists(self, lists): + """ + :type lists: List[ListNode] + :rtype: ListNode + """ + def mergeTwoLists(l1, l2): + curr = dummy = ListNode(0) + while l1 and l2: + if l1.val < l2.val: + curr.next = l1 + l1 = l1.next + else: + curr.next = l2 + l2 = l2.next + curr = curr.next + curr.next = l1 or l2 + return dummy.next + + if not lists: + return None + left, right = 0, len(lists) - 1; + while right > 0: + if left >= right: + left = 0 + else: + lists[left] = mergeTwoLists(lists[left], lists[right]) + left += 1 + right -= 1 + return lists[0] + + +# Time: O(nlogk) +# Space: O(logk) +# Divide and Conquer solution. +class Solution2: + # @param a list of ListNode + # @return a ListNode + def mergeKLists(self, lists): + def mergeTwoLists(l1, l2): + curr = dummy = ListNode(0) + while l1 and l2: + if l1.val < l2.val: + curr.next = l1 + l1 = l1.next + else: + curr.next = l2 + l2 = l2.next + curr = curr.next + curr.next = l1 or l2 + return dummy.next - def __repr__(self): - if self: - return "{} -> {}".format(self.val, repr(self.next)) + def mergeKListsHelper(lists, begin, end): + if begin > end: + return None + if begin == end: + return lists[begin] + return mergeTwoLists(mergeKListsHelper(lists, begin, (begin + end) / 2), \ + mergeKListsHelper(lists, (begin + end) / 2 + 1, end)) + + return mergeKListsHelper(lists, 0, len(lists) - 1) -class Solution: + +# Time: O(nlogk) +# Space: O(k) +# Heap solution. +import heapq +class Solution3: # @param a list of ListNode # @return a ListNode def mergeKLists(self, lists): @@ -35,10 +104,11 @@ def mergeKLists(self, lists): return dummy.next + if __name__ == "__main__": list1 = ListNode(1) list1.next = ListNode(3) list2 = ListNode(2) list2.next = ListNode(4) - print Solution().mergeKLists([list1, list2]) \ No newline at end of file + print Solution().mergeKLists([list1, list2]) diff --git a/Python/merge-sorted-array.py b/Python/merge-sorted-array.py index 1f07ae31e..5b6a275fc 100644 --- a/Python/merge-sorted-array.py +++ b/Python/merge-sorted-array.py @@ -33,4 +33,35 @@ def merge(self, A, m, B, n): A = [1, 3, 5, 0, 0, 0, 0] B = [2, 4, 6, 7] Solution().merge(A, 3, B, 4) - print A \ No newline at end of file + print A + + +# Time: O(n) +# Space: O(n) +# you may get a input like this, +# nums1 : [0] +# m : 0 +# nums2 : [1] +# n : 1 +# so you need to judge if n is still large than 0 +class Solution2: + def merge(self, nums1, m, nums2, n): + """ + :type nums1: List[int] + :type m: int + :type nums2: List[int] + :type n: int + :rtype: void Do not return anything, modify nums1 in-place instead. + """ + while m > 0 and n > 0: + if nums1[m-1] > nums2[n-1]: + nums1[m+n-1] = nums1[m-1] + m -= 1 + else: + nums1[m+n-1] = nums2[n-1] + n -= 1 + if n > 0: + nums1[:n] = nums2[:n] # Space: O(n), + # Reference: + # - https://stackoverflow.com/questions/4948293/python-slice-assignment-memory-usage + # - https://stackoverflow.com/questions/10623302/how-assignment-works-with-python-list-slice diff --git a/Python/merge-two-binary-trees.py b/Python/merge-two-binary-trees.py new file mode 100644 index 000000000..3fc1c04ef --- /dev/null +++ b/Python/merge-two-binary-trees.py @@ -0,0 +1,53 @@ +# Time: O(n) +# Space: O(h) + +# Given two binary trees and imagine that +# when you put one of them to cover the other, +# some nodes of the two trees are overlapped +# while the others are not. +# +# You need to merge them into a new binary tree. +# The merge rule is that if two nodes overlap, +# then sum node values up as the new value of the merged node. +# Otherwise, the NOT null node will be used as the node of new tree. +# +# Example 1: +# Input: +# Tree 1 Tree 2 +# 1 2 +# / \ / \ +# 3 2 1 3 +# / \ \ +# 5 4 7 +# Output: +# Merged tree: +# 3 +# / \ +# 4 5 +# / \ \ +# 5 4 7 +# +# Note: The merging process must start from the root nodes of both trees. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def mergeTrees(self, t1, t2): + """ + :type t1: TreeNode + :type t2: TreeNode + :rtype: TreeNode + """ + if t1 is None: + return t2 + if t2 is None: + return t1 + t1.val += t2.val + t1.left = self.mergeTrees(t1.left, t2.left) + t1.right = self.mergeTrees(t1.right, t2.right) + return t1 diff --git a/Python/merge-two-sorted-lists.py b/Python/merge-two-sorted-lists.py index 609c90a57..0d965d2b9 100644 --- a/Python/merge-two-sorted-lists.py +++ b/Python/merge-two-sorted-lists.py @@ -6,38 +6,36 @@ # # Definition for singly-linked list. -class ListNode: +class ListNode(object): def __init__(self, x): self.val = x self.next = None - + def __repr__(self): if self: return "{} -> {}".format(self.val, self.next) -class Solution: - # @param two ListNodes - # @return a ListNode + +class Solution(object): def mergeTwoLists(self, l1, l2): - dummy = ListNode(0) - current = dummy - + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + curr = dummy = ListNode(0) while l1 and l2: if l1.val < l2.val: - current.next = l1 + curr.next = l1 l1 = l1.next else: - current.next = l2 + curr.next = l2 l2 = l2.next - current = current.next - - if l1: - current.next = l1 - else: - current.next = l2 - + curr = curr.next + curr.next = l1 or l2 return dummy.next + if __name__ == "__main__": l1 = ListNode(0) l1.next = ListNode(1) @@ -45,4 +43,4 @@ def mergeTwoLists(self, l1, l2): l2.next = ListNode(3) print Solution().mergeTwoLists(l1, l2) - \ No newline at end of file + diff --git a/Python/min-cost-climbing-stairs.py b/Python/min-cost-climbing-stairs.py new file mode 100644 index 000000000..89c0c3380 --- /dev/null +++ b/Python/min-cost-climbing-stairs.py @@ -0,0 +1,31 @@ +# Time: O(n) +# Space: O(1) + +# On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed). +# +# Once you pay the cost, you can either climb one or two steps. +# You need to find minimum cost to reach the top of the floor, +# and you can either start from the step with index 0, or the step with index 1. +# +# Example 1: +# Input: cost = [10, 15, 20] +# Output: 15 +# Explanation: Cheapest is start on cost[1], pay that cost and go to the top. +# Example 2: +# Input: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] +# Output: 6 +# Explanation: Cheapest is start on cost[0], and only step on 1s, skipping cost[3]. +# Note: +# - cost will have a length in the range [2, 1000]. +# - Every cost[i] will be an integer in the range [0, 999]. + +class Solution(object): + def minCostClimbingStairs(self, cost): + """ + :type cost: List[int] + :rtype: int + """ + dp = [0] * 3 + for i in reversed(xrange(len(cost))): + dp[i%3] = cost[i] + min(dp[(i+1)%3], dp[(i+2)%3]) + return min(dp[0], dp[1]) diff --git a/Python/min-stack.py b/Python/min-stack.py index 4036555b5..12df16163 100644 --- a/Python/min-stack.py +++ b/Python/min-stack.py @@ -17,7 +17,7 @@ def __init__(self): # @param x, an integer # @return an integer def push(self, x): - if len(self.stack) == 0: + if not self.stack: self.stack.append(0) self.min = x else: @@ -80,4 +80,4 @@ def getMin(self): stack = MinStack() stack.push(-1) print [stack.top(), stack.getMin()] - \ No newline at end of file + diff --git a/Python/minesweeper.py b/Python/minesweeper.py new file mode 100644 index 000000000..a3a9fe712 --- /dev/null +++ b/Python/minesweeper.py @@ -0,0 +1,138 @@ +# Time: O(m * n) +# Space: O(m + n) + +# Let's play the minesweeper game (Wikipedia, online game)! +# +# You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, +# 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent +# (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents +# how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine. +# +# Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), +# return the board after revealing this position according to the following rules: +# +# If a mine ('M') is revealed, then the game is over - change it to 'X'. +# If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') +# and all of its adjacent unrevealed squares should be revealed recursively. +# If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') +# representing the number of adjacent mines. +# Return the board when no more squares will be revealed. +# +# Example 1: +# Input: +# [['E', 'E', 'E', 'E', 'E'], +# ['E', 'E', 'M', 'E', 'E'], +# ['E', 'E', 'E', 'E', 'E'], +# ['E', 'E', 'E', 'E', 'E']] +# Click : [3,0] +# Output: +# [['B', '1', 'E', '1', 'B'], +# ['B', '1', 'M', '1', 'B'], +# ['B', '1', '1', '1', 'B'], +# ['B', 'B', 'B', 'B', 'B']] +# +# Example 2: +# Input: +# [['B', '1', 'E', '1', 'B'], +# ['B', '1', 'M', '1', 'B'], +# ['B', '1', '1', '1', 'B'], +# ['B', 'B', 'B', 'B', 'B']] +# +# Click : [1,2] +# Output: +# [['B', '1', 'E', '1', 'B'], +# ['B', '1', 'X', '1', 'B'], +# ['B', '1', '1', '1', 'B'], +# ['B', 'B', 'B', 'B', 'B']] +# +# Note: +# The range of the input matrix's height and width is [1,50]. +# The click position will only be an unrevealed square ('M' or 'E'), +# which also means the input board contains at least one clickable square. +# The input board won't be a stage when game is over (some mines have been revealed). +# For simplicity, not mentioned rules should be ignored in this problem. +# For example, you don't need to reveal all the unrevealed mines when the game is over, +# consider any cases that you will win the game or flag any squares. + +class Solution(object): + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + q = collections.deque([click]) + while q: + row, col = q.popleft() + if board[row][col] == 'M': + board[row][col] = 'X' + else: + count = 0 + for i in xrange(-1, 2): + for j in xrange(-1, 2): + if i == 0 and j == 0: + continue + r, c = row + i, col + j + if not (0 <= r < len(board)) or not (0 <= c < len(board[r])): + continue + if board[r][c] == 'M' or board[r][c] == 'X': + count += 1 + + if count: + board[row][col] = chr(count + ord('0')) + else: + board[row][col] = 'B' + for i in xrange(-1, 2): + for j in xrange(-1, 2): + if i == 0 and j == 0: + continue + r, c = row + i, col + j + if not (0 <= r < len(board)) or not (0 <= c < len(board[r])): + continue + if board[r][c] == 'E': + q.append((r, c)) + board[r][c] = ' ' + + return board + + +# Time: O(m * n) +# Space: O(m * n) +class Solution2(object): + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + row, col = click[0], click[1] + if board[row][col] == 'M': + board[row][col] = 'X' + else: + count = 0 + for i in xrange(-1, 2): + for j in xrange(-1, 2): + if i == 0 and j == 0: + continue + r, c = row + i, col + j + if not (0 <= r < len(board)) or not (0 <= c < len(board[r])): + continue + if board[r][c] == 'M' or board[r][c] == 'X': + count += 1 + + if count: + board[row][col] = chr(count + ord('0')) + else: + board[row][col] = 'B' + for i in xrange(-1, 2): + for j in xrange(-1, 2): + if i == 0 and j == 0: + continue + r, c = row + i, col + j + if not (0 <= r < len(board)) or not (0 <= c < len(board[r])): + continue + if board[r][c] == 'E': + self.updateBoard(board, (r, c)) + + return board + diff --git a/Python/mini-parser.py b/Python/mini-parser.py new file mode 100644 index 000000000..fadf39f66 --- /dev/null +++ b/Python/mini-parser.py @@ -0,0 +1,98 @@ +# Time: O(n) +# Space: O(h) + +# Given a nested list of integers represented as a string, implement a parser to deserialize it. +# +# Each element is either an integer, or a list -- whose elements may also be integers or other lists. +# +# Note: You may assume that the string is well-formed: +# +# String is non-empty. +# String does not contain white spaces. +# String contains only digits 0-9, [, - ,, ]. +# Example 1: +# +# Given s = "324", +# +# You should return a NestedInteger object which contains a single integer 324. +# Example 2: +# +# Given s = "[123,[456,[789]]]", +# +# Return a NestedInteger object containing a nested list with 2 elements: +# +# 1. An integer containing value 123. +# 2. A nested list containing two elements: +# i. An integer containing value 456. +# ii. A nested list with one element: +# a. An integer containing value 789. +# +# """ +# This is the interface that allows for creating nested lists. +# You should not implement it, or speculate about its implementation +# """ +#class NestedInteger(object): +# def __init__(self, value=None): +# """ +# If value is not specified, initializes an empty list. +# Otherwise initializes a single integer equal to value. +# """ +# +# def isInteger(self): +# """ +# @return True if this NestedInteger holds a single integer, rather than a nested list. +# :rtype bool +# """ +# +# def add(self, elem): +# """ +# Set this NestedInteger to hold a nested list and adds a nested integer elem to it. +# :rtype void +# """ +# +# def setInteger(self, value): +# """ +# Set this NestedInteger to hold a single integer equal to value. +# :rtype void +# """ +# +# def getInteger(self): +# """ +# @return the single integer that this NestedInteger holds, if it holds a single integer +# Return None if this NestedInteger holds a nested list +# :rtype int +# """ +# +# def getList(self): +# """ +# @return the nested list that this NestedInteger holds, if it holds a nested list +# Return None if this NestedInteger holds a single integer +# :rtype List[NestedInteger] +# """ + + +class Solution(object): + def deserialize(self, s): + if not s: + return NestedInteger() + + if s[0] != '[': + return NestedInteger(int(s)) + + stk = [] + + i = 0 + for j in xrange(len(s)): + if s[j] == '[': + stk += NestedInteger(), + i = j+1 + elif s[j] in ',]': + if s[j-1].isdigit(): + stk[-1].add(NestedInteger(int(s[i:j]))) + if s[j] == ']' and len(stk) > 1: + cur = stk[-1] + stk.pop(); + stk[-1].add(cur) + i = j+1 + + return stk[-1] diff --git a/Python/minimum-absolute-difference-in-bst.py b/Python/minimum-absolute-difference-in-bst.py new file mode 100644 index 000000000..daaafe6df --- /dev/null +++ b/Python/minimum-absolute-difference-in-bst.py @@ -0,0 +1,46 @@ +# Time: O(n) +# Space: O(h) + +# Given a binary search tree with non-negative values, +# find the minimum absolute difference between values of any two nodes. +# +# Example: +# +# Input: +# +# 1 +# \ +# 3 +# / +# 2 +# +# Output: +# 1 +# +# Explanation: +# The minimum absolute difference is 1, +# which is the difference between 2 and 1 (or between 2 and 3). +# Note: There are at least two nodes in this BST. +# +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def getMinimumDifference(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def inorderTraversal(root, prev, result): + if not root: + return (result, prev) + + result, prev = inorderTraversal(root.left, prev, result) + if prev: result = min(result, root.val - prev.val) + return inorderTraversal(root.right, root, result) + + return inorderTraversal(root, None, float("inf"))[0] diff --git a/Python/minimum-ascii-delete-sum-for-two-strings.py b/Python/minimum-ascii-delete-sum-for-two-strings.py new file mode 100644 index 000000000..6fd3f7683 --- /dev/null +++ b/Python/minimum-ascii-delete-sum-for-two-strings.py @@ -0,0 +1,72 @@ +# Time: O(m * n) +# Space: O(n) + +# Given two strings s1, s2, find the lowest ASCII sum of deleted characters to make two strings equal. +# +# Example 1: +# Input: s1 = "sea", s2 = "eat" +# Output: 231 +# Explanation: Deleting "s" from "sea" adds the ASCII value of "s" (115) to the sum. +# Deleting "t" from "eat" adds 116 to the sum. +# At the end, both strings are equal, and 115 + 116 = 231 is the minimum sum possible to achieve this. +# +# Example 2: +# Input: s1 = "delete", s2 = "leet" +# Output: 403 +# Explanation: Deleting "dee" from "delete" to turn the string into "let", +# adds 100[d]+101[e]+101[e] to the sum. Deleting "e" from "leet" adds 101[e] to the sum. +# At the end, both strings are equal to "let", and the answer is 100+101+101+101 = 403. +# If instead we turned both strings into "lee" or "eet", we would get answers of 433 or 417, which are higher. +# +# Note: +# - 0 < s1.length, s2.length <= 1000. +# - All elements of each string will have an ASCII value in [97, 122]. + +# DP with rolling window +class Solution(object): + def minimumDeleteSum(self, s1, s2): + """ + :type s1: str + :type s2: str + :rtype: int + """ + dp = [[0] * (len(s2)+1) for _ in xrange(2)] + for j in xrange(len(s2)): + dp[0][j+1] = dp[0][j] + ord(s2[j]) + + for i in xrange(len(s1)): + dp[(i+1)%2][0] = dp[i%2][0] + ord(s1[i]) + for j in xrange(len(s2)): + if s1[i] == s2[j]: + dp[(i+1)%2][j+1] = dp[i%2][j] + else: + dp[(i+1)%2][j+1] = min(dp[i%2][j+1] + ord(s1[i]), \ + dp[(i+1)%2][j] + ord(s2[j])) + + return dp[len(s1)%2][-1] + + +# Time: O(m * n) +# Space: O(m * n) +class Solution2(object): + def minimumDeleteSum(self, s1, s2): + """ + :type s1: str + :type s2: str + :rtype: int + """ + dp = [[0] * (len(s2)+1) for _ in xrange(len(s1)+1)] + for i in xrange(len(s1)): + dp[i+1][0] = dp[i][0] + ord(s1[i]) + for j in xrange(len(s2)): + dp[0][j+1] = dp[0][j] + ord(s2[j]) + + for i in xrange(len(s1)): + for j in xrange(len(s2)): + if s1[i] == s2[j]: + dp[i+1][j+1] = dp[i][j] + else: + dp[i+1][j+1] = min(dp[i][j+1] + ord(s1[i]), \ + dp[i+1][j] + ord(s2[j])) + + return dp[-1][-1] diff --git a/Python/minimum-depth-of-binary-tree.py b/Python/minimum-depth-of-binary-tree.py index 5494074ec..2833dcaab 100644 --- a/Python/minimum-depth-of-binary-tree.py +++ b/Python/minimum-depth-of-binary-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, find its minimum depth. # @@ -28,4 +28,4 @@ def minDepth(self, root): if __name__ == "__main__": root = TreeNode(1) root.left = TreeNode(2) - print Solution().minDepth(root) \ No newline at end of file + print Solution().minDepth(root) diff --git a/Python/minimum-factorization.py b/Python/minimum-factorization.py new file mode 100644 index 000000000..52d72293a --- /dev/null +++ b/Python/minimum-factorization.py @@ -0,0 +1,19 @@ +# Time: O(loga) +# Space: O(1) + +class Solution(object): + def smallestFactorization(self, a): + """ + :type a: int + :rtype: int + """ + if a < 2: + return a + result, mul = 0, 1 + for i in reversed(xrange(2, 10)): + while a % i == 0: + a /= i + result = mul*i + result + mul *= 10 + return result if a == 1 and result < 2**31 else 0 + diff --git a/Python/minimum-genetic-mutation.py b/Python/minimum-genetic-mutation.py new file mode 100644 index 000000000..900510bb7 --- /dev/null +++ b/Python/minimum-genetic-mutation.py @@ -0,0 +1,66 @@ +# Time: O(n * b), n is the length of gene string, b is size of bank +# Space: O(b) + +# A gene string can be represented by an 8-character long string, +# with choices from "A","C","G","T". +# Suppose we need to investigate about a mutation (mutation from "start" to "end"), +# where ONE mutation is defined as ONE single character changed in the gene string. +# For example, "AACCGGTT" -> "AACCGGTA" is 1 mutation. +# Also, there is a given gene "bank", which records all the valid gene mutations. +# A gene must be in the bank to make it a valid gene string. +# +# Now, given 3 things - start, end, bank, +# your task is to determine what is the minimum number of mutations needed to +# mutate from "start" to "end". If there is no such a mutation, return -1. +# +# NOTE: 1. Starting point is assumed to be valid, so it might not be included in the bank. +# 2. If multiple mutations are needed, all mutations during in the sequence must be valid. +# +# For example, +# +# bank: "AACCGGTA" +# start: "AACCGGTT" +# end: "AACCGGTA" +# return: 1 +# +# bank: "AACCGGTA", "AACCGCTA", "AAACGGTA" +# start: "AACCGGTT" +# end: "AAACGGTA" +# return: 2 +# +# bank: "AAAACCCC", "AAACCCCC", "AACCCCCC" +# start: "AAAAACCC" +# end: "AACCCCCC" +# return: 3 + +from collections import deque + +class Solution(object): + def minMutation(self, start, end, bank): + """ + :type start: str + :type end: str + :type bank: List[str] + :rtype: int + """ + lookup = {} + for b in bank: + lookup[b] = False + + q = deque([(start, 0)]) + while q: + cur, level = q.popleft() + if cur == end: + return level + + for i in xrange(len(cur)): + for c in ['A', 'T', 'C', 'G']: + if cur[i] == c: + continue + + next_str = cur[:i] + c + cur[i+1:] + if next_str in lookup and lookup[next_str] == False: + q.append((next_str, level+1)) + lookup[next_str] = True + + return -1 diff --git a/Python/minimum-height-trees.py b/Python/minimum-height-trees.py new file mode 100644 index 000000000..dbd7df905 --- /dev/null +++ b/Python/minimum-height-trees.py @@ -0,0 +1,92 @@ +# Time: O(n) +# Space: O(n) + +# For a undirected graph with tree characteristics, we can +# choose any node as the root. The result graph is then a +# rooted tree. Among all possible rooted trees, those with +# minimum height are called minimum height trees (MHTs). +# Given such a graph, write a function to find all the +# MHTs and return a list of their root labels. +# +# Format +# The graph contains n nodes which are labeled from 0 to n - 1. +# You will be given the number n and a list of undirected +# edges (each edge is a pair of labels). +# +# You can assume that no duplicate edges will appear in edges. +# Since all edges are undirected, [0, 1] is the same as [1, 0] +# and thus will not appear together in edges. +# +# Example 1: +# +# Given n = 4, edges = [[1, 0], [1, 2], [1, 3]] +# +# 0 +# | +# 1 +# / \ +# 2 3 +# return [1] +# +# Example 2: +# +# Given n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]] +# +# 0 1 2 +# \ | / +# 3 +# | +# 4 +# | +# 5 +# return [3, 4] +# +# Hint: +# +# How many MHTs can a graph have at most? +# Note: +# +# (1) According to the definition of tree on Wikipedia: +# "a tree is an undirected graph in which any two vertices +# are connected by exactly one path. In other words, +# any connected graph without simple cycles is a tree." +# +# (2) The height of a rooted tree is the number of edges on the +# longest downward path between the root and a leaf. + +class Solution(object): + def findMinHeightTrees(self, n, edges): + """ + :type n: int + :type edges: List[List[int]] + :rtype: List[int] + """ + if n == 1: + return [0] + + neighbors = collections.defaultdict(set) + for u, v in edges: + neighbors[u].add(v) + neighbors[v].add(u) + + pre_level, unvisited = [], set() + for i in xrange(n): + if len(neighbors[i]) == 1: # A leaf. + pre_level.append(i) + unvisited.add(i) + + # A graph can have 2 MHTs at most. + # BFS from the leaves until the number + # of the unvisited nodes is less than 3. + while len(unvisited) > 2: + cur_level = [] + for u in pre_level: + unvisited.remove(u) + for v in neighbors[u]: + if v in unvisited: + neighbors[v].remove(u) + if len(neighbors[v]) == 1: + cur_level.append(v) + pre_level = cur_level + + return list(unvisited) diff --git a/Python/minimum-index-sum-of-two-lists.py b/Python/minimum-index-sum-of-two-lists.py new file mode 100644 index 000000000..4a953c004 --- /dev/null +++ b/Python/minimum-index-sum-of-two-lists.py @@ -0,0 +1,51 @@ +# Time: O((m + n) * l), m is the size of list1, n is the size of list2 +# Space: O(m * l), l is the average length of string + +# Suppose Andy and Doris want to choose a restaurant for dinner, +# and they both have a list of favorite restaurants represented by strings. +# +# You need to help them find out their common interest with the least list index sum. +# If there is a choice tie between answers, output all of them with no order requirement. +# You could assume there always exists an answer. +# +# Example 1: +# Input: +# ["Shogun", "Tapioca Express", "Burger King", "KFC"] +# ["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"] +# Output: ["Shogun"] +# Explanation: The only restaurant they both like is "Shogun". +# Example 2: +# Input: +# ["Shogun", "Tapioca Express", "Burger King", "KFC"] +# ["KFC", "Shogun", "Burger King"] +# Output: ["Shogun"] +# Explanation: The restaurant they both like and have the least index sum is "Shogun" with index sum 1 (0+1). +# Note: +# The length of both lists will be in the range of [1, 1000]. +# The length of strings in both lists will be in the range of [1, 30]. +# The index is starting from 0 to the list length minus 1. +# No duplicates in both lists. + +class Solution(object): + def findRestaurant(self, list1, list2): + """ + :type list1: List[str] + :type list2: List[str] + :rtype: List[str] + """ + lookup = {} + for i, s in enumerate(list1): + lookup[s] = i + + result = [] + min_sum = float("inf") + for j, s in enumerate(list2): + if j > min_sum: + break + if s in lookup: + if j + lookup[s] < min_sum: + result = [s] + min_sum = j + lookup[s] + elif j + lookup[s] == min_sum: + result.append(s) + return result diff --git a/Python/minimum-moves-to-equal-array-elements-ii.py b/Python/minimum-moves-to-equal-array-elements-ii.py new file mode 100644 index 000000000..ee447cd6f --- /dev/null +++ b/Python/minimum-moves-to-equal-array-elements-ii.py @@ -0,0 +1,46 @@ +# Time: O(n) on average +# Space: O(1) + +from random import randint + +# Quick select solution. +class Solution(object): + def minMoves2(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + def kthElement(nums, k): + def PartitionAroundPivot(left, right, pivot_idx, nums): + pivot_value = nums[pivot_idx] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i] > pivot_value: + nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] + new_pivot_idx += 1 + + nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] + return new_pivot_idx + + left, right = 0, len(nums) - 1 + while left <= right: + pivot_idx = randint(left, right) + new_pivot_idx = PartitionAroundPivot(left, right, pivot_idx, nums) + if new_pivot_idx == k - 1: + return nums[new_pivot_idx] + elif new_pivot_idx > k - 1: + right = new_pivot_idx - 1 + else: # new_pivot_idx < k - 1. + left = new_pivot_idx + 1 + + median = kthElement(nums, len(nums)/2 + 1) + return sum(abs(num - median) for num in nums) + + def minMoves22(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + median = sorted(nums)[len(nums) / 2] + return sum(abs(num - median) for num in nums) diff --git a/Python/minimum-moves-to-equal-array-elements.py b/Python/minimum-moves-to-equal-array-elements.py new file mode 100644 index 000000000..fd4afdff2 --- /dev/null +++ b/Python/minimum-moves-to-equal-array-elements.py @@ -0,0 +1,27 @@ +# Time: O(n) +# Space: O(1) + +# Given a non-empty integer array of size n, +# find the minimum number of moves required to make all array elements equal, +# where a move is incrementing n - 1 elements by 1. +# +# Example: +# +# Input: +# [1,2,3] +# +# Output: +# 3 +# +# Explanation: +# Only three moves are needed (remember each move increments two elements): +# +# [1,2,3] => [2,3,3] => [3,4,3] => [4,4,4] + +class Solution(object): + def minMoves(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return sum(nums) - len(nums) * min(nums) diff --git a/Python/minimum-number-of-arrows-to-burst-balloons.py b/Python/minimum-number-of-arrows-to-burst-balloons.py new file mode 100644 index 000000000..04248ea80 --- /dev/null +++ b/Python/minimum-number-of-arrows-to-burst-balloons.py @@ -0,0 +1,48 @@ +# Time: O(nlogn) +# Space: O(1) + +# There are a number of spherical balloons spread in two-dimensional space. +# For each balloon, provided input is the start and end coordinates of the horizontal diameter. +# Since it's horizontal, y-coordinates don't matter and hence the x-coordinates of start and +# end of the diameter suffice. Start is always smaller than end. There will be at most 104 balloons. +# +# An arrow can be shot up exactly vertically from different points along the x-axis. +# A balloon with xstart and xend bursts by an arrow shot at x if xstart <= x <= xend. +# There is no limit to the number of arrows that can be shot. +# An arrow once shot keeps travelling up infinitely. +# The problem is to find the minimum number of arrows that must be shot to burst all balloons. +# +# Example: +# +# Input: +# [[10,16], [2,8], [1,6], [7,12]] +# +# Output: +# 2 +# +# Explanation: +# One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) +# and another arrow at x = 11 (bursting the other two balloons). + +class Solution(object): + def findMinArrowShots(self, points): + """ + :type points: List[List[int]] + :rtype: int + """ + if not points: + return 0 + + points.sort() + + result = 0 + i = 0 + while i < len(points): + j = i + 1 + right_bound = points[i][1] + while j < len(points) and points[j][0] <= right_bound: + right_bound = min(right_bound, points[j][1]) + j += 1 + result += 1 + i = j + return result diff --git a/Python/minimum-size-subarray-sum.py b/Python/minimum-size-subarray-sum.py new file mode 100644 index 000000000..24d56ced0 --- /dev/null +++ b/Python/minimum-size-subarray-sum.py @@ -0,0 +1,60 @@ +# Time: O(n) +# Space: O(1) +# +# Given an array of n positive integers and a positive integer s, +# find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead. +# +# For example, given the array [2,3,1,2,4,3] and s = 7, +# the subarray [4,3] has the minimal length under the problem constraint. +# +# More practice: +# If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n). +# + +# Sliding window solution. +class Solution: + # @param {integer} s + # @param {integer[]} nums + # @return {integer} + def minSubArrayLen(self, s, nums): + start = 0 + sum = 0 + min_size = float("inf") + for i in xrange(len(nums)): + sum += nums[i] + while sum >= s: + min_size = min(min_size, i - start + 1) + sum -= nums[start] + start += 1 + + return min_size if min_size != float("inf") else 0 + +# Time: O(nlogn) +# Space: O(n) +# Binary search solution. +class Solution2: + # @param {integer} s + # @param {integer[]} nums + # @return {integer} + def minSubArrayLen(self, s, nums): + min_size = float("inf") + sum_from_start = [n for n in nums] + for i in xrange(len(sum_from_start) - 1): + sum_from_start[i + 1] += sum_from_start[i] + for i in xrange(len(sum_from_start)): + end = self.binarySearch(lambda x, y: x <= y, sum_from_start, \ + i, len(sum_from_start), \ + sum_from_start[i] - nums[i] + s) + if end < len(sum_from_start): + min_size = min(min_size, end - i + 1) + + return min_size if min_size != float("inf") else 0 + + def binarySearch(self, compare, A, start, end, target): + while start < end: + mid = start + (end - start) / 2 + if compare(target, A[mid]): + end = mid + else: + start = mid + 1 + return start diff --git a/Python/minimum-time-difference.py b/Python/minimum-time-difference.py new file mode 100644 index 000000000..1366a336a --- /dev/null +++ b/Python/minimum-time-difference.py @@ -0,0 +1,23 @@ +# Time: O(nlogn) +# Space: O(n) + +# Given a list of 24-hour clock time points in "Hour:Minutes" format, +# find the minimum minutes difference between any two time points in the list. +# +# Example 1: +# Input: ["23:59","00:00"] +# Output: 1 +# Note: +# The number of time points in the given list is at least 2 and won't exceed 20000. +# The input time is legal and ranges from 00:00 to 23:59. + +class Solution(object): + def findMinDifference(self, timePoints): + """ + :type timePoints: List[str] + :rtype: int + """ + minutes = map(lambda x: int(x[:2]) * 60 + int(x[3:]), timePoints) + minutes.sort() + return min((y - x) % (24 * 60) \ + for x, y in zip(minutes, minutes[1:] + minutes[:1])) diff --git a/Python/minimum-unique-word-abbreviation.py b/Python/minimum-unique-word-abbreviation.py new file mode 100644 index 000000000..3a3f3324b --- /dev/null +++ b/Python/minimum-unique-word-abbreviation.py @@ -0,0 +1,40 @@ +# Time: O(2^n) +# Space: O(n) + +class Solution(object): + def minAbbreviation(self, target, dictionary): + """ + :type target: str + :type dictionary: List[str] + :rtype: str + """ + def bits_len(target, bits): + return sum(((bits >> i) & 3) == 0 for i in xrange(len(target)-1)) + + diffs = [] + for word in dictionary: + if len(word) != len(target): + continue + diffs.append(sum(2**i for i, c in enumerate(word) if target[i] != c)) + + if not diffs: + return str(len(target)) + + bits = 2**len(target) - 1 + for i in xrange(2**len(target)): + if all(d & i for d in diffs) and bits_len(target, i) > bits_len(target, bits): + bits = i + + abbr = [] + pre = 0 + for i in xrange(len(target)): + if bits & 1: + if i - pre > 0: + abbr.append(str(i - pre)) + pre = i + 1 + abbr.append(str(target[i])) + elif i == len(target) - 1: + abbr.append(str(i - pre + 1)) + bits >>= 1 + + return "".join(abbr) diff --git a/Python/minimum-window-subsequence.py b/Python/minimum-window-subsequence.py new file mode 100644 index 000000000..647dcea4c --- /dev/null +++ b/Python/minimum-window-subsequence.py @@ -0,0 +1,29 @@ +# Time: O(s * t) +# Space: O(s) + +class Solution(object): + def minWindow(self, S, T): + """ + :type S: str + :type T: str + :rtype: str + """ + dp = [[None for _ in xrange(len(S))] for _ in xrange(2)] + for j, c in enumerate(S): + if c == T[0]: + dp[0][j] = j + + for i in xrange(1, len(T)): + prev = None + dp[i%2] = [None] * len(S) + for j, c in enumerate(S): + if prev is not None and c == T[i]: + dp[i%2][j] = prev + if dp[(i-1)%2][j] is not None: + prev = dp[(i-1)%2][j] + + start, end = 0, len(S) + for j, i in enumerate(dp[(len(T)-1)%2]): + if i >= 0 and j-i < end-start: + start, end = i, j + return S[start:end+1] if end < len(S) else "" diff --git a/Python/minimum-window-substring.py b/Python/minimum-window-substring.py index 37a001902..d006f4f1e 100644 --- a/Python/minimum-window-substring.py +++ b/Python/minimum-window-substring.py @@ -1,7 +1,8 @@ # Time: O(n) -# Space: O(1) -# -# Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). +# Space: O(k), k is the number of different characters + +# Given a string S and a string T, find the minimum window in S which +# will contain all the characters in T in complexity O(n). # # For example, # S = "ADOBECODEBANC" @@ -9,30 +10,35 @@ # Minimum window is "BANC". # # Note: -# If there is no such window in S that covers all characters in T, return the emtpy string "". +# If there is no such window in S that covers all characters in T, +# return the emtpy string "". # -# If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S. -# +# If there are multiple such windows, you are guaranteed that +# there will always be only one unique minimum window in S. -class Solution: - # @return a string - def minWindow(self, S, T): +class Solution(object): + def minWindow(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ current_count = [0 for i in xrange(52)] expected_count = [0 for i in xrange(52)] - for char in T: + for char in t: expected_count[ord(char) - ord('a')] += 1 i, count, start, min_width, min_start = 0, 0, 0, float("inf"), 0 - while i < len(S): - current_count[ord(S[i]) - ord('a')] += 1 - if current_count[ord(S[i]) - ord('a')] <= expected_count[ord(S[i]) - ord('a')]: + while i < len(s): + current_count[ord(s[i]) - ord('a')] += 1 + if current_count[ord(s[i]) - ord('a')] <= expected_count[ord(s[i]) - ord('a')]: count += 1 - if count == len(T): - while expected_count[ord(S[start]) - ord('a')] == 0 or\ - current_count[ord(S[start]) - ord('a')] > expected_count[ord(S[start]) - ord('a')]: - current_count[ord(S[start]) - ord('a')] -= 1 + if count == len(t): + while expected_count[ord(s[start]) - ord('a')] == 0 or \ + current_count[ord(s[start]) - ord('a')] > expected_count[ord(s[start]) - ord('a')]: + current_count[ord(s[start]) - ord('a')] -= 1 start += 1 if min_width > i - start + 1: @@ -43,7 +49,8 @@ def minWindow(self, S, T): if min_width == float("inf"): return "" - return S[min_start:min_start + min_width] + return s[min_start:min_start + min_width] + if __name__ == "__main__": print Solution().minWindow("ADOBECODEBANC", "ABC") diff --git a/Python/missing-number.py b/Python/missing-number.py new file mode 100644 index 000000000..39aae053a --- /dev/null +++ b/Python/missing-number.py @@ -0,0 +1,27 @@ +# Time: O(n) +# Space: O(1) +# +# Given an array containing n distinct numbers taken from +# 0, 1, 2, ..., n, find the one that is missing from the array. +# +# For example, +# Given nums = [0, 1, 3] return 2. +# +# Note: +# Your algorithm should run in linear runtime complexity. +# Could you implement it using only constant extra space complexity? +# + +class Solution(object): + def missingNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return reduce(operator.xor, nums, \ + reduce(operator.xor, xrange(len(nums) + 1))) + + +class Solution2(object): + def missingNumber(self, nums): + return sum(xrange(len(nums)+1)) - sum(nums) diff --git a/Python/missing-ranges.py b/Python/missing-ranges.py index a4d0d1378..e43b6104c 100644 --- a/Python/missing-ranges.py +++ b/Python/missing-ranges.py @@ -8,33 +8,34 @@ # return ["2", "4->49", "51->74", "76->99"]. # -class Solution: - # @param A, a list of integers - # @param lower, an integer - # @param upper, an integer - # @return a list of strings - def findMissingRanges(self, A, lower, upper): +class Solution(object): + def findMissingRanges(self, nums, lower, upper): + """ + :type nums: List[int] + :type lower: int + :type upper: int + :rtype: List[str] + """ + def getRange(lower, upper): + if lower == upper: + return "{}".format(lower) + else: + return "{}->{}".format(lower, upper) ranges = [] pre = lower - 1 - for i in xrange(len(A) + 1): - if i == len(A): + for i in xrange(len(nums) + 1): + if i == len(nums): cur = upper + 1 else: - cur = A[i] - + cur = nums[i] if cur - pre >= 2: - ranges.append(self.getRange(pre + 1, cur - 1)) + ranges.append(getRange(pre + 1, cur - 1)) pre = cur return ranges - - def getRange(self, lower, upper): - if lower == upper: - return "{}".format(lower) - else: - return "{}->{}".format(lower, upper) - + + if __name__ == "__main__": - print Solution().findMissingRanges([0, 1, 3, 50, 75], 0, 99) \ No newline at end of file + print Solution().findMissingRanges([0, 1, 3, 50, 75], 0, 99) diff --git a/Python/monotone-increasing-digits.py b/Python/monotone-increasing-digits.py new file mode 100644 index 000000000..111fb299c --- /dev/null +++ b/Python/monotone-increasing-digits.py @@ -0,0 +1,38 @@ +# Time: O(logn) = O(1) +# Space: O(logn) = O(1) + +# Given a non-negative integer N, +# find the largest number that is less than or equal to N with monotone increasing digits. +# +# (Recall that an integer has monotone increasing digits if and only +# if each pair of adjacent digits x and y satisfy x <= y.) +# +# Example 1: +# Input: N = 10 +# Output: 9 +# +# Example 2: +# Input: N = 1234 +# Output: 1234 +# +# Example 3: +# Input: N = 332 +# Output: 299 +# +# Note: N is an integer in the range [0, 10^9]. + +class Solution(object): + def monotoneIncreasingDigits(self, N): + """ + :type N: int + :rtype: int + """ + nums = map(int, list(str(N))) + leftmost_inverted_idx = len(nums) + for i in reversed(xrange(1, len(nums))): + if nums[i-1] > nums[i]: + leftmost_inverted_idx = i + nums[i-1] -= 1 + for i in xrange(leftmost_inverted_idx, len(nums)): + nums[i] = 9 + return int("".join(map(str, nums))) diff --git a/Python/most-frequent-subtree-sum.py b/Python/most-frequent-subtree-sum.py new file mode 100644 index 000000000..ca261a1b5 --- /dev/null +++ b/Python/most-frequent-subtree-sum.py @@ -0,0 +1,51 @@ +# Time: O(n) +# Space: O(n) + +# Given the root of a tree, you are asked to find the most frequent subtree sum. +# The subtree sum of a node is defined as the sum of all the node values formed by +# the subtree rooted at that node (including the node itself). +# So what is the most frequent subtree sum value? If there is a tie, +# return all the values with the highest frequency in any order. +# +# Examples 1 +# Input: +# +# 5 +# / \ +# 2 -3 +# return [2, -3, 4], since all the values happen only once, return all of them in any order. +# Examples 2 +# Input: +# +# 5 +# / \ +# 2 -5 +# return [2], since 2 happens twice, however -5 only occur once. +# Note: You may assume the sum of values in any subtree is in the range of 32-bit signed integer. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findFrequentTreeSum(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + def countSubtreeSumHelper(root, counts): + if not root: + return 0 + total = root.val + \ + countSubtreeSumHelper(root.left, counts) + \ + countSubtreeSumHelper(root.right, counts) + counts[total] += 1 + return total + + counts = collections.defaultdict(int) + countSubtreeSumHelper(root, counts) + max_count = max(counts.values()) if counts else 0 + return [total for total, count in counts.iteritems() if count == max_count] diff --git a/Python/move-zeroes.py b/Python/move-zeroes.py new file mode 100644 index 000000000..fb121754c --- /dev/null +++ b/Python/move-zeroes.py @@ -0,0 +1,55 @@ +# Time: O(n) +# Space: O(1) + +# Given an array nums, write a function to move all 0's +# to the end of it while maintaining the relative order +# of the non-zero elements. +# +# For example, given nums = [0, 1, 0, 3, 12], after +# calling your function, nums should be [1, 3, 12, 0, 0]. +# +# Note: +# You must do this in-place without making a copy of the array. +# Minimize the total number of operations. + + +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + pos = 0 + for i in xrange(len(nums)): + if nums[i]: + nums[i], nums[pos] = nums[pos], nums[i] + pos += 1 + + def moveZeroes2(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + nums.sort(cmp=lambda a, b: 0 if b else -1) + + +class Solution2(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + pos = 0 + for i in xrange(len(nums)): + if nums[i]: + nums[pos] = nums[i] + pos += 1 + + for i in xrange(pos, len(nums)): + nums[i] = 0 + + +if __name__ == '__main__': + s = Solution() + r = s.moveZeroes([0, 1, 0, 3, 12]) + print r diff --git a/Python/moving-average-from-data-stream.py b/Python/moving-average-from-data-stream.py new file mode 100644 index 000000000..d61bdaded --- /dev/null +++ b/Python/moving-average-from-data-stream.py @@ -0,0 +1,31 @@ +# Time: O(1) +# Space: O(w) + +from collections import deque + +class MovingAverage(object): + + def __init__(self, size): + """ + Initialize your data structure here. + :type size: int + """ + self.__size = size + self.__sum = 0 + self.__q = deque([]) + + def next(self, val): + """ + :type val: int + :rtype: float + """ + if len(self.__q) == self.__size: + self.__sum -= self.__q.popleft() + self.__sum += val + self.__q.append(val) + return 1.0 * self.__sum / len(self.__q) + + +# Your MovingAverage object will be instantiated and called as such: +# obj = MovingAverage(size) +# param_1 = obj.next(val) diff --git a/Python/multiply-strings.py b/Python/multiply-strings.py index e5af568af..6df6c3f12 100644 --- a/Python/multiply-strings.py +++ b/Python/multiply-strings.py @@ -6,27 +6,40 @@ # Note: The numbers can be arbitrarily large and are non-negative. # -class Solution: - # @param num1, a string - # @param num2, a string - # @return a string +class Solution(object): def multiply(self, num1, num2): + """ + :type num1: str + :type num2: str + :rtype: str + """ num1, num2 = num1[::-1], num2[::-1] - result = [0 for i in xrange(len(num1) + len(num2))] + res = [0] * (len(num1) + len(num2)) for i in xrange(len(num1)): for j in xrange(len(num2)): - result[i + j] += int(num1[i]) * int(num2[j]) - - carry, num3 = 0, [] - for digit in result: - sum = carry + digit - carry = sum / 10 - num3.insert(0, str(sum % 10)) - - while len(num3) > 1 and num3[0] == "0": - del num3[0] - - return ''.join(num3) + res[i + j] += int(num1[i]) * int(num2[j]) + res[i + j + 1] += res[i + j] / 10 + res[i + j] %= 10 + + # Skip leading 0s. + i = len(res) - 1 + while i > 0 and res[i] == 0: + i -= 1 + + return ''.join(map(str, res[i::-1])) + +# Time: O(m * n) +# Space: O(m + n) +# Using built-in bignum solution. +class Solution2(object): + def multiply(self, num1, num2): + """ + :type num1: str + :type num2: str + :rtype: str + """ + return str(int(num1) * int(num2)) + if __name__ == "__main__": - print Solution().multiply("123", "1000") \ No newline at end of file + print Solution().multiply("123", "1000") diff --git a/Python/my-calendar-i.py b/Python/my-calendar-i.py new file mode 100644 index 000000000..8814fc510 --- /dev/null +++ b/Python/my-calendar-i.py @@ -0,0 +1,95 @@ +# Time: O(nlogn) on average, O(n^2) on worst case +# Space: O(n) + +# Implement a MyCalendar class to store your events. +# A new event can be added if adding the event will not cause a double booking. +# +# Your class will have the method, book(int start, int end). +# Formally, this represents a booking on the half open interval [start, end), +# the range of real numbers x such that start <= x < end. +# +# A double booking happens when two events have some non-empty intersection +# (ie., there is some time that is common to both events.) +# +# For each call to the method MyCalendar.book, +# return true if the event can be added to the calendar successfully without causing a double booking. +# Otherwise, return false and do not add the event to the calendar. +# +# Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end) +# Example 1: +# MyCalendar(); +# MyCalendar.book(10, 20); // returns true +# MyCalendar.book(15, 25); // returns false +# MyCalendar.book(20, 30); // returns true +# Explanation: +# The first event can be booked. The second can't because time 15 is already booked by another event. +# The third event can be booked, as the first event takes every time less than 20, but not including 20. +# +# Note: +# - The number of calls to MyCalendar.book per test case will be at most 1000. +# - In calls to MyCalendar.book(start, end), start and end are integers in the range [0, 10^9]. + +class Node: + def __init__(self, start, end): + self.__start = start + self.__end = end + self.__left = None + self.__right = None + + + def insert(self, node): + if node.__start >= self.__end: + if not self.__right: + self.__right = node + return True + return self.__right.insert(node) + elif node.__end <= self.__start: + if not self.__left: + self.__left = node + return True + return self.__left.insert(node) + else: + return False + + +class MyCalendar(object): + def __init__(self): + self.__root = None + + + def book(self, start, end): + """ + :type start: int + :type end: int + :rtype: bool + """ + if self.__root is None: + self.__root = Node(start, end) + return True + return self.root.insert(Node(start, end)) + + +# Time: O(n^2) +# Space: O(n) +class MyCalendar2(object): + + def __init__(self): + self.__calendar = [] + + + def book(self, start, end): + """ + :type start: int + :type end: int + :rtype: bool + """ + for i, j in self.__calendar: + if start < j and end > i: + return False + self.__calendar.append((start, end)) + return True + + +# Your MyCalendar object will be instantiated and called as such: +# obj = MyCalendar() +# param_1 = obj.book(start,end) diff --git a/Python/my-calendar-ii.py b/Python/my-calendar-ii.py new file mode 100644 index 000000000..0dc4f14e6 --- /dev/null +++ b/Python/my-calendar-ii.py @@ -0,0 +1,64 @@ +# Time: O(n^2) +# Space: O(n) + +# Implement a MyCalendarTwo class to store your events. +# A new event can be added if adding the event will not cause a triple booking. +# +# Your class will have one method, book(int start, int end). +# Formally, this represents a booking on the half open interval [start, end), +# the range of real numbers x such that start <= x < end. +# +# A triple booking happens when three events have some non-empty intersection +# (ie., there is some time that is common to all 3 events.) +# +# For each call to the method MyCalendar.book, +# return true if the event can be added to the calendar successfully without causing a triple booking. +# Otherwise, return false and do not add the event to the calendar. +# +# Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end) +# Example 1: +# MyCalendar(); +# MyCalendar.book(10, 20); // returns true +# MyCalendar.book(50, 60); // returns true +# MyCalendar.book(10, 40); // returns true +# MyCalendar.book(5, 15); // returns false +# MyCalendar.book(5, 10); // returns true +# MyCalendar.book(25, 55); // returns true +# +# Explanation: +# The first two events can be booked. The third event can be double booked. +# The fourth event (5, 15) can't be booked, because it would result in a triple booking. +# The fifth event (5, 10) can be booked, as it does not use time 10 which is already double booked. +# The sixth event (25, 55) can be booked, as the time in [25, 40) will be double booked with the third event; +# the time [40, 50) will be single booked, and the time [50, 55) will be double booked with the second event. +# +# Note: +# - The number of calls to MyCalendar.book per test case will be at most 1000. +# - In calls to MyCalendar.book(start, end), start and end are integers in the range [0, 10^9]. + +class MyCalendarTwo(object): + + def __init__(self): + self.__overlaps = [] + self.__calendar = [] + + + def book(self, start, end): + """ + :type start: int + :type end: int + :rtype: bool + """ + for i, j in self.__overlaps: + if start < j and end > i: + return False + for i, j in self.__calendar: + if start < j and end > i: + self.__overlaps.append((max(start, i), min(end, j))) + self.__calendar.append((start, end)) + return True + + +# Your MyCalendarTwo object will be instantiated and called as such: +# obj = MyCalendarTwo() +# param_1 = obj.book(start,end) diff --git a/Python/my-calendar-iii.py b/Python/my-calendar-iii.py new file mode 100644 index 000000000..985a001a6 --- /dev/null +++ b/Python/my-calendar-iii.py @@ -0,0 +1,69 @@ +# Time: O(n^2) +# Space: O(n) + +# Implement a MyCalendarThree class to store your events. A new event can always be added. +# +# Your class will have one method, book(int start, int end). +# Formally, this represents a booking on the half open interval [start, end), +# the range of real numbers x such that start <= x < end. +# +# A K-booking happens when K events have some non-empty intersection +# (ie., there is some time that is common to all K events.) +# +# For each call to the method MyCalendar.book, +# return an integer K representing the largest integer such that there exists a K-booking in the calendar. +# +# Your class will be called like this: +# MyCalendarThree cal = new MyCalendarThree(); MyCalendarThree.book(start, end) +# Example 1: +# MyCalendarThree(); +# MyCalendarThree.book(10, 20); // returns 1 +# MyCalendarThree.book(50, 60); // returns 1 +# MyCalendarThree.book(10, 40); // returns 2 +# MyCalendarThree.book(5, 15); // returns 3 +# MyCalendarThree.book(5, 10); // returns 3 +# MyCalendarThree.book(25, 55); // returns 3 +# Explanation: +# The first two events can be booked and are disjoint, so the maximum K-booking is a 1-booking. +# The third event [10, 40) intersects the first event, and the maximum K-booking is a 2-booking. +# The remaining events cause the maximum K-booking to be only a 3-booking. +# Note that the last event locally causes a 2-booking, but the answer is still 3 because +# eg. [10, 20), [10, 40), and [5, 15) are still triple booked. +# Note: +# - The number of calls to MyCalendarThree.book per test case will be at most 400. +# - In calls to MyCalendarThree.book(start, end), start and end are integers in the range [0, 10^9]. + +class MyCalendarThree(object): + + def __init__(self): + self.__books = [] + + + def book(self, start, end): + """ + :type start: int + :type end: int + :rtype: int + """ + i = bisect.bisect_left(self.__books, (start, 1)) + if i < len(self.__books) and self.__books[i][0] == start: + self.__books[i] = (self.__books[i][0], self.__books[i][1]+1) + else: + self.__books.insert(i, (start, 1)) + + j = bisect.bisect_left(self.__books, (end, 1)) + if j < len(self.__books) and self.__books[j][0] == end: + self.__books[j] = (self.__books[j][0], self.__books[j][1]-1) + else: + self.__books.insert(j, (end, -1)) + + result, cnt = 0, 0 + for book in self.__books: + cnt += book[1] + result = max(result, cnt) + return result + + +# Your MyCalendarThree object will be instantiated and called as such: +# obj = MyCalendarThree() +# param_1 = obj.book(start,end) diff --git a/Python/nested-list-weight-sum-ii.py b/Python/nested-list-weight-sum-ii.py new file mode 100644 index 000000000..0594d091c --- /dev/null +++ b/Python/nested-list-weight-sum-ii.py @@ -0,0 +1,51 @@ +# Time: O(n) +# Space: O(h) + +# """ +# This is the interface that allows for creating nested lists. +# You should not implement it, or speculate about its implementation +# """ +#class NestedInteger(object): +# def isInteger(self): +# """ +# @return True if this NestedInteger holds a single integer, rather than a nested list. +# :rtype bool +# """ +# +# def getInteger(self): +# """ +# @return the single integer that this NestedInteger holds, if it holds a single integer +# Return None if this NestedInteger holds a nested list +# :rtype int +# """ +# +# def getList(self): +# """ +# @return the nested list that this NestedInteger holds, if it holds a nested list +# Return None if this NestedInteger holds a single integer +# :rtype List[NestedInteger] +# """ + +class Solution(object): + def depthSumInverse(self, nestedList): + """ + :type nestedList: List[NestedInteger] + :rtype: int + """ + def depthSumInverseHelper(list, depth, result): + if len(result) < depth + 1: + result.append(0) + if list.isInteger(): + result[depth] += list.getInteger() + else: + for l in list.getList(): + depthSumInverseHelper(l, depth + 1, result) + + result = [] + for list in nestedList: + depthSumInverseHelper(list, 0, result) + + sum = 0 + for i in reversed(xrange(len(result))): + sum += result[i] * (len(result) - i) + return sum diff --git a/Python/nested-list-weight-sum.py b/Python/nested-list-weight-sum.py new file mode 100644 index 000000000..f014799e1 --- /dev/null +++ b/Python/nested-list-weight-sum.py @@ -0,0 +1,43 @@ +# Time: O(n) +# Space: O(h) + +# """ +# This is the interface that allows for creating nested lists. +# You should not implement it, or speculate about its implementation +# """ +#class NestedInteger(object): +# def isInteger(self): +# """ +# @return True if this NestedInteger holds a single integer, rather than a nested list. +# :rtype bool +# """ +# +# def getInteger(self): +# """ +# @return the single integer that this NestedInteger holds, if it holds a single integer +# Return None if this NestedInteger holds a nested list +# :rtype int +# """ +# +# def getList(self): +# """ +# @return the nested list that this NestedInteger holds, if it holds a nested list +# Return None if this NestedInteger holds a single integer +# :rtype List[NestedInteger] +# """ + +class Solution(object): + def depthSum(self, nestedList): + """ + :type nestedList: List[NestedInteger] + :rtype: int + """ + def depthSumHelper(nestedList, depth): + res = 0 + for l in nestedList: + if l.isInteger(): + res += l.getInteger() * depth + else: + res += depthSumHelper(l.getList(), depth + 1) + return res + return depthSumHelper(nestedList, 1) diff --git a/Python/network-delay-time.py b/Python/network-delay-time.py new file mode 100644 index 000000000..b8f2a237f --- /dev/null +++ b/Python/network-delay-time.py @@ -0,0 +1,42 @@ +# Time: O(|E| + |V|log|V|) +# Space: O(|E| + |V|) + +# There are N network nodes, labelled 1 to N. +# +# Given times, a list of travel times as directed edges times[i] = (u, v, w), +# where u is the source node, v is the target node, +# and w is the time it takes for a signal to travel from source to target. +# +# Now, we send a signal from a certain node K. +# How long will it take for all nodes to receive the signal? If it is impossible, return -1. +# +# Note: +# - N will be in the range [1, 100]. +# - K will be in the range [1, N]. +# - The length of times will be in the range [1, 6000]. +# - All edges times[i] = (u, v, w) will have 1 <= u, v <= N and 1 <= w <= 100. + +# Dijkstra's algorithm +class Solution(object): + def networkDelayTime(self, times, N, K): + """ + :type times: List[List[int]] + :type N: int + :type K: int + :rtype: int + """ + adj = [[] for _ in xrange(N)] + for u, v, w in times: + adj[u-1].append((v-1, w)) + + result = 0 + lookup = set() + min_heap = [(0, K-1)] + while min_heap and len(lookup) != N: + result, u = heapq.heappop(min_heap) + lookup.add(u) + for v, w in adj[u]: + if v in lookup: continue + heapq.heappush(min_heap, (result+w, v)) + return result if len(lookup) == N else -1 + diff --git a/Python/next-closest-time.py b/Python/next-closest-time.py new file mode 100644 index 000000000..d69cd9ed2 --- /dev/null +++ b/Python/next-closest-time.py @@ -0,0 +1,40 @@ +# Time: O(1) +# Space: O(1) + +# Given a time represented in the format "HH:MM", +# form the next closest time by reusing the current digits. +# There is no limit on how many times a digit can be reused. +# +# You may assume the given input string is always valid. +# For example, "01:34", "12:09" are all valid. "1:34", "12:9" are all invalid. +# +# Example 1: +# +# Input: "19:34" +# Output: "19:39" +# Explanation: The next closest time choosing from digits 1, 9, 3, 4, is 19:39, which occurs 5 minutes later. +# It is not 19:33, because this occurs 23 hours and 59 minutes later. +# +# Example 2: +# +# Input: "23:59" +# Output: "22:22" +# Explanation: The next closest time choosing from digits 2, 3, 5, 9, is 22:22. +# It may be assumed that the returned time is next day's time since it is smaller than the input time numerically. + +class Solution(object): + def nextClosestTime(self, time): + """ + :type time: str + :rtype: str + """ + h, m = time.split(":") + curr = int(h) * 60 + int(m) + result = None + for i in xrange(curr+1, curr+1441): + t = i % 1440 + h, m = t // 60, t % 60 + result = "%02d:%02d" % (h, m) + if set(result) <= set(time): + break + return result diff --git a/Python/next-greater-element-i.py b/Python/next-greater-element-i.py new file mode 100644 index 000000000..10463b33a --- /dev/null +++ b/Python/next-greater-element-i.py @@ -0,0 +1,41 @@ +# Time: O(m + n) +# Space: O(m + n) + +# You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. +# Find all the next greater numbers for nums1's elements in the corresponding places of nums2. +# +# The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. +# If it does not exist, output -1 for this number. +# +# Example 1: +# Input: nums1 = [4,1,2], nums2 = [1,3,4,2]. +# Output: [-1,3,-1] +# Explanation: +# For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1. +# For number 1 in the first array, the next greater number for it in the second array is 3. +# For number 2 in the first array, there is no next greater number for it in the second array, so output -1. +# Example 2: +# Input: nums1 = [2,4], nums2 = [1,2,3,4]. +# Output: [3,-1] +# Explanation: +# For number 2 in the first array, the next greater number for it in the second array is 3. +# For number 4 in the first array, there is no next greater number for it in the second array, so output -1. +# Note: +# All elements in nums1 and nums2 are unique. +# The length of both nums1 and nums2 would not exceed 1000. + +class Solution(object): + def nextGreaterElement(self, findNums, nums): + """ + :type findNums: List[int] + :type nums: List[int] + :rtype: List[int] + """ + stk, lookup = [], {} + for num in nums: + while stk and num > stk[-1]: + lookup[stk.pop()] = num + stk.append(num) + while stk: + lookup[stk.pop()] = -1 + return map(lambda x : lookup[x], findNums) diff --git a/Python/next-greater-element-ii.py b/Python/next-greater-element-ii.py new file mode 100644 index 000000000..03ee1c106 --- /dev/null +++ b/Python/next-greater-element-ii.py @@ -0,0 +1,30 @@ +# Time: O(n) +# Space: O(n) + +# Given a circular array (the next element of the last element is the first element of the array), +# print the Next Greater Number for every element. +# The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, +# which means you could search circularly to find its next greater number. +# If it doesn't exist, output -1 for this number. +# +# Example 1: +# Input: [1,2,1] +# Output: [2,-1,2] +# Explanation: The first 1's next greater number is 2; +# The number 2 can't find next greater number; +# The second 1's next greater number needs to search circularly, which is also 2. +# Note: The length of given array won't exceed 10000. + +class Solution(object): + def nextGreaterElements(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + result, stk = [0] * len(nums), [] + for i in reversed(xrange(2*len(nums))): + while stk and stk[-1] <= nums[i % len(nums)]: + stk.pop() + result[i % len(nums)] = stk[-1] if stk else -1 + stk.append(nums[i % len(nums)]) + return result diff --git a/Python/next-greater-element-iii.py b/Python/next-greater-element-iii.py new file mode 100644 index 000000000..9a4f344ea --- /dev/null +++ b/Python/next-greater-element-iii.py @@ -0,0 +1,38 @@ +# Time: O(logn) = O(1) +# Space: O(logn) = O(1) + +# Given a positive 32-bit integer n, you need to find the smallest 32-bit integer +# which has exactly the same digits existing in the integer n and is greater in value than n. +# If no such positive 32-bit integer exists, you need to return -1. +@ +# Example 1: +# Input: 12 +# Output: 21 +# Example 2: +# Input: 21 +# Output: -1 + +class Solution(object): + def nextGreaterElement(self, n): + """ + :type n: int + :rtype: int + """ + digits = map(int, list(str(n))) + k, l = -1, 0 + for i in xrange(len(digits) - 1): + if digits[i] < digits[i + 1]: + k = i + + if k == -1: + digits.reverse() + return -1 + + for i in xrange(k + 1, len(digits)): + if digits[i] > digits[k]: + l = i + + digits[k], digits[l] = digits[l], digits[k] + digits[k + 1:] = digits[:k:-1] + result = int("".join(map(str, digits))) + return -1 if result >= 0x7FFFFFFF else result diff --git a/Python/next-permutation.py b/Python/next-permutation.py index 6af93140a..48056e9c6 100644 --- a/Python/next-permutation.py +++ b/Python/next-permutation.py @@ -14,8 +14,8 @@ # class Solution: - # @param num, a list of integer - # @return a list of integer + # @param {integer[]} nums + # @return {void} Do not return anything, modify nums in-place instead. def nextPermutation(self, num): k, l = -1, 0 for i in xrange(len(num) - 1): @@ -23,20 +23,21 @@ def nextPermutation(self, num): k = i if k == -1: - return num[::-1] + num.reverse() + return - for i in xrange(len(num)): + for i in xrange(k + 1, len(num)): if num[i] > num[k]: l = i num[k], num[l] = num[l], num[k] - return num[:k + 1] + num[:k:-1] + num[k + 1:] = num[:k:-1] if __name__ == "__main__": num = [1, 4, 3, 2] - num = Solution().nextPermutation(num) + Solution().nextPermutation(num) print num - num = Solution().nextPermutation(num) + Solution().nextPermutation(num) + print num + Solution().nextPermutation(num) print num - num = Solution().nextPermutation(num) - print num \ No newline at end of file diff --git a/Python/nim-game.py b/Python/nim-game.py new file mode 100644 index 000000000..f1eadb01a --- /dev/null +++ b/Python/nim-game.py @@ -0,0 +1,26 @@ +# Time: O(1) +# Space: O(1) +# +# You are playing the following Nim Game with your friend: +# There is a heap of stones on the table, each time one of +# you take turns to remove 1 to 3 stones. +# The one who removes the last stone will be the winner. +# You will take the first turn to remove the stones. +# +# Both of you are very clever and have optimal strategies for +# the game. Write a function to determine whether you can win +# the game given the number of stones in the heap. +# +# For example, if there are 4 stones in the heap, then you will +# never win the game: no matter 1, 2, or 3 stones you remove, +# the last stone will always be removed by your friend. +# + + +class Solution(object): + def canWinNim(self, n): + """ + :type n: int + :rtype: bool + """ + return n % 4 != 0 diff --git a/Python/non-decreasing-array.py b/Python/non-decreasing-array.py new file mode 100644 index 000000000..e5e51c42f --- /dev/null +++ b/Python/non-decreasing-array.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# Given an array with n integers, your task is to check if +# it could become non-decreasing by modifying at most 1 element. +# +# We define an array is non-decreasing if array[i] <= array[i + 1] holds for every i (1 <= i < n). +# +# Example 1: +# Input: [4,2,3] +# Output: True +# Explanation: You could modify the first +# 4 +# to +# 1 +# to get a non-decreasing array. +# Example 2: +# Input: [4,2,1] +# Output: False +# Explanation: You can't get a non-decreasing array by modify at most one element. +# Note: The n belongs to [1, 10,000]. + +class Solution(object): + def checkPossibility(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + modified, prev = False, nums[0] + for i in xrange(1, len(nums)): + if prev > nums[i]: + if modified: + return False + if i-2 < 0 or nums[i-2] <= nums[i]: + prev = nums[i] # nums[i-1] = nums[i], prev = nums[i] +# else: +# prev = nums[i-1] # nums[i] = nums[i-1], prev = nums[i] + modified = True + else: + prev = nums[i] + return True + diff --git a/Python/non-negative-integers-without-consecutive-ones.py b/Python/non-negative-integers-without-consecutive-ones.py new file mode 100644 index 000000000..37d59f055 --- /dev/null +++ b/Python/non-negative-integers-without-consecutive-ones.py @@ -0,0 +1,41 @@ +# Time: O(1) +# Space: O(1) + +# Given a positive integer n, find the number of non-negative integers less than +# or equal to n, whose binary representations do NOT contain consecutive ones. +# +# Example 1: +# Input: 5 +# Output: 5 +# Explanation: +# Here are the non-negative integers <= 5 with their corresponding binary representations: +# 0 : 0 +# 1 : 1 +# 2 : 10 +# 3 : 11 +# 4 : 100 +# 5 : 101 +# Among them, only integer 3 disobeys the rule (two consecutive ones) and the other 5 satisfy the rule. +# Note: 1 <= n <= 10^9 + +class Solution(object): + def findIntegers(self, num): + """ + :type num: int + :rtype: int + """ + dp = [0] * 32 + dp[0], dp[1] = 1, 2 + for i in xrange(2, len(dp)): + dp[i] = dp[i-1] + dp[i-2] + result, prev_bit = 0, 0 + for i in reversed(xrange(31)): + if (num & (1 << i)) != 0: + result += dp[i] + if prev_bit == 1: + result -= 1 + break + prev_bit = 1 + else: + prev_bit = 0 + return result + 1 diff --git a/Python/non-overlapping-intervals.py b/Python/non-overlapping-intervals.py new file mode 100644 index 000000000..16a204dd6 --- /dev/null +++ b/Python/non-overlapping-intervals.py @@ -0,0 +1,50 @@ +# Time: O(nlogn) +# Space: O(1) + +# Given a collection of intervals, find the minimum number of intervals +# you need to remove to make the rest of the intervals non-overlapping. +# +# Note: +# You may assume the interval's end point is always bigger than its start point. +# Intervals like [1,2] and [2,3] have borders "touching" but they don't overlap each other. +# Example 1: +# Input: [ [1,2], [2,3], [3,4], [1,3] ] +# +# Output: 1 +# +# Explanation: [1,3] can be removed and the rest of intervals are non-overlapping. +# Example 2: +# Input: [ [1,2], [1,2], [1,2] ] +# +# Output: 2 +# +# Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping. +# Example 3: +# Input: [ [1,2], [2,3] ] +# +# Output: 0 +# +# Explanation: You don't need to remove any of the intervals since they're already non-overlapping. + +# Definition for an interval. +# class Interval(object): +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution(object): + def eraseOverlapIntervals(self, intervals): + """ + :type intervals: List[Interval] + :rtype: int + """ + intervals.sort(key=lambda interval: interval.start) + result, prev = 0, 0 + for i in xrange(1, len(intervals)): + if intervals[i].start < intervals[prev].end: + if intervals[i].end < intervals[prev].end: + prev = i + result += 1 + else: + prev = i + return result diff --git a/Python/nth-digit.py b/Python/nth-digit.py new file mode 100644 index 000000000..e0c7b72a3 --- /dev/null +++ b/Python/nth-digit.py @@ -0,0 +1,45 @@ +# Time: O(logn) +# Space: O(1) + +# Find the nth digit of the infinite integer sequence +# 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... +# +# Note: +# n is positive and will fit within the range of a 32-bit signed integer (n < 231). +# +# Example 1: +# +# Input: +# 3 +# +# Output: +# 3 +# Example 2: +# +# Input: +# 11 +# +# Output: +# 0 +# +# Explanation: +# The 11th digit of the sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, +# ... is a 0, which is part of the number 10. + +class Solution(object): + def findNthDigit(self, n): + """ + :type n: int + :rtype: int + """ + digit_len = 1 + while n > digit_len * 9 * (10 ** (digit_len-1)): + n -= digit_len * 9 * (10 ** (digit_len-1)) + digit_len += 1 + + num = 10 ** (digit_len-1) + (n-1)/digit_len + + nth_digit = num / (10 ** ((digit_len-1) - ((n-1)%digit_len))) + nth_digit %= 10 + + return nth_digit diff --git a/Python/number-complement.py b/Python/number-complement.py new file mode 100644 index 000000000..5e628b8e6 --- /dev/null +++ b/Python/number-complement.py @@ -0,0 +1,34 @@ +# Time: O(1) +# Space: O(1) + +# Given a positive integer, output its complement number. +# The complement strategy is to flip the bits of its binary representation. +# +# Note: +# The given integer is guaranteed to fit within the range of a 32-bit signed integer. +# You could assume no leading zero bit in the integer’s binary representation. +# Example 1: +# Input: 5 +# Output: 2 +# Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2. +# Example 2: +# Input: 1 +# Output: 0 +# Explanation: The binary representation of 1 is 1 (no leading zero bits), and its complement is 0. So you need to output 0. + + +class Solution(object): + def findComplement(self, num): + """ + :type num: int + :rtype: int + """ + return 2 ** (len(bin(num)) - 2) - 1 - num + + +class Solution2(object): + def findComplement(self, num): + i = 1 + while i <= num: + i <<= 1 + return (i - 1) ^ num diff --git a/Python/number-of-1-bits.py b/Python/number-of-1-bits.py new file mode 100644 index 000000000..1d3f12f2a --- /dev/null +++ b/Python/number-of-1-bits.py @@ -0,0 +1,21 @@ +# Time: O(logn) = O(32) +# Space: O(1) +# +# Write a function that takes an unsigned integer +# and returns the number of '1' bits it has (also known as the Hamming weight). +# +# For example, the 32-bit integer '11' has binary representation 00000000000000000000000000001011, +# so the function should return 3. +# +class Solution: + # @param n, an integer + # @return an integer + def hammingWeight(self, n): + result = 0 + while n: + n &= n - 1 + result += 1 + return result + +if __name__ == '__main__': + print Solution().hammingWeight(11) diff --git a/Python/number-of-atoms.py b/Python/number-of-atoms.py new file mode 100644 index 000000000..ca0bb7fab --- /dev/null +++ b/Python/number-of-atoms.py @@ -0,0 +1,68 @@ +# Time: O(n) +# Space: O(n) + +# Given a chemical formula (given as a string), return the count of each atom. +# +# An atomic element always starts with an uppercase character, +# then zero or more lowercase letters, representing the name. +# +# 1 or more digits representing the count of that element may follow if the count is greater than 1. +# If the count is 1, no digits will follow. For example, H2O and H2O2 are possible, but H1O2 is impossible. +# +# Two formulas concatenated together produce another formula. For example, H2O2He3Mg4 is also a formula. +# +# A formula placed in parentheses, and a count (optionally added) is also a formula. +# For example, (H2O2) and (H2O2)3 are formulas. +# +# Given a formula, output the count of all elements as a string in the following form: +# the first name (in sorted order), followed by its count (if that count is more than 1), +# followed by the second name (in sorted order), +# followed by its count (if that count is more than 1), and so on. +# +# Example 1: +# Input: +# formula = "H2O" +# Output: "H2O" +# Explanation: +# The count of elements are {'H': 2, 'O': 1}. +# +# Example 2: +# Input: +# formula = "Mg(OH)2" +# Output: "H2MgO2" +# Explanation: +# The count of elements are {'H': 2, 'Mg': 1, 'O': 2}. +# +# Example 3: +# Input: +# formula = "K4(ON(SO3)2)2" +# Output: "K4N2O14S4" +# Explanation: +# The count of elements are {'K': 4, 'N': 2, 'O': 14, 'S': 4}. +# Note: +# +# All atom names consist of lowercase letters, except for the first character which is uppercase. +# The length of formula will be in the range [1, 1000]. +# formula will only consist of letters, digits, and round parentheses, +# and is a valid formula as defined in the problem. + +class Solution(object): + def countOfAtoms(self, formula): + """ + :type formula: str + :rtype: str + """ + parse = re.findall(r"([A-Z][a-z]*)(\d*)|(\()|(\))(\d*)", formula) + stk = [collections.Counter()] + for name, m1, left_open, right_open, m2 in parse: + if name: + stk[-1][name] += int(m1 or 1) + if left_open: + stk.append(collections.Counter()) + if right_open: + top = stk.pop() + for k, v in top.iteritems(): + stk[-1][k] += v * int(m2 or 1) + + return "".join(name + (str(stk[-1][name]) if stk[-1][name] > 1 else '') \ + for name in sorted(stk[-1])) diff --git a/Python/number-of-boomerangs.py b/Python/number-of-boomerangs.py new file mode 100644 index 000000000..e31756e0f --- /dev/null +++ b/Python/number-of-boomerangs.py @@ -0,0 +1,58 @@ +# Time: O(n^2) +# Space: O(n) + +# Given n points in the plane that are all pairwise distinct, +# a "boomerang" is a tuple of points (i, j, k) such that the distance +# between i and j equals the distance between i and k (the order of the tuple matters). +# +# Find the number of boomerangs. You may assume that n will be at most 500 +# and coordinates of points are all in the range [-10000, 10000] (inclusive). +# +# Example: +# Input: +# [[0,0],[1,0],[2,0]] +# +# Output: +# 2 +# +# Explanation: +# The two boomerangs are [[1,0],[0,0],[2,0]] and [[1,0],[2,0],[0,0]] +import collections + + +class Solution(object): + def numberOfBoomerangs(self, points): + """ + :type points: List[List[int]] + :rtype: int + """ + result = 0 + + for i in xrange(len(points)): + group = collections.defaultdict(int) + for j in xrange(len(points)): + if j == i: + continue + dx, dy = points[i][0] - points[j][0], points[i][1] - points[j][1] + group[dx**2 + dy**2] += 1 + + for _, v in group.iteritems(): + if v > 1: + result += v * (v-1) + + return result + + def numberOfBoomerangs2(self, points): + """ + :type points: List[List[int]] + :rtype: int + """ + cnt = 0 + for a, i in enumerate(points): + dis_list = [] + for b, k in enumerate(points[:a] + points[a + 1:]): + dis_list.append((k[0] - i[0]) ** 2 + (k[1] - i[1]) ** 2) + for z in collections.Counter(dis_list).values(): + if z > 1: + cnt += z * (z - 1) + return cnt diff --git a/Python/number-of-connected-components-in-an-undirected-graph.py b/Python/number-of-connected-components-in-an-undirected-graph.py new file mode 100644 index 000000000..e8b27f59e --- /dev/null +++ b/Python/number-of-connected-components-in-an-undirected-graph.py @@ -0,0 +1,31 @@ +# Time: O(nlog*n) ~= O(n), n is the length of the positions +# Space: O(n) + +class UnionFind(object): + def __init__(self, n): + self.set = range(n) + self.count = n + + def find_set(self, x): + if self.set[x] != x: + self.set[x] = self.find_set(self.set[x]) # path compression. + return self.set[x] + + def union_set(self, x, y): + x_root, y_root = map(self.find_set, (x, y)) + if x_root != y_root: + self.set[min(x_root, y_root)] = max(x_root, y_root) + self.count -= 1 + + +class Solution(object): + def countComponents(self, n, edges): + """ + :type n: int + :type edges: List[List[int]] + :rtype: int + """ + union_find = UnionFind(n) + for i, j in edges: + union_find.union_set(i, j) + return union_find.count diff --git a/Python/number-of-corner-rectangles.py b/Python/number-of-corner-rectangles.py new file mode 100644 index 000000000..6dbe75bee --- /dev/null +++ b/Python/number-of-corner-rectangles.py @@ -0,0 +1,50 @@ +# Time: O(n * m^2), n is the number of rows with 1s, m is the number of cols with 1s +# Space: O(n * m) + +# Given a grid where each entry is only 0 or 1, find the number of corner rectangles. +# +# A corner rectangle is 4 distinct 1s on the grid that form an axis-aligned rectangle. +# Note that only the corners need to have the value 1. Also, all four 1s used must be distinct. +# +# Example 1: +# Input: grid = +# [[1, 0, 0, 1, 0], +# [0, 0, 1, 0, 1], +# [0, 0, 0, 1, 0], +# [1, 0, 1, 0, 1]] +# Output: 1 +# Explanation: There is only one corner rectangle, with corners grid[1][2], grid[1][4], grid[3][2], grid[3][4]. +# +# Example 2: +# Input: grid = +# [[1, 1, 1], +# [1, 1, 1], +# [1, 1, 1]] +# Output: 9 +# Explanation: There are four 2x2 rectangles, four 2x3 and 3x2 rectangles, and one 3x3 rectangle. +# +# Example 3: +# Input: grid = +# [[1, 1, 1, 1]] +# Output: 0 +# Explanation: Rectangles must have four distinct corners. +# Note: +# - The number of rows and columns of grid will each be in the range [1, 200]. +# - Each grid[i][j] will be either 0 or 1. +# - The number of 1s in the grid will be at most 6000. + +class Solution(object): + def countCornerRectangles(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + rows = [[c for c, val in enumerate(row) if val] + for row in grid] + result = 0 + for i in xrange(len(rows)): + lookup = set(rows[i]) + for j in xrange(i): + count = sum(1 for c in rows[j] if c in lookup) + result += count*(count-1)/2 + return result diff --git a/Python/number-of-digit-one.py b/Python/number-of-digit-one.py new file mode 100644 index 000000000..97dcab395 --- /dev/null +++ b/Python/number-of-digit-one.py @@ -0,0 +1,39 @@ +# Time: O(logn) +# Space: O(1) +# +# Given an integer n, count the total number of digit 1 appearing +# in all non-negative integers less than or equal to n. +# +# For example: +# Given n = 13, +# Return 6, because digit 1 occurred in the following numbers: +# 1, 10, 11, 12, 13. +# + +class Solution: + # @param {integer} n + # @return {integer} + def countDigitOne(self, n): + k = 1; + cnt, multiplier, left_part = 0, 1, n + + while left_part > 0: + # split number into: left_part, curr, right_part + curr = left_part % 10 + right_part = n % multiplier + + # count of (c000 ~ oooc000) = (ooo + (k < curr)? 1 : 0) * 1000 + cnt += (left_part / 10 + (k < curr)) * multiplier + + # if k == 0, oooc000 = (ooo - 1) * 1000 + if k == 0 and multiplier > 1: + cnt -= multiplier + + # count of (oook000 ~ oookxxx): count += xxx + 1 + if curr == k: + cnt += right_part + 1 + + left_part /= 10 + multiplier *= 10 + + return cnt diff --git a/Python/number-of-distinct-islands-ii.py b/Python/number-of-distinct-islands-ii.py new file mode 100644 index 000000000..4b1197c5c --- /dev/null +++ b/Python/number-of-distinct-islands-ii.py @@ -0,0 +1,44 @@ +# Time: O((m * n) * log(m * n)) +# Space: O(m * n) + +class Solution(object): + def numDistinctIslands2(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + + def dfs(i, j, grid, island): + if not (0 <= i < len(grid) and \ + 0 <= j < len(grid[0]) and \ + grid[i][j] > 0): + return False + grid[i][j] *= -1 + island.append((i, j)); + for d in directions: + dfs(i+d[0], j+d[1], grid, island) + return True + + def normalize(island): + shapes = [[] for _ in xrange(8)] + for x, y in island: + rotations_and_reflections = [[ x, y], [ x, -y], [-x, y], [-x, -y], + [ y, x], [ y, -x], [-y, x], [-y, -x]] + for i in xrange(len(rotations_and_reflections)): + shapes[i].append(rotations_and_reflections[i]) + for shape in shapes: + shape.sort() # Time: O(ilogi), i is the size of the island, the max would be (m * n) + origin = list(shape[0]) + for p in shape: + p[0] -= origin[0] + p[1] -= origin[1] + return min(shapes) + + islands = set() + for i in xrange(len(grid)): + for j in xrange(len(grid[0])): + island = [] + if dfs(i, j, grid, island): + islands.add(str(normalize(island))) + return len(islands) diff --git a/Python/number-of-distinct-islands.py b/Python/number-of-distinct-islands.py new file mode 100644 index 000000000..dc471e867 --- /dev/null +++ b/Python/number-of-distinct-islands.py @@ -0,0 +1,30 @@ +# Time: O(m * n) +# Space: O(m * n) + +class Solution(object): + def numDistinctIslands(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + directions = {'l':[-1, 0], 'r':[ 1, 0], \ + 'u':[ 0, 1], 'd':[ 0, -1]} + + def dfs(i, j, grid, island): + if not (0 <= i < len(grid) and \ + 0 <= j < len(grid[0]) and \ + grid[i][j] > 0): + return False + grid[i][j] *= -1 + for k, v in directions.iteritems(): + island.append(k); + dfs(i+v[0], j+v[1], grid, island) + return True + + islands = set() + for i in xrange(len(grid)): + for j in xrange(len(grid[0])): + island = [] + if dfs(i, j, grid, island): + islands.add("".join(island)) + return len(islands) diff --git a/Python/number-of-islands-ii.py b/Python/number-of-islands-ii.py new file mode 100644 index 000000000..3c36a265e --- /dev/null +++ b/Python/number-of-islands-ii.py @@ -0,0 +1,43 @@ +# Time: O(klog*k) ~= O(k), k is the length of the positions +# Space: O(k) + +class Solution(object): + def numIslands2(self, m, n, positions): + """ + :type m: int + :type n: int + :type positions: List[List[int]] + :rtype: List[int] + """ + def node_id(node, n): + return node[0] * n + node[1] + + def find_set(x): + if set[x] != x: + set[x] = find_set(set[x]) # path compression. + return set[x] + + def union_set(x, y): + x_root, y_root = find_set(x), find_set(y) + set[min(x_root, y_root)] = max(x_root, y_root) + + numbers = [] + number = 0 + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + set = {} + for position in positions: + node = (position[0], position[1]) + set[node_id(node, n)] = node_id(node, n) + number += 1 + + for d in directions: + neighbor = (position[0] + d[0], position[1] + d[1]) + if 0 <= neighbor[0] < m and 0 <= neighbor[1] < n and \ + node_id(neighbor, n) in set: + if find_set(node_id(node, n)) != find_set(node_id(neighbor, n)): + # Merge different islands, amortised time: O(log*k) ~= O(1) + union_set(node_id(node, n), node_id(neighbor, n)) + number -= 1 + numbers.append(number) + + return numbers diff --git a/Python/number-of-islands.py b/Python/number-of-islands.py new file mode 100644 index 000000000..03d93dd0b --- /dev/null +++ b/Python/number-of-islands.py @@ -0,0 +1,56 @@ +# Time: O(m * n) +# Space: O(m * n) +# +# Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. +# An island is surrounded by water and is formed by connecting adjacent lands horizontally +# or vertically. You may assume all four edges of the grid are all surrounded by water. +# +# Example 1: +# +# 11110 +# 11010 +# 11000 +# 00000 +# Answer: 1 +# +# Example 2: +# +# 11000 +# 11000 +# 00100 +# 00011 +# Answer: 3 +# + +class Solution: + # @param {boolean[][]} grid a boolean 2D matrix + # @return {int} an integer + def numIslands(self, grid): + if not grid: + return 0 + + row = len(grid) + col = len(grid[0]) + used = [[False for j in xrange(col)] for i in xrange(row)] + + count = 0 + for i in xrange(row): + for j in xrange(col): + if grid[i][j] == '1' and not used[i][j]: + self.dfs(grid, used, row, col, i, j) + count += 1 + return count + + def dfs(self, grid, used, row, col, x, y): + if grid[x][y] == '0' or used[x][y]: + return + used[x][y] = True + + if x != 0: + self.dfs(grid, used, row, col, x - 1, y) + if x != row - 1: + self.dfs(grid, used, row, col, x + 1, y) + if y != 0: + self.dfs(grid, used, row, col, x, y - 1) + if y != col - 1: + self.dfs(grid, used, row, col, x, y + 1) diff --git a/Python/number-of-longest-increasing-subsequence.py b/Python/number-of-longest-increasing-subsequence.py new file mode 100644 index 000000000..9a45cadb1 --- /dev/null +++ b/Python/number-of-longest-increasing-subsequence.py @@ -0,0 +1,38 @@ +# Time: O(n^2) +# Space: O(n) + +# Given an unsorted array of integers, find the number of longest increasing subsequence. +# +# Example 1: +# Input: [1,3,5,4,7] +# Output: 2 +# Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7]. +# Example 2: +# Input: [2,2,2,2,2] +# Output: 5 +# Explanation: The length of longest continuous increasing subsequence is 1, and there are +# 5 subsequences' length is 1, so output 5. +# Note: Length of the given array will be not exceed 2000 and the answer is guaranteed +# to be fit in 32-bit signed int. + +class Solution(object): + def findNumberOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result, max_len = 0, 0 + dp = [[1, 1] for _ in xrange(len(nums))] # {length, number} pair + for i in xrange(len(nums)): + for j in xrange(i): + if nums[i] > nums[j]: + if dp[i][0] == dp[j][0]+1: + dp[i][1] += dp[j][1] + elif dp[i][0] < dp[j][0]+1: + dp[i] = [dp[j][0]+1, dp[j][1]] + if max_len == dp[i][0]: + result += dp[i][1] + elif max_len < dp[i][0]: + max_len = dp[i][0] + result = dp[i][1] + return result diff --git a/Python/number-of-segments-in-a-string.py b/Python/number-of-segments-in-a-string.py new file mode 100644 index 000000000..1a5c0086f --- /dev/null +++ b/Python/number-of-segments-in-a-string.py @@ -0,0 +1,34 @@ +# Time: O(n) +# Space: O(1) + +# Count the number of segments in a string, +# where a segment is defined to be a contiguous +# sequence of non-space characters. +# +# Please note that the string does not +# contain any non-printable characters. +# +# Example: +# +# Input: "Hello, my name is John" +# Output: 5 + + +class Solution(object): + def countSegments(self, s): + """ + :type s: str + :rtype: int + """ + result = int(len(s) and s[-1] != ' ') + for i in xrange(1, len(s)): + if s[i] == ' ' and s[i-1] != ' ': + result += 1 + return result + + def countSegments2(self, s): + """ + :type s: str + :rtype: int + """ + return len([i for i in s.strip().split(' ') if i]) diff --git a/Python/odd-even-linked-list.py b/Python/odd-even-linked-list.py new file mode 100644 index 000000000..457c48ac3 --- /dev/null +++ b/Python/odd-even-linked-list.py @@ -0,0 +1,43 @@ +# Time: O(n) +# Space: O(1) + +# Given a singly linked list, group all odd nodes +# together followed by the even nodes. +# Please note here we are talking about the node number +# and not the value in the nodes. +# +# You should try to do it in place. The program should run +# in O(1) space complexity and O(nodes) time complexity. +# +# Example: +# Given 1->2->3->4->5->NULL, +# return 1->3->5->2->4->NULL. +# +# Note: +# The relative order inside both the even and odd groups +# should remain as it was in the input. +# The first node is considered odd, the second node even +# and so on ... + +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution(object): + def oddEvenList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if head: + odd_tail, cur = head, head.next + while cur and cur.next: + even_head = odd_tail.next + odd_tail.next = cur.next + odd_tail = odd_tail.next + cur.next = odd_tail.next + odd_tail.next = even_head + cur = cur.next + return head diff --git a/Python/one-edit-distance.py b/Python/one-edit-distance.py index 8a5dd426b..4e11cfe29 100644 --- a/Python/one-edit-distance.py +++ b/Python/one-edit-distance.py @@ -4,11 +4,13 @@ # Given two strings S and T, determine if they are both one edit distance apart. # -class Solution: - # @param s, a string - # @param t, a string - # @return a boolean +class Solution(object): def isOneEditDistance(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ m, n = len(s), len(t) if m > n: return self.isOneEditDistance(t, s) @@ -24,6 +26,7 @@ def isOneEditDistance(self, s, t): i += 1 return i == m - + + if __name__ == "__main__": - print Solution().isOneEditDistance("teacher", "acher") \ No newline at end of file + print Solution().isOneEditDistance("teacher", "acher") diff --git a/Python/ones-and-zeroes.py b/Python/ones-and-zeroes.py new file mode 100644 index 000000000..388bf960f --- /dev/null +++ b/Python/ones-and-zeroes.py @@ -0,0 +1,48 @@ +# Time: O(s * m * n), s is the size of the array. +# Space: O(m * n) + +# In the computer world, use restricted resource you have to +# generate maximum benefit is what we always want to pursue. +# +# For now, suppose you are a dominator of m 0s and n 1s respectively. +# On the other hand, there is an array with strings consisting of only 0s and 1s. +# +# Now your task is to find the maximum number of strings that you can form +# with given m 0s and n 1s. Each 0 and 1 can be used at most once. +# +# Note: +# The given numbers of 0s and 1s will both not exceed 100 +# The size of given string array won't exceed 600. +# Example 1: +# Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 +# Output: 4 +# +# Explanation: This are totally 4 strings can be formed +# by the using of 5 0s and 3 1s, which are “10,”0001”,”1”,”0” +# Example 2: +# Input: Array = {"10", "0", "1"}, m = 1, n = 1 +# Output: 2 +# +# Explanation: You could form "10", but then you'd have nothing left. Better form "0" and "1". + +class Solution(object): + def findMaxForm(self, strs, m, n): + """ + :type strs: List[str] + :type m: int + :type n: int + :rtype: int + """ + dp = [[0 for _ in xrange(n+1)] for _ in xrange(m+1)] + for s in strs: + zero_count, one_count = 0, 0 + for c in s: + if c == '0': + zero_count += 1 + elif c == '1': + one_count += 1 + + for i in reversed(xrange(zero_count, m+1)): + for j in reversed(xrange(one_count, n+1)): + dp[i][j] = max(dp[i][j], dp[i-zero_count][j-one_count]+1) + return dp[m][n] diff --git a/Python/optimal-account-balancing.py b/Python/optimal-account-balancing.py new file mode 100644 index 000000000..4d409c853 --- /dev/null +++ b/Python/optimal-account-balancing.py @@ -0,0 +1,37 @@ +# Time: O(n * 2^n), n is the size of the debt. +# Space: O(n * 2^n) + +class Solution(object): + def minTransfers(self, transactions): + """ + :type transactions: List[List[int]] + :rtype: int + """ + account = collections.defaultdict(int) + for transaction in transactions: + account[transaction[0]] += transaction[2] + account[transaction[1]] -= transaction[2] + + debt = [] + for v in account.values(): + if v: + debt.append(v) + + if not debt: + return 0 + + n = 1 << len(debt) + dp, subset = [float("inf")] * n, [] + for i in xrange(1, n): + net_debt, number = 0, 0 + for j in xrange(len(debt)): + if i & 1 << j: + net_debt += debt[j] + number += 1 + if net_debt == 0: + dp[i] = number - 1 + for s in subset: + if (i & s) == s: + dp[i] = min(dp[i], dp[s] + dp[i - s]) + subset.append(i) + return dp[-1] diff --git a/Python/optimal-division.py b/Python/optimal-division.py new file mode 100644 index 000000000..0435f174f --- /dev/null +++ b/Python/optimal-division.py @@ -0,0 +1,44 @@ +# Time: O(n) +# Space: O(1) + +# Given a list of positive integers, the adjacent integers will perform the float division. +# For example, [2,3,4] -> 2 / 3 / 4. +# +# However, you can add any number of parenthesis at any position to change the priority of operations. +# You should find out how to add parenthesis to get the maximum result, +# and return the corresponding expression in string format. Your expression should NOT contain redundant parenthesis. +# +# Example: +# Input: [1000,100,10,2] +# Output: "1000/(100/10/2)" +# Explanation: +# 1000/(100/10/2) = 1000/((100/10)/2) = 200 +# However, the bold parenthesis in "1000/((100/10)/2)" are redundant, +# since they don't influence the operation priority. So you should return "1000/(100/10/2)". +# +# Other cases: +# 1000/(100/10)/2 = 50 +# 1000/(100/(10/2)) = 50 +# 1000/100/10/2 = 0.5 +# 1000/100/(10/2) = 2 +# Note: +# +# The length of the input array is [1, 10]. +# Elements in the given array will be in range [2, 1000]. +# There is only one optimal division for each test case. + +class Solution(object): + def optimalDivision(self, nums): + """ + :type nums: List[int] + :rtype: str + """ + if len(nums) == 1: + return str(nums[0]) + if len(nums) == 2: + return str(nums[0]) + "/" + str(nums[1]) + result = [str(nums[0]) + "/(" + str(nums[1])] + for i in xrange(2, len(nums)): + result += "/" + str(nums[i]) + result += ")" + return "".join(result) diff --git a/Python/out-of-boundary-paths.py b/Python/out-of-boundary-paths.py new file mode 100644 index 000000000..259406840 --- /dev/null +++ b/Python/out-of-boundary-paths.py @@ -0,0 +1,42 @@ +# Time: O(N * m * n) +# Space: O(m * n) + +# There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, +# you can move the ball to adjacent cell or cross the grid boundary in +# four directions (up, down, left, right). However, you can at most move N times. +# Find out the number of paths to move the ball out of grid boundary. +# The answer may be very large, return it after mod 109 + 7. +# +# Example 1: +# Input:m = 2, n = 2, N = 2, i = 0, j = 0 +# Output: 6 +# +# Example 2: +# Input:m = 1, n = 3, N = 3, i = 0, j = 1 +# Output: 12 +# +# Note: +# Once you move the ball out of boundary, you cannot move it back. +# The length and height of the grid is in range [1,50]. +# N is in range [0,50]. + +class Solution(object): + def findPaths(self, m, n, N, x, y): + """ + :type m: int + :type n: int + :type N: int + :type x: int + :type y: int + :rtype: int + """ + M = 1000000000 + 7 + dp = [[[0 for _ in xrange(n)] for _ in xrange(m)] for _ in xrange(2)] + for moves in xrange(N): + for i in xrange(m): + for j in xrange(n): + dp[(moves + 1) % 2][i][j] = (((1 if (i == 0) else dp[moves % 2][i - 1][j]) + \ + (1 if (i == m - 1) else dp[moves % 2][i + 1][j])) % M + \ + ((1 if (j == 0) else dp[moves % 2][i][j - 1]) + \ + (1 if (j == n - 1) else dp[moves % 2][i][j + 1])) % M) % M + return dp[N % 2][x][y] diff --git a/Python/output-contest-matches.py b/Python/output-contest-matches.py new file mode 100644 index 000000000..1606a031e --- /dev/null +++ b/Python/output-contest-matches.py @@ -0,0 +1,14 @@ +# Time: O(n) +# Space: O(n) + +class Solution(object): + def findContestMatch(self, n): + """ + :type n: int + :rtype: str + """ + matches = map(str, range(1, n+1)) + while len(matches)/2: + matches = ["({},{})".format(matches[i], matches[-i-1]) for i in xrange(len(matches)/2)] + return matches[0] + diff --git a/Python/pacific-atlantic-water-flow.py b/Python/pacific-atlantic-water-flow.py new file mode 100644 index 000000000..57a0566e2 --- /dev/null +++ b/Python/pacific-atlantic-water-flow.py @@ -0,0 +1,68 @@ +# Time: O(m * n) +# Space: O(m * n) + +# Given an m x n matrix of non-negative integers representing the height of +# each unit cell in a continent, the "Pacific ocean" touches the left and +# top edges of the matrix and the "Atlantic ocean" touches the right and bottom edges. +# +# Water can only flow in four directions (up, down, left, or right) +# from a cell to another one with height equal or lower. +# +# Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean. +# +# Note: +# The order of returned grid coordinates does not matter. +# Both m and n are less than 150. +# Example: +# +# Given the following 5x5 matrix: +# +# Pacific ~ ~ ~ ~ ~ +# ~ 1 2 2 3 (5) * +# ~ 3 2 3 (4) (4) * +# ~ 2 4 (5) 3 1 * +# ~ (6) (7) 1 4 5 * +# ~ (5) 1 1 2 4 * +# * * * * * Atlantic +# +# Return: +# +# [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix). + +class Solution(object): + def pacificAtlantic(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: List[List[int]] + """ + PACIFIC, ATLANTIC = 1, 2 + + def pacificAtlanticHelper(matrix, x, y, prev_height, prev_val, visited, res): + if (not 0 <= x < len(matrix)) or \ + (not 0 <= y < len(matrix[0])) or \ + matrix[x][y] < prev_height or \ + (visited[x][y] | prev_val) == visited[x][y]: + return + + visited[x][y] |= prev_val + if visited[x][y] == (PACIFIC | ATLANTIC): + res.append((x, y)) + + for d in [(0, -1), (0, 1), (-1, 0), (1, 0)]: + pacificAtlanticHelper(matrix, x + d[0], y + d[1], matrix[x][y], visited[x][y], visited, res) + + if not matrix: + return [] + + res = [] + m, n = len(matrix),len(matrix[0]) + visited = [[0 for _ in xrange(n)] for _ in xrange(m)] + + for i in xrange(m): + pacificAtlanticHelper(matrix, i, 0, float("-inf"), PACIFIC, visited, res) + pacificAtlanticHelper(matrix, i, n - 1, float("-inf"), ATLANTIC, visited, res) + for j in xrange(n): + pacificAtlanticHelper(matrix, 0, j, float("-inf"), PACIFIC, visited, res) + pacificAtlanticHelper(matrix, m - 1, j, float("-inf"), ATLANTIC, visited, res) + + return res diff --git a/Python/paint-fence.py b/Python/paint-fence.py new file mode 100644 index 000000000..be60c6e62 --- /dev/null +++ b/Python/paint-fence.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# DP solution with rolling window. +class Solution(object): + def numWays(self, n, k): + """ + :type n: int + :type k: int + :rtype: int + """ + if n == 0: + return 0 + elif n == 1: + return k + ways = [0] * 3 + ways[0] = k + ways[1] = (k - 1) * ways[0] + k + for i in xrange(2, n): + ways[i % 3] = (k - 1) * (ways[(i - 1) % 3] + ways[(i - 2) % 3]) + return ways[(n - 1) % 3] + +# Time: O(n) +# Space: O(n) +# DP solution. +class Solution2(object): + def numWays(self, n, k): + """ + :type n: int + :type k: int + :rtype: int + """ + if n == 0: + return 0 + elif n == 1: + return k + ways = [0] * n + ways[0] = k + ways[1] = (k - 1) * ways[0] + k + for i in xrange(2, n): + ways[i] = (k - 1) * (ways[i - 1] + ways[i - 2]) + return ways[n - 1] diff --git a/Python/paint-house-ii.py b/Python/paint-house-ii.py new file mode 100644 index 000000000..724de0c42 --- /dev/null +++ b/Python/paint-house-ii.py @@ -0,0 +1,41 @@ +# Time: O(n * k) +# Space: O(k) + +class Solution2(object): + def minCostII(self, costs): + """ + :type costs: List[List[int]] + :rtype: int + """ + return min(reduce(self.combine, costs)) if costs else 0 + + def combine(self, tmp, house): + smallest, k, i = min(tmp), len(tmp), tmp.index(min(tmp)) + tmp, tmp[i] = [smallest] * k, min(tmp[:i] + tmp[i+1:]) + return map(sum, zip(tmp, house)) + + +class Solution2(object): + def minCostII(self, costs): + """ + :type costs: List[List[int]] + :rtype: int + """ + if not costs: + return 0 + + n = len(costs) + k = len(costs[0]) + min_cost = [costs[0], [0] * k] + for i in xrange(1, n): + smallest, second_smallest = float("inf"), float("inf") + for j in xrange(k): + if min_cost[(i - 1) % 2][j] < smallest: + smallest, second_smallest = min_cost[(i - 1) % 2][j], smallest + elif min_cost[(i - 1) % 2][j] < second_smallest: + second_smallest = min_cost[(i - 1) % 2][j] + for j in xrange(k): + min_j = smallest if min_cost[(i - 1) % 2][j] != smallest else second_smallest + min_cost[i % 2][j] = costs[i][j] + min_j + + return min(min_cost[(n - 1) % 2]) diff --git a/Python/paint-house.py b/Python/paint-house.py new file mode 100644 index 000000000..24e42a96b --- /dev/null +++ b/Python/paint-house.py @@ -0,0 +1,43 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def minCost(self, costs): + """ + :type costs: List[List[int]] + :rtype: int + """ + if not costs: + return 0 + + min_cost = [costs[0], [0, 0, 0]] + + n = len(costs) + for i in xrange(1, n): + min_cost[i % 2][0] = costs[i][0] + \ + min(min_cost[(i - 1) % 2][1], min_cost[(i - 1) % 2][2]) + min_cost[i % 2][1] = costs[i][1] + \ + min(min_cost[(i - 1) % 2][0], min_cost[(i - 1) % 2][2]) + min_cost[i % 2][2] = costs[i][2] + \ + min(min_cost[(i - 1) % 2][0], min_cost[(i - 1) % 2][1]) + + return min(min_cost[(n - 1) % 2]) + +# Time: O(n) +# Space: O(n) +class Solution2(object): + def minCost(self, costs): + """ + :type costs: List[List[int]] + :rtype: int + """ + if not costs: + return 0 + + n = len(costs) + for i in xrange(1, n): + costs[i][0] += min(costs[i - 1][1], costs[i - 1][2]) + costs[i][1] += min(costs[i - 1][0], costs[i - 1][2]) + costs[i][2] += min(costs[i - 1][0], costs[i - 1][1]) + + return min(costs[n - 1]) diff --git a/Python/palindrome-linked-list.py b/Python/palindrome-linked-list.py new file mode 100644 index 000000000..21f542737 --- /dev/null +++ b/Python/palindrome-linked-list.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space: O(1) +# +# Given a singly linked list, determine if it is a palindrome. +# +# Follow up: +# Could you do it in O(n) time and O(1) space? +# +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +# + +class Solution: + # @param {ListNode} head + # @return {boolean} + def isPalindrome(self, head): + reverse, fast = None, head + # Reverse the first half part of the list. + while fast and fast.next: + fast = fast.next.next + head.next, reverse, head = reverse, head, head.next + + # If the number of the nodes is odd, + # set the head of the tail list to the next of the median node. + tail = head.next if fast else head + + # Compare the reversed first half list with the second half list. + # And restore the reversed first half list. + is_palindrome = True + while reverse: + is_palindrome = is_palindrome and reverse.val == tail.val + reverse.next, head, reverse = head, reverse, reverse.next + tail = tail.next + + return is_palindrome diff --git a/Python/palindrome-pairs.py b/Python/palindrome-pairs.py new file mode 100644 index 000000000..bf823ce55 --- /dev/null +++ b/Python/palindrome-pairs.py @@ -0,0 +1,142 @@ +# Time: O(n * k^2), n is the number of the words, k is the max length of the words. +# Space: O(n * k) + +# Given a list of unique words. Find all pairs of indices (i, j) +# in the given list, so that the concatenation of the two words, +# i.e. words[i] + words[j] is a palindrome. +# +# Example 1: +# Given words = ["bat", "tab", "cat"] +# Return [[0, 1], [1, 0]] +# The palindromes are ["battab", "tabbat"] +# Example 2: +# Given words = ["abcd", "dcba", "lls", "s", "sssll"] +# Return [[0, 1], [1, 0], [3, 2], [2, 4]] +# The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"] + +class Solution(object): + def palindromePairs(self, words): + """ + :type words: List[str] + :rtype: List[List[int]] + """ + res = [] + lookup = {} + for i, word in enumerate(words): + lookup[word] = i + + for i in xrange(len(words)): + for j in xrange(len(words[i]) + 1): + prefix = words[i][j:] + suffix = words[i][:j] + if prefix == prefix[::-1] and \ + suffix[::-1] in lookup and lookup[suffix[::-1]] != i: + res.append([i, lookup[suffix[::-1]]]) + if j > 0 and suffix == suffix[::-1] and \ + prefix[::-1] in lookup and lookup[prefix[::-1]] != i: + res.append([lookup[prefix[::-1]], i]) + return res + +# Time: O(n * k^2), n is the number of the words, k is the max length of the words. +# Space: O(n * k^2) +# Manacher solution. +class Solution_TLE(object): + def palindromePairs(self, words): + """ + :type words: List[str] + :rtype: List[List[int]] + """ + def manacher(s, P): + def preProcess(s): + if not s: + return ['^', '$'] + T = ['^'] + for c in s: + T += ["#", c] + T += ['#', '$'] + return T + + T = preProcess(s) + center, right = 0, 0 + for i in xrange(1, len(T) - 1): + i_mirror = 2 * center - i + if right > i: + P[i] = min(right - i, P[i_mirror]) + else: + P[i] = 0 + while T[i + 1 + P[i]] == T[i - 1 - P[i]]: + P[i] += 1 + if i + P[i] > right: + center, right = i, i + P[i] + + prefix, suffix = collections.defaultdict(list), collections.defaultdict(list) + for i, word in enumerate(words): + P = [0] * (2 * len(word) + 3) + manacher(word, P) + for j in xrange(len(P)): + if j - P[j] == 1: + prefix[word[(j + P[j]) / 2:]].append(i) + if j + P[j] == len(P) - 2: + suffix[word[:(j - P[j]) / 2]].append(i) + res = [] + for i, word in enumerate(words): + for j in prefix[word[::-1]]: + if j != i: + res.append([i, j]) + for j in suffix[word[::-1]]: + if len(word) != len(words[j]): + res.append([j, i]) + return res + + +# Time: O(n * k^2), n is the number of the words, k is the max length of the words. +# Space: O(n * k) +# Trie solution. +class TrieNode: + def __init__(self): + self.word_idx = -1 + self.leaves = {} + + def insert(self, word, i): + cur = self + for c in word: + if not c in cur.leaves: + cur.leaves[c] = TrieNode() + cur = cur.leaves[c] + cur.word_idx = i + + def find(self, s, idx, res): + cur = self + for i in reversed(xrange(len(s))): + if s[i] in cur.leaves: + cur = cur.leaves[s[i]] + if cur.word_idx not in (-1, idx) and \ + self.is_palindrome(s, i - 1): + res.append([cur.word_idx, idx]) + else: + break + + def is_palindrome(self, s, j): + i = 0 + while i <= j: + if s[i] != s[j]: + return False + i += 1 + j -= 1 + return True + +class Solution_MLE(object): + def palindromePairs(self, words): + """ + :type words: List[str] + :rtype: List[List[int]] + """ + res = [] + trie = TrieNode() + for i in xrange(len(words)): + trie.insert(words[i], i) + + for i in xrange(len(words)): + trie.find(words[i], i, res) + + return res diff --git a/Python/palindrome-permutation-ii.py b/Python/palindrome-permutation-ii.py new file mode 100644 index 000000000..097f0956a --- /dev/null +++ b/Python/palindrome-permutation-ii.py @@ -0,0 +1,44 @@ +# Time: O(n * n!) +# Space: O(n) + +class Solution(object): + def generatePalindromes(self, s): + """ + :type s: str + :rtype: List[str] + """ + cnt = collections.Counter(s) + mid = ''.join(k for k, v in cnt.iteritems() if v % 2) + chars = ''.join(k * (v / 2) for k, v in cnt.iteritems()) + return self.permuteUnique(mid, chars) if len(mid) < 2 else [] + + def permuteUnique(self, mid, nums): + result = [] + used = [False] * len(nums) + self.permuteUniqueRecu(mid, result, used, [], nums) + return result + + def permuteUniqueRecu(self, mid, result, used, cur, nums): + if len(cur) == len(nums): + half_palindrome = ''.join(cur) + result.append(half_palindrome + mid + half_palindrome[::-1]) + return + for i in xrange(len(nums)): + if not used[i] and not (i > 0 and nums[i-1] == nums[i] and used[i-1]): + used[i] = True + cur.append(nums[i]) + self.permuteUniqueRecu(mid, result, used, cur, nums) + cur.pop() + used[i] = False + +class Solution2(object): + def generatePalindromes(self, s): + """ + :type s: str + :rtype: List[str] + """ + cnt = collections.Counter(s) + mid = tuple(k for k, v in cnt.iteritems() if v % 2) + chars = ''.join(k * (v / 2) for k, v in cnt.iteritems()) + return [''.join(half_palindrome + mid + half_palindrome[::-1]) \ + for half_palindrome in set(itertools.permutations(chars))] if len(mid) < 2 else [] diff --git a/Python/palindrome-permutation.py b/Python/palindrome-permutation.py new file mode 100644 index 000000000..21df60552 --- /dev/null +++ b/Python/palindrome-permutation.py @@ -0,0 +1,10 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def canPermutePalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + return sum(v % 2 for v in collections.Counter(s).values()) < 2 diff --git a/Python/palindromic-substrings.py b/Python/palindromic-substrings.py new file mode 100644 index 000000000..7cc38189e --- /dev/null +++ b/Python/palindromic-substrings.py @@ -0,0 +1,39 @@ +# Time: O(n) +# Space: O(n) + +# Given a string, your task is to count how many palindromic substrings in this string. +# +# The substrings with different start indexes or end indexes are counted as +# different substrings even they consist of same characters. +# +# Example 1: +# Input: "abc" +# Output: 3 +# Explanation: Three palindromic strings: "a", "b", "c". +# Example 2: +# Input: "aaa" +# Output: 6 +# Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa". +# Note: +# The input string length won't exceed 1000. + +class Solution(object): + def countSubstrings(self, s): + """ + :type s: str + :rtype: int + """ + def manacher(s): + s = '^#' + '#'.join(s) + '#$' + P = [0] * len(s) + C, R = 0, 0 + for i in xrange(1, len(s) - 1): + i_mirror = 2*C-i + if R > i: + P[i] = min(R-i, P[i_mirror]) + while s[i+1+P[i]] == s[i-1-P[i]]: + P[i] += 1 + if i+P[i] > R: + C, R = i, i+P[i] + return P + return sum((max_len+1)/2 for max_len in manacher(s)) diff --git a/Python/parse-lisp-expression.py b/Python/parse-lisp-expression.py new file mode 100644 index 000000000..e0ecf7b80 --- /dev/null +++ b/Python/parse-lisp-expression.py @@ -0,0 +1,110 @@ +# Time: O(n^2) +# Space: O(n^2) + +# You are given a string expression representing a Lisp-like expression to return the integer value of. +# +# The syntax for these expressions is given as follows. +# +# An expression is either an integer, a let-expression, +# an add-expression, a mult-expression, or an assigned variable. +# Expressions always evaluate to a single integer. +# (An integer could be positive or negative.) +# A let-expression takes the form (let v1 e1 v2 e2 ... vn en expr), +# where let is always the string "let", then there are 1 or more pairs of alternating variables and expressions, +# meaning that the first variable v1 is assigned the value of the expression e1, +# the second variable v2 is assigned the value of the expression e2, +# and so on sequentially; and then the value of this let-expression is the value of the expression expr. +# An add-expression takes the form (add e1 e2) where add is always the string "add", +# there are always two expressions e1, e2, +# and this expression evaluates to the addition of the evaluation of e1 and the evaluation of e2. +# A mult-expression takes the form (mult e1 e2) where mult is always the string "mult", +# there are always two expressions e1, e2, +# and this expression evaluates to the multiplication of the evaluation of e1 and the evaluation of e2. +# For the purposes of this question, we will use a smaller subset of variable names. +# A variable starts with a lowercase letter, then zero or more lowercase letters or digits. +# Additionally for your convenience, +# the names "add", "let", or "mult" are protected and will never be used as variable names. +# Finally, there is the concept of scope. +# When an expression of a variable name is evaluated, +# within the context of that evaluation, +# the innermost scope (in terms of parentheses) is checked first for the value of that variable, +# and then outer scopes are checked sequentially. It is guaranteed that every expression is legal. +# Please see the examples for more details on scope. +# +# Evaluation Examples: +# Input: (add 1 2) +# Output: 3 +# +# Input: (mult 3 (add 2 3)) +# Output: 15 +# +# Input: (let x 2 (mult x 5)) +# Output: 10 +# +# Input: (let x 2 (mult x (let x 3 y 4 (add x y)))) +# Output: 14 +# Explanation: In the expression (add x y), when checking for the value of the variable x, +# we check from the innermost scope to the outermost in the context of the variable we are trying to evaluate. +# Since x = 3 is found first, the value of x is 3. +# +# Input: (let x 3 x 2 x) +# Output: 2 +# Explanation: Assignment in let statements is processed sequentially. +# +# Input: (let x 1 y 2 x (add x y) (add x y)) +# Output: 5 +# Explanation: The first (add x y) evaluates as 3, and is assigned to x. +# The second (add x y) evaluates as 3+2 = 5. +# +# Input: (let x 2 (add (let x 3 (let x 4 x)) x)) +# Output: 6 +# Explanation: Even though (let x 4 x) has a deeper scope, it is outside the context +# of the final x in the add-expression. That final x will equal 2. +# +# Input: (let a1 3 b2 (add a1 1) b2) +# Output 4 +# Explanation: Variable names can contain digits after the first character. +# +# Note: +# - The given string expression is well formatted: +# There are no leading or trailing spaces, +# there is only a single space separating different components of the string, +# and no space between adjacent parentheses. +# The expression is guaranteed to be legal and evaluate to an integer. +# - The length of expression is at most 2000. (It is also non-empty, as that would not be a legal expression.) +# - The answer and all intermediate calculations of that answer are guaranteed to fit in a 32-bit integer. + +class Solution(object): + def evaluate(self, expression): + """ + :type expression: str + :rtype: int + """ + def getval(lookup, x): + return lookup.get(x, x) + + def evaluate(tokens, lookup): + if tokens[0] in ('add', 'mult'): + a, b = map(int, map(lambda x: getval(lookup, x), tokens[1:])) + return str(a+b if tokens[0] == 'add' else a*b) + for i in xrange(1, len(tokens)-1, 2): + if tokens[i+1]: + lookup[tokens[i]] = getval(lookup, tokens[i+1]) + return getval(lookup, tokens[-1]) + + tokens, lookup, stk = [''], {}, [] + for c in expression: + if c == '(': + if tokens[0] == 'let': + evaluate(tokens, lookup) + stk.append((tokens, dict(lookup))) + tokens = [''] + elif c == ' ': + tokens.append('') + elif c == ')': + val = evaluate(tokens, lookup) + tokens, lookup = stk.pop() + tokens[-1] += val + else: + tokens[-1] += c + return int(tokens[0]) diff --git a/Python/partition-equal-subset-sum.py b/Python/partition-equal-subset-sum.py new file mode 100644 index 000000000..962974fe2 --- /dev/null +++ b/Python/partition-equal-subset-sum.py @@ -0,0 +1,42 @@ +# Time: O(n * s), s is the sum of nums +# Space: O(s) + +# Given a non-empty array containing only positive integers, +# find if the array can be partitioned into two subsets +# such that the sum of elements in both subsets is equal. +# +# Note: +# Both the array size and each of the array element will not exceed 100. +# +# Example 1: +# +# Input: [1, 5, 11, 5] +# +# Output: true +# +# Explanation: The array can be partitioned as [1, 5, 5] and [11]. +# Example 2: +# +# Input: [1, 2, 3, 5] +# +# Output: false +# +# Explanation: The array cannot be partitioned into equal sum subsets. + +class Solution(object): + def canPartition(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + s = sum(nums) + if s % 2: + return False + + dp = [False] * (s/2 + 1) + dp[0] = True + for num in nums: + for i in xrange(1, len(dp)): + if num <= i: + dp[i] = dp[i] or dp[i - num] + return dp[-1] diff --git a/Python/partition-to-k-equal-sum-subsets.py b/Python/partition-to-k-equal-sum-subsets.py new file mode 100644 index 000000000..60ed1b5ce --- /dev/null +++ b/Python/partition-to-k-equal-sum-subsets.py @@ -0,0 +1,68 @@ +# Time: O(n*2^n) +# Space: O(2^n) + +# Given an array of integers nums and a positive integer k, +# find whether it's possible to divide this array into k non-empty subsets whose sums are all equal. +# +# Example 1: +# Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4 +# Output: True +# Explanation: It's possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums. +# Note: +# +# 1 <= k <= len(nums) <= 16. +# 0 < nums[i] < 10000. + +# Memoization solution. +class Solution(object): + def canPartitionKSubsets(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + def dfs(nums, target, used, todo, lookup): + if lookup[used] is None: + targ = (todo-1)%target + 1 + lookup[used] = any(dfs(nums, target, used | (1<>i) & 1) == 0 and num <= targ) + return lookup[used] + + total = sum(nums) + if total%k or max(nums) > total//k: + return False + lookup = [None] * (1 << len(nums)) + lookup[-1] = True + return dfs(nums, total//k, 0, total, lookup) + + +# Time: O(k^(n-k) * k!) +# Space: O(n) +# DFS solution with pruning. +class Solution2(object): + def canPartitionKSubsets(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + def dfs(nums, target, i, subset_sums): + if i == len(nums): + return True + for k in xrange(len(subset_sums)): + if subset_sums[k]+nums[i] > target: + continue + subset_sums[k] += nums[i] + if dfs(nums, target, i+1, subset_sums): + return True + subset_sums[k] -= nums[i] + if not subset_sums[k]: break + return False + + total = sum(nums) + if total%k != 0 or max(nums) > total//k: + return False + nums.sort(reverse=True) + subset_sums = [0] * k + return dfs(nums, total//k, 0, subset_sums) diff --git a/Python/pascals-triangle-ii.py b/Python/pascals-triangle-ii.py index f8aaa06d1..9f7cfd63d 100644 --- a/Python/pascals-triangle-ii.py +++ b/Python/pascals-triangle-ii.py @@ -1,6 +1,6 @@ # Time: O(n^2) -# Space: O(n) -# +# Space: O(1) + # Given an index k, return the kth row of the Pascal's triangle. # # For example, given k = 3, @@ -11,14 +11,6 @@ # class Solution: - # @return a list of integers - def getRow(self, rowIndex): - result = [1] - for i in range(1, rowIndex + 1): - result = [1] + [result[j - 1] + result[j] for j in range(1, i)] + [1] - return result - -class Solution2: # @return a list of integers def getRow(self, rowIndex): result = [0] * (rowIndex + 1) @@ -28,5 +20,47 @@ def getRow(self, rowIndex): old, result[j] = result[j], old + result[j] return result + def getRow2(self, rowIndex): + """ + :type rowIndex: int + :rtype: List[int] + """ + row = [1] + for _ in range(rowIndex): + row = [x + y for x, y in zip([0] + row, row + [0])] + return row + + def getRow3(self, rowIndex): + """ + :type rowIndex: int + :rtype: List[int] + """ + if rowIndex == 0: return [1] + res = [1, 1] + + def add(nums): + res = nums[:1] + for i, j in enumerate(nums): + if i < len(nums) - 1: + res += [nums[i] + nums[i + 1]] + res += nums[:1] + return res + + while res[1] < rowIndex: + res = add(res) + return res + + +# Time: O(n^2) +# Space: O(n) +class Solution2: + # @return a list of integers + def getRow(self, rowIndex): + result = [1] + for i in range(1, rowIndex + 1): + result = [1] + [result[j - 1] + result[j] for j in xrange(1, i)] + [1] + return result + + if __name__ == "__main__": - print Solution().getRow(3) \ No newline at end of file + print Solution().getRow(3) diff --git a/Python/pascals-triangle.py b/Python/pascals-triangle.py index 96bbf51f7..19b03a607 100644 --- a/Python/pascals-triangle.py +++ b/Python/pascals-triangle.py @@ -1,5 +1,5 @@ # Time: O(n^2) -# Space: O(n) +# Space: O(1) # # Given numRows, generate the first numRows of Pascal's triangle. # @@ -28,5 +28,33 @@ def generate(self, numRows): result[i].append(result[i - 1][j - 1] + result[i - 1][j]) return result + def generate2(self, numRows): + if not numRows: return [] + res = [[1]] + for i in range(1, numRows): + res += [map(lambda x, y: x + y, res[-1] + [0], [0] + res[-1])] + return res[:numRows] + + def generate3(self, numRows): + """ + :type numRows: int + :rtype: List[List[int]] + """ + if numRows == 0: return [] + if numRows == 1: return [[1]] + res = [[1], [1, 1]] + + def add(nums): + res = nums[:1] + for i, j in enumerate(nums): + if i < len(nums) - 1: + res += [nums[i] + nums[i + 1]] + res += nums[:1] + return res + + while len(res) < numRows: + res.extend([add(res[-1])]) + return res + if __name__ == "__main__": print Solution().generate(5) diff --git a/Python/patching-array.py b/Python/patching-array.py new file mode 100644 index 000000000..ce91f1f6e --- /dev/null +++ b/Python/patching-array.py @@ -0,0 +1,48 @@ +# Time: O(s + logn), s is the number of elements in the array +# Space: O(1) + +# Given a sorted positive integer array nums and +# an integer n, add/patch elements to the array +# such that any number in range [1, n] inclusive +# can be formed by the sum of some elements in the +# array. Return the minimum number of patches required. +# +# Example 1: +# nums = [1, 3], n = 6 +# Return 1. +# +# Combinations of nums are [1], [3], [1,3], which form +# possible sums of: 1, 3, 4. +# Now if we add/patch 2 to nums, the combinations are: +# [1], [2], [3], [1,3], [2,3], [1,2,3]. +# Possible sums are 1, 2, 3, 4, 5, 6, which now covers +# the range [1, 6]. +# So we only need 1 patch. +# +# Example 2: +# nums = [1, 5, 10], n = 20 +# Return 2. +# The two patches can be [2, 4]. +# +# Example 3: +# nums = [1, 2, 2], n = 5 +# Return 0. + + +class Solution(object): + def minPatches(self, nums, n): + """ + :type nums: List[int] + :type n: int + :rtype: int + """ + patch, miss, i = 0, 1, 0 + while miss <= n: + if i < len(nums) and nums[i] <= miss: + miss += nums[i] + i += 1 + else: + miss += miss + patch += 1 + + return patch diff --git a/Python/path-sum-ii.py b/Python/path-sum-ii.py index a6e835dcb..df35acde8 100644 --- a/Python/path-sum-ii.py +++ b/Python/path-sum-ii.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. # @@ -51,4 +51,4 @@ def pathSumRecu(self, result, cur, root, sum): if __name__ == "__main__": root = TreeNode(5) - print Solution().pathSum(root, 5) \ No newline at end of file + print Solution().pathSum(root, 5) diff --git a/Python/path-sum-iii.py b/Python/path-sum-iii.py new file mode 100644 index 000000000..ed24dde54 --- /dev/null +++ b/Python/path-sum-iii.py @@ -0,0 +1,86 @@ +# Time: O(n) +# Space: O(h) + +# You are given a binary tree in which each node contains an integer value. +# +# Find the number of paths that sum to a given value. +# +# The path does not need to start or end at the root or a leaf, +# but it must go downwards (traveling only from parent nodes to child nodes). +# +# The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000. +# +# Example: +# +# root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 +# +# 10 +# / \ +# 5 -3 +# / \ \ +# 3 2 11 +# / \ \ +# 3 -2 1 +# +# Return 3. The paths that sum to 8 are: +# +# 1. 5 -> 3 +# 2. 5 -> 2 -> 1 +# 3. -3 -> 11 + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def pathSum(self, root, sum): + """ + :type root: TreeNode + :type sum: int + :rtype: int + """ + def pathSumHelper(root, curr, sum, lookup): + if root is None: + return 0 + curr += root.val + result = lookup[curr-sum] if curr-sum in lookup else 0 + lookup[curr] += 1 + result += pathSumHelper(root.left, curr, sum, lookup) + \ + pathSumHelper(root.right, curr, sum, lookup) + lookup[curr] -= 1 + if lookup[curr] == 0: + del lookup[curr] + return result + + lookup = collections.defaultdict(int) + lookup[0] = 1 + return pathSumHelper(root, 0, sum, lookup) + + +# Time: O(n^2) +# Space: O(h) +class Solution2(object): + def pathSum(self, root, sum): + """ + :type root: TreeNode + :type sum: int + :rtype: int + """ + def pathSumHelper(root, prev, sum): + if root is None: + return 0 + + curr = prev + root.val; + return int(curr == sum) + \ + pathSumHelper(root.left, curr, sum) + \ + pathSumHelper(root.right, curr, sum) + + if root is None: + return 0 + + return pathSumHelper(root, 0, sum) + \ + self.pathSum(root.left, sum) + \ + self.pathSum(root.right, sum) diff --git a/Python/path-sum-iv.py b/Python/path-sum-iv.py new file mode 100644 index 000000000..ead4b0735 --- /dev/null +++ b/Python/path-sum-iv.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(p), p is the number of paths + +class Solution(object): + def pathSum(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + class Node(object): + def __init__(self, num): + self.level = num/100 - 1 + self.i = (num%100)/10 - 1 + self.val = num%10 + self.leaf = True + + def isParent(self, other): + return self.level == other.level-1 and \ + self.i == other.i/2 + + if not nums: + return 0 + result = 0 + q = collections.deque() + dummy = Node(10) + parent = dummy + for num in nums: + child = Node(num) + while not parent.isParent(child): + result += parent.val if parent.leaf else 0 + parent = q.popleft() + parent.leaf = False + child.val += parent.val + q.append(child) + while q: + result += q.pop().val + return result diff --git a/Python/path-sum.py b/Python/path-sum.py index 0f686ec7f..b24c951a1 100644 --- a/Python/path-sum.py +++ b/Python/path-sum.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree and a sum, determine if the tree has a root-to-leaf path # such that adding up all the values along the path equals the given sum. @@ -42,4 +42,4 @@ def hasPathSum(self, root, sum): root.right = TreeNode(8) root.left.left = TreeNode(11) root.left.left.right = TreeNode(2) - print Solution().hasPathSum(root, 22) \ No newline at end of file + print Solution().hasPathSum(root, 22) diff --git a/Python/peeking-iterator.py b/Python/peeking-iterator.py new file mode 100644 index 000000000..f21db1fa3 --- /dev/null +++ b/Python/peeking-iterator.py @@ -0,0 +1,83 @@ +# Time: O(1) per peek(), next(), hasNext() +# Space: O(1) + +# Given an Iterator class interface with methods: next() and hasNext(), +# design and implement a PeekingIterator that support the peek() operation -- +# it essentially peek() at the element that will be returned by the next call to next(). +# +# Here is an example. Assume that the iterator is initialized to the beginning of +# the list: [1, 2, 3]. +# +# Call next() gets you 1, the first element in the list. +# +# Now you call peek() and it returns 2, the next element. Calling next() after that +# still return 2. +# +# You call next() the final time and it returns 3, the last element. Calling hasNext() +# after that should return false. +# + +# Below is the interface for Iterator, which is already defined for you. +# +# class Iterator(object): +# def __init__(self, nums): +# """ +# Initializes an iterator object to the beginning of a list. +# :type nums: List[int] +# """ +# +# def hasNext(self): +# """ +# Returns true if the iteration has more elements. +# :rtype: bool +# """ +# +# def next(self): +# """ +# Returns the next element in the iteration. +# :rtype: int +# """ + +class PeekingIterator(object): + def __init__(self, iterator): + """ + Initialize your data structure here. + :type iterator: Iterator + """ + self.iterator = iterator + self.val_ = None + self.has_next_ = iterator.hasNext() + self.has_peeked_ = False + + + def peek(self): + """ + Returns the next element in the iteration without advancing the iterator. + :rtype: int + """ + if not self.has_peeked_: + self.has_peeked_ = True + self.val_ = self.iterator.next() + return self.val_; + + def next(self): + """ + :rtype: int + """ + self.val_ = self.peek() + self.has_peeked_ = False + self.has_next_ = self.iterator.hasNext() + return self.val_; + + def hasNext(self): + """ + :rtype: bool + """ + return self.has_next_ + + +# Your PeekingIterator object will be instantiated and called as such: +# iter = PeekingIterator(Iterator(nums)) +# while iter.hasNext(): +# val = iter.peek() # Get the next element but not advance the iterator. +# iter.next() # Should return the same value as [val]. diff --git a/Python/perfect-number.py b/Python/perfect-number.py new file mode 100644 index 000000000..a3fefe5b5 --- /dev/null +++ b/Python/perfect-number.py @@ -0,0 +1,28 @@ +# Time: O(sqrt(n)) +# Space: O(1) + +# We define the Perfect Number is a positive integer that is equal +# to the sum of all its positive divisors except itself. +# +# Now, given an integer n, write a function that returns true +# when it is a perfect number and false when it is not. +# Example: +# Input: 28 +# Output: True +# Explanation: 28 = 1 + 2 + 4 + 7 + 14 +# Note: The input number n will not exceed 100,000,000. (1e8) + +class Solution(object): + def checkPerfectNumber(self, num): + """ + :type num: int + :rtype: bool + """ + if num <= 0: + return False + + sqrt_num = int(num ** 0.5) + total = sum(i+num//i for i in xrange(1, sqrt_num+1) if num%i == 0) + if sqrt_num ** 2 == num: + total -= sqrt_num + return total - num == num diff --git a/Python/perfect-rectangle.py b/Python/perfect-rectangle.py new file mode 100644 index 000000000..7a3822f41 --- /dev/null +++ b/Python/perfect-rectangle.py @@ -0,0 +1,81 @@ +# Time: O(n) +# Space: O(n) + +# Given N axis-aligned rectangles where N > 0, +# determine if they all together form an exact cover of a rectangular region. +# +# Each rectangle is represented as a bottom-left point and a top-right point. +# For example, a unit square is represented as [1,1,2,2]. +# (coordinate of bottom-left point is (1, 1) and top-right point is (2, 2)). +# +# Example 1: +# +# rectangles = [ +# [1,1,3,3], +# [3,1,4,2], +# [3,2,4,4], +# [1,3,2,4], +# [2,3,3,4] +# ] +# +# Return true. All 5 rectangles together form an exact cover of a rectangular region. +# +# Example 2: +# +# rectangles = [ +# [1,1,2,3], +# [1,3,2,4], +# [3,1,4,2], +# [3,2,4,4] +# ] +# +# Return false. Because there is a gap between the two rectangular regions. +# +# Example 3: +# +# rectangles = [ +# [1,1,3,3], +# [3,1,4,2], +# [1,3,2,4], +# [3,2,4,4] +# ] +# +# Return false. Because there is a gap in the top center. +# +# Example 4: +# +# rectangles = [ +# [1,1,3,3], +# [3,1,4,2], +# [1,3,2,4], +# [2,2,4,4] +# ] +# +# Return false. Because two of the rectangles overlap with each other. + +from collections import defaultdict + +class Solution(object): + def isRectangleCover(self, rectangles): + """ + :type rectangles: List[List[int]] + :rtype: bool + """ + left = min(rec[0] for rec in rectangles) + bottom = min(rec[1] for rec in rectangles) + right = max(rec[2] for rec in rectangles) + top = max(rec[3] for rec in rectangles) + + points = defaultdict(int) + for l, b, r, t in rectangles: + for p, q in zip(((l, b), (r, b), (l, t), (r, t)), (1, 2, 4, 8)): + if points[p] & q: + return False + points[p] |= q + + for px, py in points: + if left < px < right or bottom < py < top: + if points[(px, py)] not in (3, 5, 10, 12, 15): + return False + + return True diff --git a/Python/perfect-squares.py b/Python/perfect-squares.py new file mode 100644 index 000000000..2cee23f58 --- /dev/null +++ b/Python/perfect-squares.py @@ -0,0 +1,21 @@ +# Time: O(n * sqrt(n)) +# Space: O(n) +# +# Given a positive integer n, find the least number of perfect +# square numbers (for example, 1, 4, 9, 16, ...) which sum to n. +# +# For example, given n = 12, return 3 because 12 = 4 + 4 + 4; +# given n = 13, return 2 because 13 = 4 + 9. +# + +class Solution(object): + _num = [0] + def numSquares(self, n): + """ + :type n: int + :rtype: int + """ + num = self._num + while len(num) <= n: + num += min(num[-i*i] for i in xrange(1, int(len(num)**0.5+1))) + 1, + return num[n] diff --git a/Python/permutation-in-string.py b/Python/permutation-in-string.py new file mode 100644 index 000000000..171502725 --- /dev/null +++ b/Python/permutation-in-string.py @@ -0,0 +1,39 @@ +# Time: O(n) +# Space: O(1) + +# Given two strings s1 and s2, write a function to return true +# if s2 contains the permutation of s1. In other words, +# one of the first string's permutations is the substring of the second string. +# +# Example 1: +# Input:s1 = "ab" s2 = "eidbaooo" +# Output:True +# Explanation: s2 contains one permutation of s1 ("ba"). +# Example 2: +# Input:s1= "ab" s2 = "eidboaoo" +# Output: False +# Note: +# The input strings only contain lower case letters. +# The length of both given strings is in range [1, 10,000]. + +class Solution(object): + def checkInclusion(self, s1, s2): + """ + :type s1: str + :type s2: str + :rtype: bool + """ + counts = collections.Counter(s1) + l = len(s1) + for i in xrange(len(s2)): + if counts[s2[i]] > 0: + l -= 1 + counts[s2[i]] -= 1 + if l == 0: + return True + start = i + 1 - len(s1) + if start >= 0: + counts[s2[start]] += 1 + if counts[s2[start]] > 0: + l += 1 + return False diff --git a/Python/permutation-sequence.py b/Python/permutation-sequence.py index 2252f26ad..cc8b59603 100644 --- a/Python/permutation-sequence.py +++ b/Python/permutation-sequence.py @@ -1,6 +1,6 @@ -# Time: O(n) -# Space: O(1) -# +# Time: O(n^2) +# Space: O(n) + # The set [1,2,3,...,n] contains a total of n! unique permutations. # # By listing and labeling all of the permutations in order, @@ -15,14 +15,17 @@ # Given n and k, return the kth permutation sequence. # # Note: Given n will be between 1 and 9 inclusive. -# import math # Cantor ordering solution -class Solution: - # @return a string +class Solution(object): def getPermutation(self, n, k): + """ + :type n: int + :type k: int + :rtype: str + """ seq, k, fact = "", k - 1, math.factorial(n - 1) perm = [i for i in xrange(1, n + 1)] for i in reversed(xrange(n)): @@ -33,6 +36,7 @@ def getPermutation(self, n, k): k %= fact fact /= i return seq + if __name__ == "__main__": print Solution().getPermutation(3, 2) diff --git a/Python/permutations-ii.py b/Python/permutations-ii.py index 1f473145a..2b98e265c 100644 --- a/Python/permutations-ii.py +++ b/Python/permutations-ii.py @@ -1,4 +1,4 @@ -# Time: O(n!) +# Time: O(n * n!) # Space: O(n) # # Given a collection of numbers that might contain duplicates, return all possible unique permutations. @@ -8,8 +8,32 @@ # [1,1,2], [1,2,1], and [2,1,1]. # - -class Solution: +class Solution(object): + def permuteUnique(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + result = [] + used = [False] * len(nums) + self.permuteUniqueRecu(result, used, [], nums) + return result + + def permuteUniqueRecu(self, result, used, cur, nums): + if len(cur) == len(nums): + result.append(cur + []) + return + for i in xrange(len(nums)): + if used[i] or (i > 0 and nums[i-1] == nums[i] and not used[i-1]): + continue + used[i] = True + cur.append(nums[i]) + self.permuteUniqueRecu(result, used, cur, nums) + cur.pop() + used[i] = False + +class Solution2: # @param num, a list of integer # @return a list of lists of integers def permuteUnique(self, nums): diff --git a/Python/permutations.py b/Python/permutations.py index f224894c8..03d76be78 100644 --- a/Python/permutations.py +++ b/Python/permutations.py @@ -1,4 +1,4 @@ -# Time: O(n!) +# Time: O(n * n!) # Space: O(n) # # Given a collection of numbers, return all possible permutations. diff --git a/Python/plus-one-linked-list.py b/Python/plus-one-linked-list.py new file mode 100644 index 000000000..1d7e2c352 --- /dev/null +++ b/Python/plus-one-linked-list.py @@ -0,0 +1,66 @@ +# Time: O(n) +# Space: O(1) + +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +# Two pointers solution. +class Solution(object): + def plusOne(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if not head: + return None + + dummy = ListNode(0) + dummy.next = head + + left, right = dummy, head + while right.next: + if right.val != 9: + left = right + right = right.next + + if right.val != 9: + right.val += 1 + else: + left.val += 1 + right = left.next + while right: + right.val = 0 + right = right.next + + return dummy if dummy.val else dummy.next + + +# Time: O(n) +# Space: O(1) +class Solution2(object): + def plusOne(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + def reverseList(head): + dummy = ListNode(0) + curr = head + while curr: + dummy.next, curr.next, curr = curr, dummy.next, curr.next + return dummy.next + + rev_head = reverseList(head) + curr, carry = rev_head, 1 + while curr and carry: + curr.val += carry + carry = curr.val / 10 + curr.val %= 10 + if carry and curr.next is None: + curr.next = ListNode(0) + curr = curr.next + + return reverseList(rev_head) diff --git a/Python/plus-one.py b/Python/plus-one.py index e704900ef..c708ff120 100644 --- a/Python/plus-one.py +++ b/Python/plus-one.py @@ -4,11 +4,13 @@ # Given a non-negative number represented as an array of digits, plus one to the number. # # The digits are stored such that the most significant digit is at the head of the list. -# + class Solution: - # @param digits, a list of integer digits - # @return a list of integer digits + """ + :type digits: List[int] + :rtype: List[int] + """ def plusOne(self, digits): carry = 1 for i in reversed(xrange(len(digits))): @@ -21,5 +23,14 @@ def plusOne(self, digits): return digits + def plusOne2(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + digits = [str(x) for x in digits] + num = int(''.join(digits)) + 1 + return [int(x) for x in str(num)] + if __name__ == "__main__": print Solution().plusOne([9, 9, 9, 9]) \ No newline at end of file diff --git a/Python/poor-pigs.py b/Python/poor-pigs.py new file mode 100644 index 000000000..c5263a9d3 --- /dev/null +++ b/Python/poor-pigs.py @@ -0,0 +1,26 @@ +# Time: O(1) +# Space: O(1) + +# There are 1000 buckets, one and only one of them contains poison, +# the rest are filled with water. They all look the same. +# If a pig drinks that poison it will die within 15 minutes. +# What is the minimum amount of pigs you need to figure out +# which bucket contains the poison within one hour. +# +# Answer this question, and write an algorithm for the follow-up general case. +# +# Follow-up: +# +# If there are n buckets and a pig drinking poison will die within m minutes, +# how many pigs (x) you need to figure out the "poison" bucket within p minutes? +# There is exact one bucket with poison. + +class Solution(object): + def poorPigs(self, buckets, minutesToDie, minutesToTest): + """ + :type buckets: int + :type minutesToDie: int + :type minutesToTest: int + :rtype: int + """ + return int(math.ceil(math.log(buckets) / math.log(minutesToTest / minutesToDie + 1))) diff --git a/Python/populating-next-right-pointers-in-each-node.py b/Python/populating-next-right-pointers-in-each-node.py index 5223f28fb..79b50a7d8 100644 --- a/Python/populating-next-right-pointers-in-each-node.py +++ b/Python/populating-next-right-pointers-in-each-node.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(1) # # Given a binary tree # @@ -45,6 +45,23 @@ def __repr__(self): return "{} -> {}".format(self.val, repr(self.next)) class Solution: + # @param root, a tree node + # @return nothing + def connect(self, root): + head = root + while head: + prev, cur, next_head = None, head, None + while cur and cur.left: + cur.left.next = cur.right + if cur.next: + cur.right.next = cur.next.left + cur = cur.next + head = head.left + +# Time: O(n) +# Space: O(logn) +# recusion +class Solution2: # @param root, a tree node # @return nothing def connect(self, root): @@ -64,4 +81,4 @@ def connect(self, root): print root print root.left print root.left.left - \ No newline at end of file + diff --git a/Python/power-of-four.py b/Python/power-of-four.py new file mode 100644 index 000000000..74ca8217a --- /dev/null +++ b/Python/power-of-four.py @@ -0,0 +1,41 @@ +# Time: O(1) +# Space: O(1) + +# Given an integer (signed 32 bits), write a function to check whether it is a power of 4. +# +# Example: +# Given num = 16, return true. Given num = 5, return false. +# +# Follow up: Could you solve it without loops/recursion? + +class Solution(object): + def isPowerOfFour(self, num): + """ + :type num: int + :rtype: bool + """ + return num > 0 and (num & (num - 1)) == 0 and \ + ((num & 0b01010101010101010101010101010101) == num) + + +# Time: O(1) +# Space: O(1) +class Solution2(object): + def isPowerOfFour(self, num): + """ + :type num: int + :rtype: bool + """ + while num and not (num & 0b11): + num >>= 2 + return (num == 1) + + +class Solution3(object): + def isPowerOfFour(self, num): + """ + :type num: int + :rtype: bool + """ + num = bin(num) + return True if num[2:].startswith('1') and len(num[2:]) == num.count('0') and num.count('0') % 2 and '-' not in num else False diff --git a/Python/power-of-three.py b/Python/power-of-three.py new file mode 100644 index 000000000..7398d4bf5 --- /dev/null +++ b/Python/power-of-three.py @@ -0,0 +1,22 @@ +# Time: O(1) +# Space: O(1) + +# Given an integer, write a function to determine +# if it is a power of three. +# +# Follow up: +# Could you do it without using any loop / recursion? +import math + + +class Solution(object): + def __init__(self): + self.__max_log3 = int(math.log(0x7fffffff) / math.log(3)) + self.__max_pow3 = 3 ** self.__max_log3 + + def isPowerOfThree(self, n): + """ + :type n: int + :rtype: bool + """ + return n > 0 and self.__max_pow3 % n == 0 diff --git a/Python/power-of-two.py b/Python/power-of-two.py new file mode 100644 index 000000000..55e5bbf92 --- /dev/null +++ b/Python/power-of-two.py @@ -0,0 +1,18 @@ +# Time: O(1) +# Space: O(1) +# +# Given an integer, write a function to determine if it is a power of two. + + +class Solution: + # @param {integer} n + # @return {boolean} + def isPowerOfTwo(self, n): + return n > 0 and (n & (n - 1)) == 0 + + +class Solution2: + # @param {integer} n + # @return {boolean} + def isPowerOfTwo(self, n): + return n > 0 and (n & ~-n) == 0 diff --git a/Python/powx-n.py b/Python/powx-n.py index 02672df29..a787cfd82 100644 --- a/Python/powx-n.py +++ b/Python/powx-n.py @@ -1,28 +1,48 @@ -# Time: O(logn) -# Space: O(logn) -# +# Time: O(logn) = O(1) +# Space: O(1) + # Implement pow(x, n). -# -class Solution: - # @param x, a float - # @param n, a integer - # @return a float - def pow(self, x, n): - if n < 0: - return 1 / self.powRecu(x, -n) - - return self.powRecu(x, n) - - def powRecu(self, x, n): +# Iterative solution. +class Solution(object): + def myPow(self, x, n): + """ + :type x: float + :type n: int + :rtype: float + """ + result = 1 + abs_n = abs(n) + while abs_n: + if abs_n & 1: + result *= x + abs_n >>= 1 + x *= x + + return 1 / result if n < 0 else result + + +# Time: O(logn) +# Space: O(logn) +# Recursive solution. +class Solution2(object): + def myPow(self, x, n): + """ + :type x: float + :type n: int + :rtype: float + """ + if n < 0 and n != -n: + return 1.0 / self.myPow(x, -n) if n == 0: - return 1.0 - + return 1 + v = self.myPow(x, n / 2) if n % 2 == 0: - return self.powRecu(x * x, n / 2) + return v * v else: - return x * self.powRecu(x * x, n / 2) + return v * v * x + if __name__ == "__main__": print Solution().pow(3, 5) - print Solution().pow(3, -5) \ No newline at end of file + print Solution().pow(3, -5) diff --git a/Python/predict-the-winner.py b/Python/predict-the-winner.py new file mode 100644 index 000000000..b64a44cf3 --- /dev/null +++ b/Python/predict-the-winner.py @@ -0,0 +1,48 @@ +# Time: O(n^2) +# Space: O(n) + +# Given an array of scores that are non-negative integers. +# Player 1 picks one of the numbers from either end of the array +# followed by the player 2 and then player 1 and so on. +# Each time a player picks a number, that number will not be available for the next player. +# This continues until all the scores have been chosen. The player with the maximum score wins. +# +# Given an array of scores, predict whether player 1 is the winner. +# You can assume each player plays to maximize his score. +# +# Example 1: +# Input: [1, 5, 2] +# Output: False +# Explanation: Initially, player 1 can choose between 1 and 2. +# If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. +# If player 2 chooses 5, then player 1 will be left with 1 (or 2). +# So, final score of player 1 is 1 + 2 = 3, and player 2 is 5. +# Hence, player 1 will never be the winner and you need to return False. +# Example 2: +# Input: [1, 5, 233, 7] +# Output: True +# Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. +# No matter which number player 2 choose, player 1 can choose 233. +# Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win. +# Note: +# 1 <= length of the array <= 20. +# Any scores in the given array are non-negative integers and will not exceed 10,000,000. +# If the scores of both players are equal, then player 1 is still the winner. + +class Solution(object): + def PredictTheWinner(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + if len(nums) % 2 == 0 or len(nums) == 1: + return True + + dp = [0] * len(nums); + for i in reversed(xrange(len(nums))): + dp[i] = nums[i] + for j in xrange(i+1, len(nums)): + dp[j] = max(nums[i] - dp[j], nums[j] - dp[j - 1]) + + return dp[-1] >= 0 + diff --git a/Python/prefix-and-suffix-search.py b/Python/prefix-and-suffix-search.py new file mode 100644 index 000000000..caecf336c --- /dev/null +++ b/Python/prefix-and-suffix-search.py @@ -0,0 +1,120 @@ +# Time: ctor: O(w * l^2), w is the number of words, l is the word length on average +# search: O(p + s) , p is the length of the prefix, s is the length of the suffix, +# Space: O(t), t is the number of trie nodes + +# Given many words, words[i] has weight i. +# +# Design a class WordFilter that supports one function, +# WordFilter.f(String prefix, String suffix). +# It will return the word with given prefix and suffix with maximum weight. +# If no word exists, return -1. +# +# Examples: +# Input: +# WordFilter(["apple"]) +# WordFilter.f("a", "e") // returns 0 +# WordFilter.f("b", "") // returns -1 +# Note: +# words has length in range [1, 15000]. +# For each test case, up to words.length queries WordFilter.f may be made. +# words[i] has length in range [1, 10]. +# prefix, suffix have lengths in range [0, 10]. +# words[i] and prefix, suffix queries consist of lowercase letters only. + +class WordFilter(object): + + def __init__(self, words): + """ + :type words: List[str] + """ + _trie = lambda: collections.defaultdict(_trie) + self.__trie = _trie() + + for weight, word in enumerate(words): + word += '#' + for i in xrange(len(word)): + cur = self.__trie + cur["_weight"] = weight + for j in xrange(i, 2*len(word)-1): + cur = cur[word[j%len(word)]] + cur["_weight"] = weight + + def f(self, prefix, suffix): + """ + :type prefix: str + :type suffix: str + :rtype: int + """ + cur = self.__trie + for letter in suffix + '#' + prefix: + if letter not in cur: + return -1 + cur = cur[letter] + return cur["_weight"] + + +# Time: ctor: O(w * l), w is the number of words, l is the word length on average +# search: O(p + s + max(m, n)), p is the length of the prefix, s is the length of the suffix, +# m is the number of the prefix match, n is the number of the suffix match +# Space: O(w * l) +class Trie(object): + + def __init__(self): + _trie = lambda: collections.defaultdict(_trie) + self.__trie = _trie() + + def insert(self, word, i): + def add_word(cur, i): + if "_words" not in cur: + cur["_words"] = [] + cur["_words"].append(i) + + cur = self.__trie + add_word(cur, i) + for c in word: + cur = cur[c] + add_word(cur, i) + + def find(self, word): + cur = self.__trie + for c in word: + if c not in cur: + return [] + cur = cur[c] + return cur["_words"] + + +class WordFilter2(object): + + def __init__(self, words): + """ + :type words: List[str] + """ + self.__prefix_trie = Trie() + self.__suffix_trie = Trie() + for i in reversed(xrange(len(words))): + self.__prefix_trie.insert(words[i], i) + self.__suffix_trie.insert(words[i][::-1], i) + + def f(self, prefix, suffix): + """ + :type prefix: str + :type suffix: str + :rtype: int + """ + prefix_match = self.__prefix_trie.find(prefix) + suffix_match = self.__suffix_trie.find(suffix[::-1]) + i, j = 0, 0 + while i != len(prefix_match) and j != len(suffix_match): + if prefix_match[i] == suffix_match[j]: + return prefix_match[i] + elif prefix_match[i] > suffix_match[j]: + i += 1 + else: + j += 1 + return -1 + + +# Your WordFilter object will be instantiated and called as such: +# obj = WordFilter(words) +# param_1 = obj.f(prefix,suffix) diff --git a/Python/print-binary-tree.py b/Python/print-binary-tree.py new file mode 100644 index 000000000..33b00ff1d --- /dev/null +++ b/Python/print-binary-tree.py @@ -0,0 +1,87 @@ +# Time: O(h * 2^h) +# Space: O(h * 2^h) + +# Print a binary tree in an m*n 2D string array following these rules: +# +# The row number m should be equal to the height of the given binary tree. +# The column number n should always be an odd number. +# The root node's value (in string format) should be put in the exactly middle of the first row it can be put. +# The column and the row where the root node belongs will separate the rest space into two parts +# (left-bottom part and right-bottom part). You should print the left subtree in the left-bottom part and +# print the right subtree in the right-bottom part. The left-bottom part and the right-bottom part should have the same size. +# Even if one subtree is none while the other is not, you don't need to print anything for the none subtree +# but still need to leave the space as large as that for the other subtree. However, if two subtrees are none, +# then you don't need to leave space for both of them. +# Each unused space should contain an empty string "". +# Print the subtrees following the same rules. +# Example 1: +# Input: +# 1 +# / +# 2 +# Output: +# [["", "1", ""], +# ["2", "", ""]] +# Example 2: +# Input: +# 1 +# / \ +# 2 3 +# \ +# 4 +# Output: +# [["", "", "", "1", "", "", ""], +# ["", "2", "", "", "", "3", ""], +# ["", "", "4", "", "", "", ""]] +# Example 3: +# Input: +# 1 +# / \ +# 2 5 +# / +# 3 +# / +# 4 +# Output: +# +# [["", "", "", "", "", "", "", "1", "", "", "", "", "", "", ""] +# ["", "", "", "2", "", "", "", "", "", "", "", "5", "", "", ""] +# ["", "3", "", "", "", "", "", "", "", "", "", "", "", "", ""] +# ["4", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]] +# Note: The height of binary tree is in the range of [1, 10]. +# +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def printTree(self, root): + """ + :type root: TreeNode + :rtype: List[List[str]] + """ + def getWidth(root): + if not root: + return 0 + return 2 * max(getWidth(root.left), getWidth(root.right)) + 1 + + def getHeight(root): + if not root: + return 0 + return max(getHeight(root.left), getHeight(root.right)) + 1 + + def preorderTraversal(root, level, left, right, result): + if not root: + return + mid = left + (right-left)/2 + result[level][mid] = str(root.val) + preorderTraversal(root.left, level+1, left, mid-1, result) + preorderTraversal(root.right, level+1, mid+1, right, result) + + h, w = getHeight(root), getWidth(root) + result = [[""] * w for _ in xrange(h)] + preorderTraversal(root, 0, 0, w-1, result) + return result diff --git a/Python/product-of-array-except-self.py b/Python/product-of-array-except-self.py new file mode 100644 index 000000000..f9646d83a --- /dev/null +++ b/Python/product-of-array-except-self.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(1) +# +# Given an array of n integers where n > 1, nums, +# return an array output such that output[i] is equal to +# the product of all the elements of nums except nums[i]. +# +# Solve it without division and in O(n). +# +# For example, given [1,2,3,4], return [24,12,8,6]. +# +# +# Follow up: +# Could you solve it with constant space complexity? +# (Note: The output array does not count as extra space +# for the purpose of space complexity analysis.) +# + +class Solution: + # @param {integer[]} nums + # @return {integer[]} + def productExceptSelf(self, nums): + if not nums: + return [] + + left_product = [1 for _ in xrange(len(nums))] + for i in xrange(1, len(nums)): + left_product[i] = left_product[i - 1] * nums[i - 1] + + right_product = 1 + for i in xrange(len(nums) - 2, -1, -1): + right_product *= nums[i + 1] + left_product[i] = left_product[i] * right_product + + return left_product diff --git a/Python/queue-reconstruction-by-height.py b/Python/queue-reconstruction-by-height.py new file mode 100644 index 000000000..7863a79ff --- /dev/null +++ b/Python/queue-reconstruction-by-height.py @@ -0,0 +1,58 @@ +# Time: O(n * sqrt(n)) +# Space: O(n) + +# Suppose you have a random list of people standing in a queue. +# Each person is described by a pair of integers (h, k), +# where h is the height of the person and k is the number of people +# in front of this person who have a height greater than or equal to h. +# Write an algorithm to reconstruct the queue. +# +# Note: +# The number of people is less than 1,100. +# +# Example +# +# Input: +# [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] +# +# Output: +# [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] + +class Solution(object): + def reconstructQueue(self, people): + """ + :type people: List[List[int]] + :rtype: List[List[int]] + """ + people.sort(key=lambda (h, k): (-h, k)) + + blocks = [[]] + for p in people: + index = p[1] + + for i, block in enumerate(blocks): + if index <= len(block): + break + index -= len(block) + block.insert(index, p) + + if len(block) * len(block) > len(people): + blocks.insert(i+1, block[len(block)/2:]) + del block[len(block)/2:] + + return [p for block in blocks for p in block] + + +# Time: O(n^2) +# Space: O(n) +class Solution2(object): + def reconstructQueue(self, people): + """ + :type people: List[List[int]] + :rtype: List[List[int]] + """ + people.sort(key=lambda (h, k): (-h, k)) + result = [] + for p in people: + result.insert(p[1], p) + return result diff --git a/Python/random-pick-index.py b/Python/random-pick-index.py new file mode 100644 index 000000000..f8034c6da --- /dev/null +++ b/Python/random-pick-index.py @@ -0,0 +1,53 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of integers with possible duplicates, +# randomly output the index of a given target number. +# You can assume that the given target number must exist in the array. +# +# Note: +# The array size can be very large. +# Solution that uses too much extra space will not pass the judge. +# +# Example: +# +# int[] nums = new int[] {1,2,3,3,3}; +# Solution solution = new Solution(nums); +# +# // pick(3) should return either index 2, 3, or 4 randomly. +# Each index should have equal probability of returning. +# solution.pick(3); +# +# // pick(1) should return 0. Since in the array only nums[0] is equal to 1. +# solution.pick(1); + +from random import randint + +class Solution(object): + + def __init__(self, nums): + """ + + :type nums: List[int] + :type numsSize: int + """ + self.__nums = nums + + def pick(self, target): + """ + :type target: int + :rtype: int + """ + reservoir = -1 + n = 0 + for i in xrange(len(self.__nums)): + if self.__nums[i] != target: + continue + reservoir = i if randint(1, n+1) == 1 else reservoir + n += 1 + return reservoir + + +# Your Solution object will be instantiated and called as such: +# obj = Solution(nums) +# param_1 = obj.pick(target) diff --git a/Python/range-addition-ii.py b/Python/range-addition-ii.py new file mode 100644 index 000000000..e63e660d6 --- /dev/null +++ b/Python/range-addition-ii.py @@ -0,0 +1,51 @@ +# Time: O(p), p is the number of ops +# Space: O(1) + +# Given an m * n matrix M initialized with all 0's and several update operations. +# +# Operations are represented by a 2D array, +# and each operation is represented by an array with two positive integers a and b, +# which means M[i][j] should be added by one for all 0 <= i < a and 0 <= j < b. +# +# You need to count and return the number of maximum integers +# in the matrix after performing all the operations. +# +# Example 1: +# Input: +# m = 3, n = 3 +# operations = [[2,2],[3,3]] +# Output: 4 +# Explanation: +# Initially, M = +# [[0, 0, 0], +# [0, 0, 0], +# [0, 0, 0]] +# +# After performing [2,2], M = +# [[1, 1, 0], +# [1, 1, 0], +# [0, 0, 0]] +# +# After performing [3,3], M = +# [[2, 2, 1], +# [2, 2, 1], +# [1, 1, 1]] +# +# So the maximum integer in M is 2, and there are four of it in M. So return 4. +# Note: +# The range of m and n is [1,40000]. +# The range of a is [1,m], and the range of b is [1,n]. +# The range of operations size won't exceed 10,000. + +class Solution(object): + def maxCount(self, m, n, ops): + """ + :type m: int + :type n: int + :type ops: List[List[int]] + :rtype: int + """ + for op in ops: + m = min(m, op[0]) + n = min(n, op[1]) + return m*n diff --git a/Python/range-addition.py b/Python/range-addition.py new file mode 100644 index 000000000..bc9c6fcaf --- /dev/null +++ b/Python/range-addition.py @@ -0,0 +1,20 @@ +# Time: O(k + n) +# Space: O(1) + +class Solution(object): + def getModifiedArray(self, length, updates): + """ + :type length: int + :type updates: List[List[int]] + :rtype: List[int] + """ + result = [0] * length + for update in updates: + result[update[0]] += update[2] + if update[1]+1 < length: + result[update[1]+1] -= update[2] + + for i in xrange(1, length): + result[i] += result[i-1] + + return result diff --git a/Python/range-module.py b/Python/range-module.py new file mode 100644 index 000000000..612011f0e --- /dev/null +++ b/Python/range-module.py @@ -0,0 +1,95 @@ +# Time: addRange: O(n) +# removeRange: O(n) +# queryRange: O(logn) +# Space: O(n) + +# A Range Module is a module that tracks ranges of numbers. +# Your task is to design and implement the following interfaces in an efficient manner. +# - addRange(int left, int right) Adds the half-open interval [left, right), +# tracking every real number in that interval. +# Adding an interval that partially overlaps with currently tracked numbers should +# add any numbers in the interval [left, right) that are not already tracked. +# - queryRange(int left, int right) Returns true if and only if +# every real number in the interval [left, right) is currently being tracked. +# - removeRange(int left, int right) Stops tracking every real number currently being tracked +# in the interval [left, right). +# +# Example 1: +# addRange(10, 20): null +# removeRange(14, 16): null +# queryRange(10, 14): true (Every number in [10, 14) is being tracked) +# queryRange(13, 15): false (Numbers like 14, 14.03, 14.17 in [13, 15) are not being tracked) +# queryRange(16, 17): true (The number 16 in [16, 17) is still being tracked, despite the remove operation) +# +# Note: +# - A half open interval [left, right) denotes all real numbers left <= x < right. +# - 0 < left < right < 10^9 in all calls to addRange, queryRange, removeRange. +# - The total number of calls to addRange in a single test case is at most 1000. +# - The total number of calls to queryRange in a single test case is at most 5000. +# - The total number of calls to removeRange in a single test case is at most 1000. + +class RangeModule(object): + + def __init__(self): + self.__intervals = [] + + def addRange(self, left, right): + """ + :type left: int + :type right: int + :rtype: void + """ + tmp = [] + i = 0 + for interval in self.__intervals: + if right < interval[0]: + tmp.append((left, right)) + break + elif interval[1] < left: + tmp.append(interval); + else: + left = min(left, interval[0]) + right = max(right, interval[1]) + i += 1 + if i == len(self.__intervals): + tmp.append((left, right)) + while i < len(self.__intervals): + tmp.append(self.__intervals[i]) + i += 1 + self.__intervals = tmp + + def queryRange(self, left, right): + """ + :type left: int + :type right: int + :rtype: bool + """ + i = bisect.bisect_left(self.__intervals, (left, float("inf"))) + if i: i -= 1 + return bool(self.__intervals) and \ + self.__intervals[i][0] <= left and \ + right <= self.__intervals[i][1] + + def removeRange(self, left, right): + """ + :type left: int + :type right: int + :rtype: void + """ + tmp = [] + for interval in self.__intervals: + if interval[1] <= left or interval[0] >= right: + tmp.append(interval) + else: + if interval[0] < left: + tmp.append((interval[0], left)) + if right < interval[1]: + tmp.append((right, interval[1])) + self.__intervals = tmp + + +# Your RangeModule object will be instantiated and called as such: +# obj = RangeModule() +# obj.addRange(left,right) +# param_2 = obj.queryRange(left,right) +# obj.removeRange(left,right) diff --git a/Python/range-sum-query-2d-immutable.py b/Python/range-sum-query-2d-immutable.py new file mode 100644 index 000000000..786f74939 --- /dev/null +++ b/Python/range-sum-query-2d-immutable.py @@ -0,0 +1,65 @@ +# Time: ctor: O(m * n), +# lookup: O(1) +# Space: O(m * n) +# +# Given a 2D matrix matrix, find the sum of the elements inside +# the rectangle defined by its upper left corner (row1, col1) +# and lower right corner (row2, col2). +# +# Range Sum Query 2D +# The above rectangle (with the red border) is defined by +# (row1, col1) = (2, 1) and (row2, col2) = (4, 3), +# which contains sum = 8. +# +# Example: +# Given matrix = [ +# [3, 0, 1, 4, 2], +# [5, 6, 3, 2, 1], +# [1, 2, 0, 1, 5], +# [4, 1, 0, 1, 7], +# [1, 0, 3, 0, 5] +# ] +# +# sumRegion(2, 1, 4, 3) -> 8 +# sumRegion(1, 1, 2, 2) -> 11 +# sumRegion(1, 2, 2, 4) -> 12 +# Note: +# You may assume that the matrix does not change. +# There are many calls to sumRegion function. +# You may assume that row1 <= row2 and col1 <= col2. + +class NumMatrix(object): + def __init__(self, matrix): + """ + initialize your data structure here. + :type matrix: List[List[int]] + """ + if not matrix: + return + + m, n = len(matrix), len(matrix[0]) + self.__sums = [[0 for _ in xrange(n+1)] for _ in xrange(m+1)] + for i in xrange(1, m+1): + for j in xrange(1, n+1): + self.__sums[i][j] = self.__sums[i][j-1] + matrix[i-1][j-1] + for j in xrange(1, n+1): + for i in xrange(1, m+1): + self.__sums[i][j] += self.__sums[i-1][j] + + def sumRegion(self, row1, col1, row2, col2): + """ + sum of elements matrix[(row1,col1)..(row2,col2)], inclusive. + :type row1: int + :type col1: int + :type row2: int + :type col2: int + :rtype: int + """ + return self.__sums[row2+1][col2+1] - self.__sums[row2+1][col1] - \ + self.__sums[row1][col2+1] + self.__sums[row1][col1] + + +# Your NumMatrix object will be instantiated and called as such: +# numMatrix = NumMatrix(matrix) +# numMatrix.sumRegion(0, 1, 2, 3) +# numMatrix.sumRegion(1, 2, 3, 4) diff --git a/Python/range-sum-query-2d-mutable.py b/Python/range-sum-query-2d-mutable.py new file mode 100644 index 000000000..ac8963f41 --- /dev/null +++ b/Python/range-sum-query-2d-mutable.py @@ -0,0 +1,81 @@ +# Time: ctor: O(m * n) +# update: O(logm * logn) +# query: O(logm * logn) +# Space: O(m * n) + +# Binary Indexed Tree (BIT) solution. +class NumMatrix(object): + def __init__(self, matrix): + """ + initialize your data structure here. + :type matrix: List[List[int]] + """ + if not matrix: + return + self.__matrix = matrix + self.__bit = [[0] * (len(self.__matrix[0]) + 1) \ + for _ in xrange(len(self.__matrix) + 1)] + for i in xrange(1, len(self.__bit)): + for j in xrange(1, len(self.__bit[0])): + self.__bit[i][j] = matrix[i-1][j-1] + self.__bit[i-1][j] + \ + self.__bit[i][j-1] - self.__bit[i-1][j-1] + for i in reversed(xrange(1, len(self.__bit))): + for j in reversed(xrange(1, len(self.__bit[0]))): + last_i, last_j = i - (i & -i), j - (j & -j) + self.__bit[i][j] = self.__bit[i][j] - self.__bit[i][last_j] - \ + self.__bit[last_i][j] + self.__bit[last_i][last_j] + + def update(self, row, col, val): + """ + update the element at matrix[row,col] to val. + :type row: int + :type col: int + :type val: int + :rtype: void + """ + if val - self.__matrix[row][col]: + self.__add(row, col, val - self.__matrix[row][col]) + self.__matrix[row][col] = val + + def sumRegion(self, row1, col1, row2, col2): + """ + sum of elements matrix[(row1,col1)..(row2,col2)], inclusive. + :type row1: int + :type col1: int + :type row2: int + :type col2: int + :rtype: int + """ + return self.__sum(row2, col2) - self.__sum(row2, col1 - 1) - \ + self.__sum(row1 - 1, col2) + self.__sum(row1 - 1, col1 - 1) + + def __sum(self, row, col): + row += 1 + col += 1 + ret = 0 + i = row + while i > 0: + j = col + while j > 0: + ret += self.__bit[i][j] + j -= (j & -j) + i -= (i & -i) + return ret + + def __add(self, row, col, val): + row += 1 + col += 1 + i = row + while i <= len(self.__matrix): + j = col + while j <= len(self.__matrix[0]): + self.__bit[i][j] += val + j += (j & -j) + i += (i & -i) + + +# Your NumMatrix object will be instantiated and called as such: +# numMatrix = NumMatrix(matrix) +# numMatrix.sumRegion(0, 1, 2, 3) +# numMatrix.update(1, 1, 10) +# numMatrix.sumRegion(1, 2, 3, 4) diff --git a/Python/range-sum-query-immutable.py b/Python/range-sum-query-immutable.py new file mode 100644 index 000000000..a5c6d7775 --- /dev/null +++ b/Python/range-sum-query-immutable.py @@ -0,0 +1,41 @@ +# Time: ctor: O(n), +# lookup: O(1) +# Space: O(n) +# +#Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. +# +# Example: +# Given nums = [-2, 0, 3, -5, 2, -1] +# +# sumRange(0, 2) -> 1 +# sumRange(2, 5) -> -1 +# sumRange(0, 5) -> -3 +# Note: +# You may assume that the array does not change. +# There are many calls to sumRange function. +# + +class NumArray(object): + def __init__(self, nums): + """ + initialize your data structure here. + :type nums: List[int] + """ + self.accu = [0] + for num in nums: + self.accu.append(self.accu[-1] + num), + + def sumRange(self, i, j): + """ + sum of elements nums[i..j], inclusive. + :type i: int + :type j: int + :rtype: int + """ + return self.accu[j + 1] - self.accu[i] + + +# Your NumArray object will be instantiated and called as such: +# numArray = NumArray(nums) +# numArray.sumRange(0, 1) +# numArray.sumRange(1, 2) diff --git a/Python/range-sum-query-mutable.py b/Python/range-sum-query-mutable.py new file mode 100644 index 000000000..d9b7db624 --- /dev/null +++ b/Python/range-sum-query-mutable.py @@ -0,0 +1,166 @@ +# Time: ctor: O(n), +# update: O(logn), +# query: O(logn) +# Space: O(n) + +# Given an integer array nums, find the sum of +# the elements between indices i and j (i <= j), inclusive. +# +# The update(i, val) function modifies nums by +# updating the element at index i to val. +# Example: +# Given nums = [1, 3, 5] +# +# sumRange(0, 2) -> 9 +# update(1, 2) +# sumRange(0, 2) -> 8 +# Note: +# The array is only modifiable by the update function. +# You may assume the number of calls to update +# and sumRange function is distributed evenly. + +# Binary Indexed Tree (BIT) solution. +class NumArray(object): + def __init__(self, nums): + """ + initialize your data structure here. + :type nums: List[int] + """ + if not nums: + return + self.__nums = nums + self.__bit = [0] * (len(self.__nums) + 1) + for i in xrange(1, len(self.__bit)): + self.__bit[i] = nums[i-1] + self.__bit[i-1] + + for i in reversed(xrange(1, len(self.__bit))): + last_i = i - (i & -i) + self.__bit[i] -= self.__bit[last_i] + + def update(self, i, val): + """ + :type i: int + :type val: int + :rtype: int + """ + if val - self.__nums[i]: + self.__add(i, val - self.__nums[i]) + self.__nums[i] = val + + def sumRange(self, i, j): + """ + sum of elements nums[i..j], inclusive. + :type i: int + :type j: int + :rtype: int + """ + return self.__sum(j) - self.__sum(i-1) + + def __sum(self, i): + i += 1 + ret = 0 + while i > 0: + ret += self.__bit[i] + i -= (i & -i) + return ret + + def __add(self, i, val): + i += 1 + while i <= len(self.__nums): + self.__bit[i] += val + i += (i & -i) + + +# Time: ctor: O(n), +# update: O(logn), +# query: O(logn) +# Space: O(n) +# Segment Tree solutoin. +class NumArray2(object): + def __init__(self, nums): + """ + initialize your data structure here. + :type nums: List[int] + """ + # Build segment tree. + self.__nums = nums + def buildHelper(nums, start, end): + if start > end: + return None + + # The root's start and end is given by build method. + root = self._SegmentTreeNode(start, end, 0) + + # If start equals to end, there will be no children for this node. + if start == end: + root.sum = nums[start] + return root + + # Left child: start=nums.left, end=(nums.left + nums.right) / 2. + root.left = buildHelper(nums, start, (start + end) / 2) + + # Right child: start=(nums.left + nums.right) / 2 + 1, end=nums.right. + root.right = buildHelper(nums, (start + end) / 2 + 1, end) + + # Update sum. + root.sum = (root.left.sum if root.left else 0) + \ + (root.right.sum if root.right else 0) + return root + + self.__root = buildHelper(nums, 0, len(nums) - 1) + + def update(self, i, val): + """ + :type i: int + :type val: int + :rtype: int + """ + def updateHelper(root, i, val): + # Out of range. + if not root or root.start > i or root.end < i: + return + + # Change the node's value with [i] to the new given value. + if root.start == i and root.end == i: + root.sum = val + return + + updateHelper(root.left, i, val) + updateHelper(root.right, i, val) + + # Update sum. + root.sum = (root.left.sum if root.left else 0) + \ + (root.right.sum if root.right else 0) + if self.__nums[i] != val: + self.__nums[i] = val + updateHelper(self.__root, i, val) + + def sumRange(self, i, j): + """ + sum of elements nums[i..j], inclusive. + :type i: int + :type j: int + :rtype: int + """ + def sumRangeHelper(root, start, end): + # Out of range. + if not root or root.start > end or root.end < start: + return 0 + # Current segment is totally within range [start, end] + if root.start >= start and root.end <= end: + return root.sum + return sumRangeHelper(root.left, start, end) + \ + sumRangeHelper(root.right, start, end) + + return sumRangeHelper(self.__root, i, j) + + class _SegmentTreeNode: + def __init__(self, i, j, s): + self.start, self.end, self.sum = i, j, s + + +# Your NumArray object will be instantiated and called as such: +# numArray = NumArray(nums) +# numArray.sumRange(0, 1) +# numArray.update(1, 10) +# numArray.sumRange(1, 2) diff --git a/Python/ransom-note.py b/Python/ransom-note.py new file mode 100644 index 000000000..917334555 --- /dev/null +++ b/Python/ransom-note.py @@ -0,0 +1,53 @@ +# Time: O(n) +# Space: O(1) + +# Given an arbitrary ransom note string and another string containing letters +# from all the magazines, write a function that will return true if +# the ransom note can be constructed from the magazines ; +# otherwise, it will return false. +# +# Each letter in the magazine string can only be used once in your ransom note. +# +# Note: +# You may assume that both strings contain only lowercase letters. +# +# canConstruct("a", "b") -> false +# canConstruct("aa", "ab") -> false +# canConstruct("aa", "aab") -> true + +class Solution(object): + def canConstruct(self, ransomNote, magazine): + """ + :type ransomNote: str + :type magazine: str + :rtype: bool + """ + counts = [0] * 26 + letters = 0 + + for c in ransomNote: + if counts[ord(c) - ord('a')] == 0: + letters += 1 + counts[ord(c) - ord('a')] += 1 + + for c in magazine: + counts[ord(c) - ord('a')] -= 1 + if counts[ord(c) - ord('a')] == 0: + letters -= 1 + if letters == 0: + break + + return letters == 0 + +# Time: O(n) +# Space: O(1) +import collections + +class Solution2(object): + def canConstruct(self, ransomNote, magazine): + """ + :type ransomNote: str + :type magazine: str + :rtype: bool + """ + return not collections.Counter(ransomNote) - collections.Counter(magazine) diff --git a/Python/read-n-characters-given-read4-ii-call-multiple-times.py b/Python/read-n-characters-given-read4-ii-call-multiple-times.py index 91532e01c..2645c5fd0 100644 --- a/Python/read-n-characters-given-read4-ii-call-multiple-times.py +++ b/Python/read-n-characters-given-read4-ii-call-multiple-times.py @@ -27,31 +27,37 @@ def read4(buf): file_content = "" return i -class Solution: +# The read4 API is already defined for you. +# @param buf, a list of characters +# @return an integer +# def read4(buf): + +class Solution(object): def __init__(self): - self.buffer_size, self.offset = 0, 0 - self.buffer = [None for _ in xrange(4)] - - # @param buf, Destination buffer (a list of characters) - # @param n, Maximum number of characters to read (an integer) - # @return The number of characters read (an integer) + self.__buf4 = [''] * 4 + self.__i4 = 0 + self.__n4 = 0 + def read(self, buf, n): - read_bytes = 0 - eof = False - while not eof and read_bytes < n: - if self.buffer_size == 0: - size = read4(self.buffer) + """ + :type buf: Destination buffer (List[str]) + :type n: Maximum number of characters to read (int) + :rtype: The number of characters read (int) + """ + i = 0 + while i < n: + if self.__i4 < self.__n4: # Any characters in buf4. + buf[i] = self.__buf4[self.__i4] + i += 1 + self.__i4 += 1 else: - size = self.buffer_size - if self.buffer_size == 0 and size < 4: - eof = True - bytes = min(n - read_bytes, size) - for i in xrange(bytes): - buf[read_bytes + i] = self.buffer[self.offset + i] - self.offset = (self.offset + bytes) % 4 - self.buffer_size = size - bytes - read_bytes += bytes - return read_bytes + self.__n4 = read4(self.__buf4) # Read more characters. + if self.__n4: + self.__i4 = 0 + else: # Buffer has been empty. + break + + return i if __name__ == "__main__": global file_content diff --git a/Python/read-n-characters-given-read4.py b/Python/read-n-characters-given-read4.py index 912eb1c25..1581cca20 100644 --- a/Python/read-n-characters-given-read4.py +++ b/Python/read-n-characters-given-read4.py @@ -27,23 +27,23 @@ def read4(buf): file_content = "" return i -class Solution: - # @param buf, Destination buffer (a list of characters) - # @param n, Maximum number of characters to read (an integer) - # @return The number of characters read (an integer) +class Solution(object): def read(self, buf, n): + """ + :type buf: Destination buffer (List[str]) + :type n: Maximum number of characters to read (int) + :rtype: The number of characters read (int) + """ read_bytes = 0 - eof = False - buffer = ['' for _ in xrange(4)] - while not eof and read_bytes < n: + buffer = [''] * 4 + for i in xrange(n / 4 + 1): size = read4(buffer) - if size < 4: - eof = True - bytes = min(n - read_bytes, size) - for i in xrange(bytes): - buf[read_bytes + i] = buffer[i] - read_bytes += bytes - return read_bytes + if size: + buf[read_bytes:read_bytes+size] = buffer + read_bytes += size + else: + break + return min(read_bytes, n) if __name__ == "__main__": global file_content @@ -51,4 +51,4 @@ def read(self, buf, n): file_content = "a" print buf[:Solution().read(buf, 9)] file_content = "abcdefghijklmnop" - print buf[:Solution().read(buf, 9)] \ No newline at end of file + print buf[:Solution().read(buf, 9)] diff --git a/Python/rearrange-string-k-distance-apart.py b/Python/rearrange-string-k-distance-apart.py new file mode 100644 index 000000000..98610862c --- /dev/null +++ b/Python/rearrange-string-k-distance-apart.py @@ -0,0 +1,71 @@ +# Time: O(n) +# Space: O(n) + +class Solution(object): + def rearrangeString(self, str, k): + """ + :type str: str + :type k: int + :rtype: str + """ + cnts = [0] * 26; + for c in str: + cnts[ord(c) - ord('a')] += 1 + + sorted_cnts = [] + for i in xrange(26): + sorted_cnts.append((cnts[i], chr(i + ord('a')))) + sorted_cnts.sort(reverse=True) + + max_cnt = sorted_cnts[0][0] + blocks = [[] for _ in xrange(max_cnt)] + i = 0 + for cnt in sorted_cnts: + for _ in xrange(cnt[0]): + blocks[i].append(cnt[1]) + i = (i + 1) % max(cnt[0], max_cnt - 1) + + for i in xrange(max_cnt-1): + if len(blocks[i]) < k: + return "" + + return "".join(map(lambda x : "".join(x), blocks)) + + +# Time: O(nlogc), c is the count of unique characters. +# Space: O(c) +from collections import defaultdict +from heapq import heappush, heappop +class Solution2(object): + def rearrangeString(self, str, k): + """ + :type str: str + :type k: int + :rtype: str + """ + if k == 0: + return str + + cnts = defaultdict(int) + for c in str: + cnts[c] += 1 + + heap = [] + for c, cnt in cnts.iteritems(): + heappush(heap, [-cnt, c]) + + result = [] + while heap: + used_cnt_chars = [] + for _ in xrange(min(k, len(str) - len(result))): + if not heap: + return "" + cnt_char = heappop(heap) + result.append(cnt_char[1]) + cnt_char[0] += 1 + if cnt_char[0] < 0: + used_cnt_chars.append(cnt_char) + for cnt_char in used_cnt_chars: + heappush(heap, cnt_char) + + return "".join(result) diff --git a/Python/reconstruct-itinerary.py b/Python/reconstruct-itinerary.py new file mode 100644 index 000000000..2305889b4 --- /dev/null +++ b/Python/reconstruct-itinerary.py @@ -0,0 +1,56 @@ +# Time: O(t! / (n1! * n2! * ... nk!)), t is the total number of tickets, +# ni is the number of the ticket which from is city i, +# k is the total number of cities. +# Space: O(t) + +# Given a list of airline tickets represented by pairs of departure +# and arrival airports [from, to], reconstruct the itinerary in order. +# All of the tickets belong to a man who departs from JFK. +# Thus, the itinerary must begin with JFK. +# +# Note: +# If there are multiple valid itineraries, you should return the itinerary +# that has the smallest lexical order when read as a single string. +# For example, the itinerary ["JFK", "LGA"] has a smaller lexical +# order than ["JFK", "LGB"]. +# All airports are represented by three capital letters (IATA code). +# You may assume all tickets may form at least one valid itinerary. +# Example 1: +# tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]] +# Return ["JFK", "MUC", "LHR", "SFO", "SJC"]. +# Example 2: +# tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]] +# Return ["JFK","ATL","JFK","SFO","ATL","SFO"]. +# Another possible reconstruction is ["JFK","SFO","ATL","JFK","ATL","SFO"]. +# But it is larger in lexical order. + +class Solution(object): + def findItinerary(self, tickets): + """ + :type tickets: List[List[str]] + :rtype: List[str] + """ + def route_helper(origin, ticket_cnt, graph, ans): + if ticket_cnt == 0: + return True + + for i, (dest, valid) in enumerate(graph[origin]): + if valid: + graph[origin][i][1] = False + ans.append(dest) + if route_helper(dest, ticket_cnt - 1, graph, ans): + return ans + ans.pop() + graph[origin][i][1] = True + return False + + graph = collections.defaultdict(list) + for ticket in tickets: + graph[ticket[0]].append([ticket[1], True]) + for k in graph.keys(): + graph[k].sort() + + origin = "JFK" + ans = [origin] + route_helper(origin, len(tickets), graph, ans) + return ans diff --git a/Python/reconstruct-original-digits-from-english.py b/Python/reconstruct-original-digits-from-english.py new file mode 100644 index 000000000..ff7797bde --- /dev/null +++ b/Python/reconstruct-original-digits-from-english.py @@ -0,0 +1,49 @@ +# Time: O(n) +# Space: O(1) + +# Given a non-empty string containing an out-of-order English representation +# of digits 0-9, output the digits in ascending order. +# +# Note: +# Input contains only lowercase English letters. +# Input is guaranteed to be valid and can be transformed to its original digits. +# That means invalid inputs such as "abc" or "zerone" are not permitted. +# Input length is less than 50,000. +# Example 1: +# Input: "owoztneoer" +# +# Output: "012" +# Example 2: +# Input: "fviefuro" +# +# Output: "45" + +from collections import Counter + +class Solution(object): + def originalDigits(self, s): + """ + :type s: str + :rtype: str + """ + # The count of each char in each number string. + cnts = [Counter(_) for _ in ["zero", "one", "two", "three", \ + "four", "five", "six", "seven", \ + "eight", "nine"]] + + # The order for greedy method. + order = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9] + + # The unique char in the order. + unique_chars = ['z', 'o', 'w', 't', 'u', \ + 'f', 'x', 's', 'g', 'n'] + + cnt = Counter(list(s)) + res = [] + for i in order: + while cnt[unique_chars[i]] > 0: + cnt -= cnts[i] + res.append(i) + res.sort() + + return "".join(map(str, res)) diff --git a/Python/rectangle-area.py b/Python/rectangle-area.py new file mode 100644 index 000000000..52b879654 --- /dev/null +++ b/Python/rectangle-area.py @@ -0,0 +1,28 @@ +# Time: O(1) +# Space: O(1) +# +# Find the total area covered by two rectilinear rectangles in a 2D plane. +# +# Each rectangle is defined by its bottom left corner +# and top right corner as shown in the figure. +# +# Rectangle Area +# Assume that the total area is never beyond the maximum +# possible value of int. +# + +class Solution: + # @param {integer} A + # @param {integer} B + # @param {integer} C + # @param {integer} D + # @param {integer} E + # @param {integer} F + # @param {integer} G + # @param {integer} H + # @return {integer} + def computeArea(self, A, B, C, D, E, F, G, H): + return (D - B) * (C - A) + \ + (G - E) * (H - F) - \ + max(0, (min(C, G) - max(A, E))) * \ + max(0, (min(D, H) - max(B, F))) diff --git a/Python/redundant-connection-ii.py b/Python/redundant-connection-ii.py new file mode 100644 index 000000000..39f86635f --- /dev/null +++ b/Python/redundant-connection-ii.py @@ -0,0 +1,70 @@ +# Time: O(nlog*n) ~= O(n), n is the length of the positions +# Space: O(n) + +# In this problem, a rooted tree is a directed graph such that, +# there is exactly one node (the root) for +# which all other nodes are descendants of this node, plus every node has exactly one parent, +# except for the root node which has no parents. +# +# The given input is a directed graph that started as a rooted tree with N nodes +# (with distinct values 1, 2, ..., N), with one additional directed edge added. +# The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed. +# +# The resulting graph is given as a 2D-array of edges. +# Each element of edges is a pair [u, v] that represents a directed edge connecting nodes u and v, +# where u is a parent of child v. +# +# Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. +# If there are multiple answers, return the answer that occurs last in the given 2D-array. +# +# Example 1: +# Input: [[1,2], [1,3], [2,3]] +# Output: [2,3] +# Explanation: The given directed graph will be like this: +# 1 +# / \ +# v v +# 2-->3 +# Example 2: +# Input: [[1,2], [2,3], [3,4], [4,1], [1,5]] +# Output: [4,1] +# Explanation: The given directed graph will be like this: +# 5 <- 1 -> 2 +# ^ | +# | v +# 4 <- 3 +# Note: +# The size of the input 2D-array will be between 3 and 1000. +# Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array. + +class UnionFind(object): + def __init__(self, n): + self.set = range(n) + self.count = n + + def find_set(self, x): + if self.set[x] != x: + self.set[x] = self.find_set(self.set[x]) # path compression. + return self.set[x] + + def union_set(self, x, y): + x_root, y_root = map(self.find_set, (x, y)) + if x_root == y_root or \ + y != y_root: # already has a father + return False + self.set[y_root] = x_root + self.count -= 1 + return True + + +class Solution(object): + def findRedundantDirectedConnection(self, edges): + """ + :type edges: List[List[int]] + :rtype: List[int] + """ + union_find = UnionFind(len(edges)+1) + for edge in edges: + if not union_find.union_set(*edge): + return edge + return [] diff --git a/Python/redundant-connection.py b/Python/redundant-connection.py new file mode 100644 index 000000000..c26efe3dd --- /dev/null +++ b/Python/redundant-connection.py @@ -0,0 +1,62 @@ +# Time: O(nlog*n) ~= O(n), n is the length of the positions +# Space: O(n) + +# We are given a "tree" in the form of a 2D-array, with distinct values for each node. +# +# In the given 2D-array, each element pair [u, v] represents that v is a child of u in the tree. +# +# We can remove exactly one redundant pair in this "tree" to make the result a (rooted) tree. +# +# You need to find and output such a pair. If there are multiple answers for this question, +# output the one appearing last in the 2D-array. There is always at least one answer. +# +# Example 1: +# Input: [[1,2], [1,3], [2,3]] +# Output: [2,3] +# Explanation: Original tree will be like this: +# 1 +# / \ +# 2 - 3 +# +# Example 2: +# Input: [[1,2], [1,3], [3,1]] +# Output: [3,1] +# Explanation: Original tree will be like this: +# 1 +# / \\ +# 2 3 +# Note: +# The size of the input 2D-array will be between 3 and 1000. +# Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array. + +class UnionFind(object): + def __init__(self, n): + self.set = range(n) + self.count = n + + def find_set(self, x): + if self.set[x] != x: + self.set[x] = self.find_set(self.set[x]) # path compression. + return self.set[x] + + def union_set(self, x, y): + x_root, y_root = map(self.find_set, (x, y)) + if x_root == y_root: + return False + self.set[min(x_root, y_root)] = max(x_root, y_root) + self.count -= 1 + return True + + +class Solution(object): + def findRedundantConnection(self, edges): + """ + :type edges: List[List[int]] + :rtype: List[int] + """ + union_find = UnionFind(len(edges)+1) + for edge in edges: + if not union_find.union_set(*edge): + return edge + return [] + diff --git a/Python/regular-expression-matching.py b/Python/regular-expression-matching.py index f6c6d2746..3101c52c7 100644 --- a/Python/regular-expression-matching.py +++ b/Python/regular-expression-matching.py @@ -40,7 +40,7 @@ def isMatch(self, s, p): if p[j-1] != '*': result[i % k][j] = result[(i-1) % k][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.') else: - result[i % k][j] = result[i % k][j-2] or (result[(i-1) % k][j] and (s[i-1] == p[j-2] or p[j-2]=='.')) + result[i % k][j] = result[i % k][j-2] or (result[(i-1) % k][j] and (s[i-1] == p[j-2] or p[j-2] == '.')) return result[len(s) % k][len(p)] @@ -62,19 +62,53 @@ def isMatch(self, s, p): if p[j-1] != '*': result[i][j] = result[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.') else: - result[i][j] = result[i][j-2] or (result[i-1][j] and (s[i-1] == p[j-2] or p[j-2]=='.')) + result[i][j] = result[i][j-2] or (result[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.')) return result[len(s)][len(p)] -# recursive +# iteration class Solution3: # @return a boolean def isMatch(self, s, p): - if len(p) == 0: - return len(s) == 0 + p_ptr, s_ptr, last_s_ptr, last_p_ptr = 0, 0, -1, -1 + last_ptr = [] + while s_ptr < len(s): + if p_ptr < len(p) and (p_ptr == len(p) - 1 or p[p_ptr + 1] != '*') and \ + (s_ptr < len(s) and (p[p_ptr] == s[s_ptr] or p[p_ptr] == '.')): + s_ptr += 1 + p_ptr += 1 + elif p_ptr < len(p) - 1 and (p_ptr != len(p) - 1 and p[p_ptr + 1] == '*'): + p_ptr += 2 + last_ptr.append([s_ptr, p_ptr]) + elif last_ptr: + [last_s_ptr, last_p_ptr] = last_ptr.pop() + while last_ptr and p[last_p_ptr - 2] != s[last_s_ptr] and p[last_p_ptr - 2] != '.': + [last_s_ptr, last_p_ptr] = last_ptr.pop() + + if p[last_p_ptr - 2] == s[last_s_ptr] or p[last_p_ptr - 2] == '.': + last_s_ptr += 1 + s_ptr = last_s_ptr + p_ptr = last_p_ptr + last_ptr.append([s_ptr, p_ptr]) + else: + return False + else: + return False + + while p_ptr < len(p) - 1 and p[p_ptr] == '.' and p[p_ptr + 1] == '*': + p_ptr += 2 + + return p_ptr == len(p) + +# recursive +class Solution4: + # @return a boolean + def isMatch(self, s, p): + if not p: + return not s if len(p) == 1 or p[1] != '*': - if len(s) == 0 or (p[0] == s[0] or p[0] == '.'): + if len(s) > 0 and (p[0] == s[0] or p[0] == '.'): return self.isMatch(s[1:], p[1:]) else: return False @@ -86,7 +120,7 @@ def isMatch(self, s, p): return self.isMatch(s, p[2:]) if __name__ == "__main__": - print Solution().isMatch("abcd","d*") + print Solution3().isMatch("abab", "a*b*") print Solution().isMatch("aaaaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*c") print Solution().isMatch("aa","a") print Solution().isMatch("aa","aa") diff --git a/Python/relative-ranks.py b/Python/relative-ranks.py new file mode 100644 index 000000000..3b32dd9a4 --- /dev/null +++ b/Python/relative-ranks.py @@ -0,0 +1,27 @@ +# Time: O(nlogn) +# Space: O(n) + +# Given scores of N athletes, find their relative ranks and +# the people with the top three highest scores, who will be +# awarded medals: "Gold Medal", "Silver Medal" and "Bronze Medal". +# +# Example 1: +# Input: [5, 4, 3, 2, 1] +# Output: ["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"] +# Explanation: The first three athletes got the top three highest scores, +# so they got "Gold Medal", "Silver Medal" and "Bronze Medal". +# For the left two athletes, you just need to output +# their relative ranks according to their scores. +# Note: +# N is a positive integer and won't exceed 10,000. +# All the scores of athletes are guaranteed to be unique. + +class Solution(object): + def findRelativeRanks(self, nums): + """ + :type nums: List[int] + :rtype: List[str] + """ + sorted_nums = sorted(nums)[::-1] + ranks = ["Gold Medal", "Silver Medal", "Bronze Medal"] + map(str, range(4, len(nums) + 1)) + return map(dict(zip(sorted_nums, ranks)).get, nums) diff --git a/Python/remove-9.py b/Python/remove-9.py new file mode 100644 index 000000000..ec7ad01e3 --- /dev/null +++ b/Python/remove-9.py @@ -0,0 +1,15 @@ +# Time: O(logn) +# Space: O(1) + +class Solution(object): + def newInteger(self, n): + """ + :type n: int + :rtype: int + """ + result, base = 0, 1 + while n > 0: + result += (n%9) * base + n /= 9 + base *= 10 + return result diff --git a/Python/remove-boxes.py b/Python/remove-boxes.py new file mode 100644 index 000000000..a34b96d6a --- /dev/null +++ b/Python/remove-boxes.py @@ -0,0 +1,46 @@ +# Time: O(n^3) ~ O(n^4) +# Space: O(n^3) + +# Given several boxes with different colors represented by different positive numbers. +# You may experience several rounds to remove boxes until there is no box left. +# Each time you can choose some continuous boxes with the same color (composed of k boxes, k >= 1), +# remove them and get k*k points. +# Find the maximum points you can get. +# +# Example 1: +# Input: +# +# [1, 3, 2, 2, 2, 3, 4, 3, 1] +# Output: +# 23 +# Explanation: +# [1, 3, 2, 2, 2, 3, 4, 3, 1] +# ----> [1, 3, 3, 4, 3, 1] (3*3=9 points) +# ----> [1, 3, 3, 3, 1] (1*1=1 points) +# ----> [1, 1] (3*3=9 points) +# ----> [] (2*2=4 points) +# Note: The number of boxes n would not exceed 100. + +class Solution(object): + def removeBoxes(self, boxes): + """ + :type boxes: List[int] + :rtype: int + """ + def dfs(boxes, l, r, k, lookup): + if l > r: return 0 + if lookup[l][r][k]: return lookup[l][r][k] + + ll, kk = l, k + while l < r and boxes[l+1] == boxes[l]: + l += 1 + k += 1 + result = dfs(boxes, l+1, r, 0, lookup) + (k+1) ** 2 + for i in xrange(l+1, r+1): + if boxes[i] == boxes[l]: + result = max(result, dfs(boxes, l+1, i-1, 0, lookup) + dfs(boxes, i, r, k+1, lookup)) + lookup[ll][r][kk] = result + return result + + lookup = [[[0]*len(boxes) for _ in xrange(len(boxes)) ] for _ in xrange(len(boxes)) ] + return dfs(boxes, 0, len(boxes)-1, 0, lookup) diff --git a/Python/remove-comments.py b/Python/remove-comments.py new file mode 100644 index 000000000..5b8707e0e --- /dev/null +++ b/Python/remove-comments.py @@ -0,0 +1,108 @@ +# Time: O(n), n is the length of the source +# Space: O(k), k is the max length of a line + +# Given a C++ program, remove comments from it. +# The program source is an array where source[i] is the i-th line of the source code. +# This represents the result of splitting the original source code string by the newline character \n. +# +# In C++, there are two types of comments, line comments, and block comments. +# +# The string // denotes a line comment, which represents that it and +# rest of the characters to the right of it in the same line should be ignored. +# +# The string /* denotes a block comment, +# which represents that all characters until the next (non-overlapping) occurrence of */ +# should be ignored. (Here, occurrences happen in reading order: line by line from left to right.) +# To be clear, the string /*/ does not yet end the block comment, as the ending would be overlapping the beginning. +# +# The first effective comment takes precedence over others: +# if the string // occurs in a block comment, it is ignored. +# Similarly, if the string /* occurs in a line or block comment, it is also ignored. +# +# If a certain line of code is empty after removing comments, +# you must not output that line: each string in the answer list will be non-empty. +# +# There will be no control characters, single quote, or double quote characters. +# For example, source = "string s = "/* Not a comment. */";" will not be a test case. +# (Also, nothing else such as defines or macros will interfere with the comments.) +# +# It is guaranteed that every open block comment will eventually be closed, +# so /* outside of a line or block comment always starts a new comment. +# +# Finally, implicit newline characters can be deleted by block comments. Please see the examples below for details. +# +# After removing the comments from the source code, return the source code in the same format. +# +# Example 1: +# Input: +# source = ["/*Test program */", "int main()", "{ ", " // variable declaration ", "int a, b, c;", "/* This is a test", " multiline ", " comment for ", " testing */", "a = b + c;", "}"] +# +# The line by line code is visualized as below: +# /*Test program */ +# int main() +# { +# // variable declaration +# int a, b, c; +# /* This is a test +# multiline +# comment for +# testing */ +# a = b + c; +# } +# +# Output: ["int main()","{ "," ","int a, b, c;","a = b + c;","}"] +# +# The line by line code is visualized as below: +# int main() +# { +# int a, b, c; +# a = b + c; +# } +# Explanation: +# The string +# /* +# denotes a block comment, including line 1 and lines 6-9. The string +# // +# denotes line 4 as comments. +# +# Example 2: +# Input: +# source = ["a/*comment", "line", "more_comment*/b"] +# Output: ["ab"] +# Explanation: The original source string is "a/*comment\nline\nmore_comment*/b", +# where we have bolded the newline characters. +# After deletion, the implicit newline characters are deleted, +# leaving the string "ab", which when delimited by newline characters becomes ["ab"]. +# +# Note: +# - The length of source is in the range [1, 100]. +# - The length of source[i] is in the range [0, 80]. +# - Every open block comment is eventually closed. +# - There are no single-quote, double-quote, or control characters in the source code. + +class Solution(object): + def removeComments(self, source): + """ + :type source: List[str] + :rtype: List[str] + """ + in_block = False + result, newline = [], [] + for line in source: + i = 0 + while i < len(line): + if not in_block and i+1 < len(line) and line[i:i+2] == '/*': + in_block = True + i += 1 + elif in_block and i+1 < len(line) and line[i:i+2] == '*/': + in_block = False + i += 1 + elif not in_block and i+1 < len(line) and line[i:i+2] == '//': + break + elif not in_block: + newline.append(line[i]) + i += 1 + if newline and not in_block: + result.append("".join(newline)) + newline = [] + return result diff --git a/Python/remove-duplicate-letters.py b/Python/remove-duplicate-letters.py new file mode 100644 index 000000000..552643870 --- /dev/null +++ b/Python/remove-duplicate-letters.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(k), k is size of the alphabet + +# Given a string which contains only lowercase letters, +# remove duplicate letters so that every letter appear +# once and only once. You must make sure your result is +# the smallest in lexicographical order among all +# possible results. +# +# Example: +# Given "bcabc" +# Return "abc" +# +# Given "cbacdcbc" +# Return "acdb" + +class Solution(object): + def removeDuplicateLetters(self, s): + """ + :type s: str + :rtype: str + """ + remaining = collections.defaultdict(int) + for c in s: + remaining[c] += 1 + + in_stack, stk = set(), [] + for c in s: + if c not in in_stack: + while stk and stk[-1] > c and remaining[stk[-1]]: + in_stack.remove(stk.pop()) + stk += c + in_stack.add(c) + remaining[c] -= 1 + return "".join(stk) diff --git a/Python/remove-duplicates-from-sorted-array-ii.py b/Python/remove-duplicates-from-sorted-array-ii.py index 527416e7f..794b192ae 100644 --- a/Python/remove-duplicates-from-sorted-array-ii.py +++ b/Python/remove-duplicates-from-sorted-array-ii.py @@ -14,7 +14,7 @@ class Solution: # @param a list of integers # @return an integer def removeDuplicates(self, A): - if len(A) == 0: + if not A: return 0 last, i, same = 0, 1, False @@ -28,4 +28,4 @@ def removeDuplicates(self, A): return last + 1 if __name__ == "__main__": - print Solution().removeDuplicates([1, 1, 1, 2, 2, 3]) \ No newline at end of file + print Solution().removeDuplicates([1, 1, 1, 2, 2, 3]) diff --git a/Python/remove-duplicates-from-sorted-array.py b/Python/remove-duplicates-from-sorted-array.py index 473e645fc..7ea358680 100644 --- a/Python/remove-duplicates-from-sorted-array.py +++ b/Python/remove-duplicates-from-sorted-array.py @@ -15,7 +15,7 @@ class Solution: # @param a list of integers # @return an integer def removeDuplicates(self, A): - if len(A) == 0: + if not A: return 0 last, i = 0, 1 @@ -28,4 +28,4 @@ def removeDuplicates(self, A): return last + 1 if __name__ == "__main__": - print Solution().removeDuplicates([1, 1, 2]) \ No newline at end of file + print Solution().removeDuplicates([1, 1, 2]) diff --git a/Python/remove-duplicates-from-sorted-list-ii.py b/Python/remove-duplicates-from-sorted-list-ii.py index 5c8f44e14..0f21f2171 100644 --- a/Python/remove-duplicates-from-sorted-list-ii.py +++ b/Python/remove-duplicates-from-sorted-list-ii.py @@ -21,21 +21,24 @@ def __repr__(self): else: return "{} -> {}".format(self.val, repr(self.next)) -class Solution: - # @param head, a ListNode - # @return a ListNode +class Solution(object): def deleteDuplicates(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ dummy = ListNode(0) - dummy.next = head - current = dummy - while current.next: - next = current.next - while next.next and next.next.val == next.val: - next = next.next - if current.next is not next: - current.next = next.next + pre, cur = dummy, head + while cur: + if cur.next and cur.next.val == cur.val: + val = cur.val; + while cur and cur.val == val: + cur = cur.next + pre.next = cur else: - current = current.next + pre.next = cur + pre = cur + cur = cur.next return dummy.next if __name__ == "__main__": @@ -43,4 +46,4 @@ def deleteDuplicates(self, head): head.next.next.next, head.next.next.next.next = ListNode(3), ListNode(4) head.next.next.next.next.next, head.next.next.next.next.next.next = ListNode(4), ListNode(5) print Solution().deleteDuplicates(head) - \ No newline at end of file + diff --git a/Python/remove-duplicates-from-sorted-list.py b/Python/remove-duplicates-from-sorted-list.py index 88e0fd370..1eda2ef1c 100644 --- a/Python/remove-duplicates-from-sorted-list.py +++ b/Python/remove-duplicates-from-sorted-list.py @@ -2,39 +2,51 @@ # Space: O(1) # # Given a sorted linked list, delete all duplicates such that each element appear only once. -# +# # For example, # Given 1->1->2, return 1->2. # Given 1->1->2->3->3, return 1->2->3. # # Definition for singly-linked list. -class ListNode: + + +class ListNode(object): def __init__(self, x): self.val = x self.next = None - - def __repr__(self): - if self is None: - return "Nil" - else: - return "{} -> {}".format(self.val, repr(self.next)) - -class Solution: - # @param head, a ListNode - # @return a ListNode + + +class Solution(object): def deleteDuplicates(self, head): - current = head - while current and current.next: - next = current.next - if current.val == next.val: - current.next = current.next.next + """ + :type head: ListNode + :rtype: ListNode + """ + cur = head + while cur: + runner = cur.next + while runner and runner.val == cur.val: + runner = runner.next + cur.next = runner + cur = runner + return head + + def deleteDuplicates2(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if not head: return head + if head.next: + if head.val == head.next.val: + head = self.deleteDuplicates(head.next) else: - current = next + head.next = self.deleteDuplicates(head.next) return head + if __name__ == "__main__": head, head.next, head.next.next = ListNode(1), ListNode(1), ListNode(2) head.next.next.next, head.next.next.next.next = ListNode(3), ListNode(3) print Solution().deleteDuplicates(head) - \ No newline at end of file diff --git a/Python/remove-invalid-parentheses.py b/Python/remove-invalid-parentheses.py new file mode 100644 index 000000000..35504e3ca --- /dev/null +++ b/Python/remove-invalid-parentheses.py @@ -0,0 +1,73 @@ +# Time: O(C(n, c)), try out all possible substrings with the minimum c deletion. +# Space: O(c), the depth is at most c, and it costs n at each depth +# +# Remove the minimum number of invalid parentheses in order to +# make the input string valid. Return all possible results. +# +# Note: The input string may contain letters other than the +# parentheses ( and ). +# +# Examples: +# "()())()" -> ["()()()", "(())()"] +# "(a)())()" -> ["(a)()()", "(a())()"] +# ")(" -> [""] +# + +# DFS solution. +class Solution(object): + def removeInvalidParentheses(self, s): + """ + :type s: str + :rtype: List[str] + """ + # Calculate the minimum left and right parantheses to remove + def findMinRemove(s): + left_removed, right_removed = 0, 0 + for c in s: + if c == '(': + left_removed += 1 + elif c == ')': + if not left_removed: + right_removed += 1 + else: + left_removed -= 1 + return (left_removed, right_removed) + + # Check whether s is valid or not. + def isValid(s): + sum = 0 + for c in s: + if c == '(': + sum += 1 + elif c == ')': + sum -= 1 + if sum < 0: + return False + return sum == 0 + + def removeInvalidParenthesesHelper(start, left_removed, right_removed): + if left_removed == 0 and right_removed == 0: + tmp = "" + for i, c in enumerate(s): + if i not in removed: + tmp += c + if isValid(tmp): + res.append(tmp) + return + + for i in xrange(start, len(s)): + if right_removed == 0 and left_removed > 0 and s[i] == '(': + if i == start or s[i] != s[i - 1]: # Skip duplicated. + removed[i] = True + removeInvalidParenthesesHelper(i + 1, left_removed - 1, right_removed) + del removed[i] + elif right_removed > 0 and s[i] == ')': + if i == start or s[i] != s[i - 1]: # Skip duplicated. + removed[i] = True + removeInvalidParenthesesHelper(i + 1, left_removed, right_removed - 1); + del removed[i] + + res, removed = [], {} + (left_removed, right_removed) = findMinRemove(s) + removeInvalidParenthesesHelper(0, left_removed, right_removed) + return res diff --git a/Python/remove-k-digits.py b/Python/remove-k-digits.py new file mode 100644 index 000000000..ec30523a3 --- /dev/null +++ b/Python/remove-k-digits.py @@ -0,0 +1,40 @@ +# Time: O(n) +# Space: O(n) + +# Given a non-negative integer num represented as a string, +# remove k digits from the number so that the new number is the smallest possible. +# +# Note: +# The length of num is less than 10^5 and will be >= k. +# The given num does not contain any leading zero. +# Example 1: +# +# Input: num = "1432219", k = 3 +# Output: "1219" +# Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest. +# Example 2: +# +# Input: num = "10200", k = 1 +# Output: "200" +# Explanation: Remove the leading 1 and the number is 200. +# Note that the output must not contain leading zeroes. +# Example 3: +# +# Input: num = "10", k = 2 +# Output: "0" +# Explanation: Remove all the digits from the number and it is left with nothing which is 0. + +class Solution(object): + def removeKdigits(self, num, k): + """ + :type num: str + :type k: int + :rtype: str + """ + result = [] + for d in num: + while k and result and result[-1] > d: + result.pop() + k -= 1 + result.append(d) + return ''.join(result).lstrip('0')[:-k or None] or '0' diff --git a/Python/remove-linked-list-elements.py b/Python/remove-linked-list-elements.py new file mode 100644 index 000000000..347370e88 --- /dev/null +++ b/Python/remove-linked-list-elements.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(1) +# +# Remove all elements from a linked list of integers that have value val. +# +# Example +# Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6 +# Return: 1 --> 2 --> 3 --> 4 --> 5 +# +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + # @param {ListNode} head + # @param {integer} val + # @return {ListNode} + def removeElements(self, head, val): + dummy = ListNode(float("-inf")) + dummy.next = head + prev, curr = dummy, dummy.next + + while curr: + if curr.val == val: + prev.next = curr.next + else: + prev = curr + + curr = curr.next + + return dummy.next + + diff --git a/Python/repeated-dna-sequences.py b/Python/repeated-dna-sequences.py new file mode 100644 index 000000000..901af0451 --- /dev/null +++ b/Python/repeated-dna-sequences.py @@ -0,0 +1,50 @@ +# Time: O(n) +# Space: O(n) + +# All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, +# for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA. +# +# Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule. +# +# For example, +# +# Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT", +# +# Return: +# ["AAAAACCCCC", "CCCCCAAAAA"]. + +import collections + +class Solution(object): + def findRepeatedDnaSequences(self, s): + """ + :type s: str + :rtype: List[str] + """ + dict, rolling_hash, res = {}, 0, [] + + for i in xrange(len(s)): + rolling_hash = ((rolling_hash << 3) & 0x3fffffff) | (ord(s[i]) & 7) + if rolling_hash not in dict: + dict[rolling_hash] = True + elif dict[rolling_hash]: + res.append(s[i - 9: i + 1]) + dict[rolling_hash] = False + return res + + def findRepeatedDnaSequences2(self, s): + """ + :type s: str + :rtype: List[str] + """ + l, r = [], [] + if len(s) < 10: return [] + for i in range(len(s) - 9): + l.extend([s[i:i + 10]]) + return [k for k, v in collections.Counter(l).items() if v > 1] + + +if __name__ == "__main__": + print Solution().findRepeatedDnaSequences("AAAAAAAAAA") + print Solution().findRepeatedDnaSequences("") + print Solution().findRepeatedDnaSequences("AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT") diff --git a/Python/repeated-string-match.py b/Python/repeated-string-match.py new file mode 100644 index 000000000..7b17def8c --- /dev/null +++ b/Python/repeated-string-match.py @@ -0,0 +1,53 @@ +# Time: O(n + m) +# Space: O(1) + +# Given two strings A and B, find the minimum number of times A has to be repeated +# such that B is a substring of it. If no such solution, return -1. +# +# For example, with A = "abcd" and B = "cdabcdab". +# +# Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; +# and B is not a substring of A repeated two times ("abcdabcd"). +# +# Note: +# The length of A and B will be between 1 and 10000. + +# Rabin-Karp Algorithm (rolling hash) +class Solution(object): + def repeatedStringMatch(self, A, B): + """ + :type A: str + :type B: str + :rtype: int + """ + def check(index): + return all(A[(i+index) % len(A)] == c + for i, c in enumerate(B)) + + M, p = 10**9+7, 113 + p_inv = pow(p, M-2, M) + q = (len(B)+len(A)-1) // len(A) + + b_hash, power = 0, 1 + for c in B: + b_hash += power * ord(c) + b_hash %= M + power = (power*p) % M + + a_hash, power = 0, 1 + for i in xrange(len(B)): + a_hash += power * ord(A[i%len(A)]) + a_hash %= M + power = (power*p) % M + + if a_hash == b_hash and check(0): return q + + power = (power*p_inv) % M + for i in xrange(len(B), (q+1)*len(A)): + a_hash = (a_hash-ord(A[(i-len(B))%len(A)])) * p_inv + a_hash += power * ord(A[i%len(A)]) + a_hash %= M + if a_hash == b_hash and check(i-len(B)+1): + return q if i < q*len(A) else q+1 + + return -1 diff --git a/Python/repeated-substring-pattern.py b/Python/repeated-substring-pattern.py new file mode 100644 index 000000000..b7925f67b --- /dev/null +++ b/Python/repeated-substring-pattern.py @@ -0,0 +1,59 @@ +# Time: O(n) +# Space: O(n) + +# Given a non-empty string check if it can be constructed by taking a substring of it +# and appending multiple copies of the substring together. +# You may assume the given string consists of lowercase English letters only and its length will not exceed 10000. +# +# Example 1: +# Input: "abab" +# +# Output: True +# +# Explanation: It's the substring "ab" twice. +# Example 2: +# Input: "aba" +# +# Output: False +# Example 3: +# Input: "abcabcabcabc" +# +# Output: True +# +# Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.) + +# KMP solution. + + +class Solution(object): + def repeatedSubstringPattern(self, str): + """ + :type str: str + :rtype: bool + """ + def getPrefix(pattern): + prefix = [-1] * len(pattern) + j = -1 + for i in xrange(1, len(pattern)): + while j > -1 and pattern[j + 1] != pattern[i]: + j = prefix[j] + if pattern[j + 1] == pattern[i]: + j += 1 + prefix[i] = j + return prefix + + prefix = getPrefix(str) + return prefix[-1] != -1 and \ + (prefix[-1] + 1) % (len(str) - prefix[-1] - 1) == 0 + + def repeatedSubstringPattern2(self, str): + """ + :type str: str + :rtype: bool + """ + if not str: + return False + + ss = (str + str)[1:-1] + print ss + return ss.find(str) != -1 diff --git a/Python/replace-words.py b/Python/replace-words.py new file mode 100644 index 000000000..8ed8c2513 --- /dev/null +++ b/Python/replace-words.py @@ -0,0 +1,47 @@ +# Time: O(n) +# Space: O(t), t is the number of nodes in trie + +# In English, we have a concept called root, which can be followed by +# some other words to form another longer word - let's call this word successor. +# For example, the root an, followed by other, which can form another word another. +# +# Now, given a dictionary consisting of many roots and a sentence. +# You need to replace all the successor in the sentence with the root forming it. +# If a successor has many roots can form it, replace it with the root with the shortest length. +# +# You need to output the sentence after the replacement. +# +# Example 1: +# Input: dict = ["cat", "bat", "rat"] +# sentence = "the cattle was rattled by the battery" +# Output: "the cat was rat by the bat" +# Note: +# The input will only have lower-case letters. +# 1 <= dict words number <= 1000 +# 1 <= sentence words number <= 1000 +# 1 <= root length <= 100 +# 1 <= sentence words length <= 1000 + +class Solution(object): + def replaceWords(self, dictionary, sentence): + """ + :type dictionary: List[str] + :type sentence: str + :rtype: str + """ + _trie = lambda: collections.defaultdict(_trie) + trie = _trie() + for word in dictionary: + reduce(dict.__getitem__, word, trie).setdefault("_end") + + def replace(word): + curr = trie + for i, c in enumerate(word): + if c not in curr: + break + curr = curr[c] + if "_end" in curr: + return word[:i+1] + return word + + return " ".join(map(replace, sentence.split())) diff --git a/Python/reshape-the-matrix.py b/Python/reshape-the-matrix.py new file mode 100644 index 000000000..acbe6bdb2 --- /dev/null +++ b/Python/reshape-the-matrix.py @@ -0,0 +1,63 @@ +# Time: O(m * n) +# Space: O(m * n) + +# In MATLAB, there is a very useful function called 'reshape', +# which can reshape a matrix into a new one with different size but keep its original data. +# +# You're given a matrix represented by a two-dimensional array, +# and two positive integers r and c representing the row number +# and column number of the wanted reshaped matrix, respectively. +# +# The reshaped matrix need to be filled with +# all the elements of the original matrix in the same row-traversing order as they were. +# +# If the 'reshape' operation with given parameters is possible and legal, +# output the new reshaped matrix; Otherwise, output the original matrix. +# +# Example 1: +# Input: +# nums = +# [[1,2], +# [3,4]] +# r = 1, c = 4 +# Output: +# [[1,2,3,4]] +# Explanation: +# The row-traversing of nums is [1,2,3,4]. The new reshaped matrix is a 1 * 4 matrix, +# fill it row by row by using the previous list. +# +# Example 2: +# Input: +# nums = +# [[1,2], +# [3,4]] +# r = 2, c = 4 +# Output: +# [[1,2], +# [3,4]] +# Explanation: +# There is no way to reshape a 2 * 2 matrix to a 2 * 4 matrix. So output the original matrix. +# +# Note: +# The height and width of the given matrix is in range [1, 100]. +# The given r and c are all positive. + +class Solution(object): + def matrixReshape(self, nums, r, c): + """ + :type nums: List[List[int]] + :type r: int + :type c: int + :rtype: List[List[int]] + """ + if not nums or \ + r*c != len(nums) * len(nums[0]): + return nums + + result = [[0 for _ in xrange(c)] for _ in xrange(r)] + count = 0 + for i in xrange(len(nums)): + for j in xrange(len(nums[0])): + result[count/c][count%c] = nums[i][j] + count += 1 + return result diff --git a/Python/restore-ip-addresses.py b/Python/restore-ip-addresses.py index 63e6b9a71..504ce6c6c 100644 --- a/Python/restore-ip-addresses.py +++ b/Python/restore-ip-addresses.py @@ -32,7 +32,7 @@ def restoreIpAddressesRecur(self, result, s, start, current, dots): current = current[:-(i - start + 2)] def isValid(self, s): - if len(s) == 0 or (s[0] == "0" and s != "0"): + if len(s) == 0 or (s[0] == '0' and s != "0"): return False return int(s) < 256 diff --git a/Python/reverse-bits.py b/Python/reverse-bits.py new file mode 100644 index 000000000..636684e0e --- /dev/null +++ b/Python/reverse-bits.py @@ -0,0 +1,34 @@ +# Time : O(logn) = O(32) +# Space: O(1) +# +# Reverse bits of a given 32 bits unsigned integer. +# +# For example, given input 43261596 (represented in binary as +# 00000010100101000001111010011100), return 964176192 (represented in binary +# as 00111001011110000010100101000000). +# +# Follow up: +# If this function is called many times, how would you optimize it? +# + +class Solution: + # @param n, an integer + # @return an integer + def reverseBits(self, n): + result = 0 + for i in xrange(32): + result <<= 1 + result |= n & 1 + n >>= 1 + return result + + def reverseBits2(self, n): + string = bin(n) + if '-' in string: + string = string[:3] + string[3:].zfill(32)[::-1] + else: + string = string[:2] + string[2:].zfill(32)[::-1] + return int(string, 2) + +if __name__ == '__main__': + print Solution().reverseBits(1) diff --git a/Python/reverse-integer.py b/Python/reverse-integer.py index 69692d017..014a66fee 100644 --- a/Python/reverse-integer.py +++ b/Python/reverse-integer.py @@ -1,4 +1,4 @@ -# Time: O(logn) +# Time: O(logn) = O(1) # Space: O(1) # # Reverse digits of an integer. @@ -18,20 +18,45 @@ # # Throw an exception? Good, but what if throwing an exception is not an option? # You would then have to re-design the function (ie, add an extra parameter). -# -class Solution: - # @return an integer + +class Solution(object): def reverse(self, x): - ans = 0 - if x >= 0: - while x: - ans = ans * 10 + x % 10 - x /= 10 - return ans - else: + """ + :type x: int + :rtype: int + """ + if x < 0: return -self.reverse(-x) - + + result = 0 + while x: + result = result * 10 + x % 10 + x /= 10 + return result if result <= 0x7fffffff else 0 # Handle overflow. + + def reverse2(self, x): + """ + :type x: int + :rtype: int + """ + if x < 0: + x = int(str(x)[::-1][-1] + str(x)[::-1][:-1]) + else: + x = int(str(x)[::-1]) + x = 0 if abs(x) > 0x7FFFFFFF else x + return x + + def reverse3(self, x): + """ + :type x: int + :rtype: int + """ + s = cmp(x, 0) + r = int(`s * x`[::-1]) + return s * r * (r < 2 ** 31) + + if __name__ == "__main__": print Solution().reverse(123) - print Solution().reverse(-321) \ No newline at end of file + print Solution().reverse(-321) diff --git a/Python/reverse-linked-list.py b/Python/reverse-linked-list.py new file mode 100644 index 000000000..8e8441ddc --- /dev/null +++ b/Python/reverse-linked-list.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(1) +# +# Reverse a singly linked list. +# +# click to show more hints. +# +# Hint: +# A linked list can be reversed either iteratively or recursively. Could you implement both? +# + +# Definition for singly-linked list. +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + def __repr__(self): + if self: + return "{} -> {}".format(self.val, repr(self.next)) + +# Iterative solution. +class Solution: + # @param {ListNode} head + # @return {ListNode} + def reverseList(self, head): + dummy = ListNode(float("-inf")) + while head: + dummy.next, head.next, head = head, dummy.next, head.next + return dummy.next + +# Time: O(n) +# Space: O(n) +# Recursive solution. +class Solution2: + # @param {ListNode} head + # @return {ListNode} + def reverseList(self, head): + [begin, end] = self.reverseListRecu(head) + return begin + + def reverseListRecu(self, head): + if not head: + return [None, None] + + [begin, end] = self.reverseListRecu(head.next) + + if end: + end.next = head + head.next = None + return [begin, head] + else: + return [head, head] + +if __name__ == "__main__": + head = ListNode(1) + head.next = ListNode(2) + head.next.next = ListNode(3) + head.next.next.next = ListNode(4) + head.next.next.next.next = ListNode(5) + print Solution2().reverseList(head) \ No newline at end of file diff --git a/Python/reverse-pairs.py b/Python/reverse-pairs.py new file mode 100644 index 000000000..17a430162 --- /dev/null +++ b/Python/reverse-pairs.py @@ -0,0 +1,53 @@ +# Time: O(nlogn) +# Space: O(n) + +# Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j]. +# +# You need to return the number of important reverse pairs in the given array. +# +# Example1: +# +# Input: [1,3,2,3,1] +# Output: 2 +# Example2: +# +# Input: [2,4,3,5,1] +# Output: 3 +# Note: +# The length of the given array will not exceed 50,000. +# All the numbers in the input array are in the range of 32-bit integer. +# Show Company Tags +# Show Tags +# Hide Similar Problems + +class Solution(object): + def reversePairs(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + def merge(nums, start, mid, end): + r = mid + 1 + tmp = [] + for i in xrange(start, mid + 1): + while r <= end and nums[i] > nums[r]: + tmp.append(nums[r]) + r += 1 + tmp.append(nums[i]) + nums[start:start+len(tmp)] = tmp + + def countAndMergeSort(nums, start, end): + if end - start <= 0: + return 0 + + mid = start + (end - start) / 2 + count = countAndMergeSort(nums, start, mid) + countAndMergeSort(nums, mid + 1, end) + r = mid + 1 + for i in xrange(start, mid + 1): + while r <= end and nums[i] > nums[r] * 2: + r += 1 + count += r - (mid + 1) + merge(nums, start, mid, end) + return count + + return countAndMergeSort(nums, 0, len(nums) - 1) diff --git a/Python/reverse-string-ii.py b/Python/reverse-string-ii.py new file mode 100644 index 000000000..e9958cae9 --- /dev/null +++ b/Python/reverse-string-ii.py @@ -0,0 +1,26 @@ +# Time: O(n) +# Space: O(1) + +# Given a string and an integer k, you need to reverse the first k characters +# for every 2k characters counting from the start of the string. +# If there are less than k characters left, reverse all of them. +# If there are less than 2k but greater than or equal to k characters, +# then reverse the first k characters and left the other as original. +# Example: +# Input: s = "abcdefg", k = 2 +# Output: "bacdfeg" +# Restrictions: +# The string consists of lower English letters only. +# Length of the given string and k will in the range [1, 10000] + +class Solution(object): + def reverseStr(self, s, k): + """ + :type s: str + :type k: int + :rtype: str + """ + s = list(s) + for i in xrange(0, len(s), 2*k): + s[i:i+k] = reversed(s[i:i+k]) + return "".join(s) diff --git a/Python/reverse-string.py b/Python/reverse-string.py new file mode 100644 index 000000000..be5e9ce83 --- /dev/null +++ b/Python/reverse-string.py @@ -0,0 +1,33 @@ +# Time: O(n) +# Space: O(n) + +# Write a function that takes a string as input and +# returns the string reversed. +# +# Example: +# Given s = "hello", return "olleh". + +class Solution(object): + def reverseString(self, s): + """ + :type s: str + :rtype: str + """ + string = list(s) + i, j = 0, len(string) - 1 + while i < j: + string[i], string[j] = string[j], string[i] + i += 1 + j -= 1 + return "".join(string) + + +# Time: O(n) +# Space: O(n) +class Solution2(object): + def reverseString(self, s): + """ + :type s: str + :rtype: str + """ + return s[::-1] diff --git a/Python/reverse-vowels-of-a-string.py b/Python/reverse-vowels-of-a-string.py new file mode 100644 index 000000000..f7eb88ae2 --- /dev/null +++ b/Python/reverse-vowels-of-a-string.py @@ -0,0 +1,31 @@ +# Time: O(n) +# Space: O(1) + +# Write a function that takes a string as input +# and reverse only the vowels of a string. +# +# Example 1: +# Given s = "hello", return "holle". +# +# Example 2: +# Given s = "leetcode", return "leotcede". + +class Solution(object): + def reverseVowels(self, s): + """ + :type s: str + :rtype: str + """ + vowels = "aeiou" + string = list(s) + i, j = 0, len(s) - 1 + while i < j: + if string[i].lower() not in vowels: + i += 1 + elif string[j].lower() not in vowels: + j -= 1 + else: + string[i], string[j] = string[j], string[i] + i += 1 + j -= 1 + return "".join(string) diff --git a/Python/reverse-words-in-a-string-ii.py b/Python/reverse-words-in-a-string-ii.py new file mode 100644 index 000000000..6656ae327 --- /dev/null +++ b/Python/reverse-words-in-a-string-ii.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space:O(1) +# +# Given an input string, reverse the string word by word. +# A word is defined as a sequence of non-space characters. +# +# The input string does not contain leading or trailing spaces +# and the words are always separated by a single space. +# +# For example, +# Given s = "the sky is blue", +# return "blue is sky the". +# +# Could you do it in-place without allocating extra space? +# + +class Solution(object): + def reverseWords(self, s): + """ + :type s: a list of 1 length strings (List[str]) + :rtype: nothing + """ + def reverse(s, begin, end): + for i in xrange((end - begin) / 2): + s[begin + i], s[end - 1 - i] = s[end - 1 - i], s[begin + i] + + reverse(s, 0, len(s)) + i = 0 + for j in xrange(len(s) + 1): + if j == len(s) or s[j] == ' ': + reverse(s, i, j) + i = j + 1 + + +if __name__ == '__main__': + s = ['h','e','l','l','o', ' ', 'w', 'o', 'r', 'l', 'd'] + Solution().reverseWords(s) + print s diff --git a/Python/reverse-words-in-a-string-iii.py b/Python/reverse-words-in-a-string-iii.py new file mode 100644 index 000000000..31947e6ae --- /dev/null +++ b/Python/reverse-words-in-a-string-iii.py @@ -0,0 +1,28 @@ +# Time: O(n) +# Space: O(1) + +# Given a string, you need to reverse the order of characters in each word within a sentence +# while still preserving whitespace and initial word order. +# +# Example 1: +# Input: "Let's take LeetCode contest" +# Output: "s'teL ekat edoCteeL tsetnoc" +# Note: In the string, each word is separated by single space and +# there will not be any extra space in the string. + +class Solution(object): + def reverseWords(self, s): + """ + :type s: str + :rtype: str + """ + def reverse(s, begin, end): + for i in xrange((end - begin) // 2): + s[begin + i], s[end - 1 - i] = s[end - 1 - i], s[begin + i] + + s, i = list(s), 0 + for j in xrange(len(s) + 1): + if j == len(s) or s[j] == ' ': + reverse(s, i, j) + i = j + 1 + return "".join(s) diff --git a/Python/rotate-array.py b/Python/rotate-array.py new file mode 100644 index 000000000..1139d6a33 --- /dev/null +++ b/Python/rotate-array.py @@ -0,0 +1,90 @@ +# Time: O(n) +# Space: O(1) +# +# Rotate an array of n elements to the right by k steps. +# +# For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. +# +# Note: +# Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem. +# + +class Solution: + """ + :type nums: List[int] + :type k: int + :rtype: void Do not return anything, modify nums in-place instead. + """ + + def rotate(self, nums, k): + k %= len(nums) + self.reverse(nums, 0, len(nums)) + self.reverse(nums, 0, k) + self.reverse(nums, k, len(nums)) + + def reverse(self, nums, start, end): + while start < end: + nums[start], nums[end - 1] = nums[end - 1], nums[start] + start += 1 + end -= 1 + + def rotate2(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: void Do not return anything, modify nums in-place instead. + """ + nums[:] = nums[len(nums) - k:] + nums[:len(nums) - k] + + +from fractions import gcd + + +class Solution2: + """ + :type nums: List[int] + :type k: int + :rtype: void Do not return anything, modify nums in-place instead. + """ + + def rotate(self, nums, k): + k %= len(nums) + num_cycles = gcd(len(nums), k) + cycle_len = len(nums) / num_cycles + for i in xrange(num_cycles): + self.apply_cycle_permutation(k, i, cycle_len, nums) + + def apply_cycle_permutation(self, k, offset, cycle_len, nums): + tmp = nums[offset] + for i in xrange(1, cycle_len): + nums[(offset + i * k) % len(nums)], tmp = tmp, nums[(offset + i * k) % len(nums)] + nums[offset] = tmp + + +class Solution3: + """ + :type nums: List[int] + :type k: int + :rtype: void Do not return anything, modify nums in-place instead. + """ + + def rotate(self, nums, k): + count = 0 + start = 0 + while count < len(nums): + curr = start + prev = nums[curr] + while True: + idx = (curr + k) % len(nums) + nums[idx], prev = prev, nums[idx] + curr = idx + count += 1 + if start == curr: + break + start += 1 + + +if __name__ == '__main__': + nums = [1, 2, 3, 4, 5, 6, 7] + Solution().rotate(nums, 3) + print nums diff --git a/Python/rotate-function.py b/Python/rotate-function.py new file mode 100644 index 000000000..654d6aa9d --- /dev/null +++ b/Python/rotate-function.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of integers A and let n to be its length. +# +# Assume Bk to be an array obtained by rotating the array A +# k positions clock-wise, we define a "rotation function" F on A as follow: +# +# F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1]. +# +# Calculate the maximum value of F(0), F(1), ..., F(n-1). +# +# Note: +# n is guaranteed to be less than 105. +# +# Example: +# +# A = [4, 3, 2, 6] +# +# F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25 +# F(1) = (0 * 6) + (1 * 4) + (2 * 3) + (3 * 2) = 0 + 4 + 6 + 6 = 16 +# F(2) = (0 * 2) + (1 * 6) + (2 * 4) + (3 * 3) = 0 + 6 + 8 + 9 = 23 +# F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26 +# +# So the maximum value of F(0), F(1), F(2), F(3) is F(3) = 26. + +class Solution(object): + def maxRotateFunction(self, A): + """ + :type A: List[int] + :rtype: int + """ + s = sum(A) + fi = 0 + for i in xrange(len(A)): + fi += i * A[i] + + result = fi + for i in xrange(1, len(A)+1): + fi += s - len(A) * A[-i] + result = max(result, fi) + return result diff --git a/Python/rotate-image.py b/Python/rotate-image.py index c434dffa5..dabc2734f 100644 --- a/Python/rotate-image.py +++ b/Python/rotate-image.py @@ -20,12 +20,12 @@ def rotate(self, matrix): # anti-diagonal mirror for i in xrange(n): for j in xrange(n - i): - matrix[i][j], matrix[n - 1 - j][n - 1 -i] = matrix[n - 1 - j][n - 1 -i], matrix[i][j] + matrix[i][j], matrix[n-1-j][n-1-i] = matrix[n-1-j][n-1-i], matrix[i][j] # horizontal mirror for i in xrange(n / 2): for j in xrange(n): - matrix[i][j], matrix[n - 1 - i][j] = matrix[n - 1 - i][j], matrix[i][j] + matrix[i][j], matrix[n-1-i][j] = matrix[n-1-i][j], matrix[i][j] return matrix diff --git a/Python/rotate-list.py b/Python/rotate-list.py index 7d33a6c84..6a536da17 100644 --- a/Python/rotate-list.py +++ b/Python/rotate-list.py @@ -18,30 +18,30 @@ def __repr__(self): if self: return "{} -> {}".format(self.val, repr(self.next)) -class Solution: - # @param head, a ListNode - # @param k, an integer - # @return a ListNode +class Solution(object): def rotateRight(self, head, k): - if head is None: + """ + :type head: ListNode + :type k: int + :rtype: ListNode + """ + if not head or not head.next: return head - - cur, len = head, 1 + + n, cur = 1, head while cur.next: cur = cur.next - len += 1 + n += 1 cur.next = head - - cur = head - shift = len - k % len - 1 - while shift > 0: + + cur, tail = head, cur + for _ in xrange(n - k % n): + tail = cur cur = cur.next - shift -= 1 - - result = cur.next - cur.next = None - - return result + tail.next = None + + return cur + if __name__ == "__main__": head = ListNode(1) @@ -49,4 +49,4 @@ def rotateRight(self, head, k): head.next.next = ListNode(3) head.next.next.next = ListNode(4) head.next.next.next.next = ListNode(5) - print Solution().rotateRight(head, 2) \ No newline at end of file + print Solution().rotateRight(head, 2) diff --git a/Python/russian-doll-envelopes.py b/Python/russian-doll-envelopes.py new file mode 100644 index 000000000..2f695b9c4 --- /dev/null +++ b/Python/russian-doll-envelopes.py @@ -0,0 +1,42 @@ +# Time: O(nlogn + nlogk) = O(nlogn), k is the length of the result. +# Space: O(1) + +# You have a number of envelopes with widths and heights given +# as a pair of integers (w, h). 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. +# +# What is the maximum number of envelopes can you Russian doll? +# (put one inside other) +# +# Example: +# Given envelopes = [[5,4],[6,4],[6,7],[2,3]], the maximum number +# of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]). + +class Solution(object): + def maxEnvelopes(self, envelopes): + """ + :type envelopes: List[List[int]] + :rtype: int + """ + def insert(target): + left, right = 0, len(result) - 1 + while left <= right: + mid = left + (right - left) / 2 + if result[mid] >= target: + right = mid - 1 + else: + left = mid + 1 + if left == len(result): + result.append(target) + else: + result[left] = target + + result = [] + + envelopes.sort(lambda x, y: y[1] - x[1] if x[0] == y[0] else \ + x[0] - y[0]) + for envelope in envelopes: + insert(envelope[1]) + + return len(result) diff --git a/Python/same-tree.py b/Python/same-tree.py index b73333130..c7e799c94 100644 --- a/Python/same-tree.py +++ b/Python/same-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given two binary trees, write a function to check if they are equal or not. # @@ -29,4 +29,4 @@ def isSameTree(self, p, q): if __name__ == "__main__": root1, root1.left, root1.right = TreeNode(1), TreeNode(2), TreeNode(3) root2, root2.left, root2.right = TreeNode(1), TreeNode(2), TreeNode(3) - print Solution().isSameTree(root1, root2) \ No newline at end of file + print Solution().isSameTree(root1, root2) diff --git a/Python/scramble-string.py b/Python/scramble-string.py index f75325daf..7969954b0 100644 --- a/Python/scramble-string.py +++ b/Python/scramble-string.py @@ -47,7 +47,7 @@ class Solution: def isScramble(self, s1, s2): if not s1 or not s2 or len(s1) != len(s2): return False - if len(s1) == 0: + if s1 == s2: return True result = [[[False for j in xrange(len(s2))] for i in xrange(len(s1))] for n in xrange(len(s1) + 1)] for i in xrange(len(s1)): @@ -67,4 +67,4 @@ def isScramble(self, s1, s2): return result[n][0][0] if __name__ == "__main__": - print Solution().isScramble("rgtae", "great") \ No newline at end of file + print Solution().isScramble("rgtae", "great") diff --git a/Python/search-a-2d-matrix-ii.py b/Python/search-a-2d-matrix-ii.py new file mode 100644 index 000000000..520f7030a --- /dev/null +++ b/Python/search-a-2d-matrix-ii.py @@ -0,0 +1,47 @@ +# Time: O(m + n) +# Space: O(1) +# +# Write an efficient algorithm that searches for a value in an m x n matrix. +# This matrix has the following properties: +# +# Integers in each row are sorted in ascending from left to right. +# Integers in each column are sorted in ascending from top to bottom. +# For example, +# +# Consider the following matrix: +# +# [ +# [1, 4, 7, 11, 15], +# [2, 5, 8, 12, 19], +# [3, 6, 9, 16, 22], +# [10, 13, 14, 17, 24], +# [18, 21, 23, 26, 30] +# ] +# Given target = 5, return true. +# +# Given target = 20, return false. +# + +class Solution: + # @param {integer[][]} matrix + # @param {integer} target + # @return {boolean} + def searchMatrix(self, matrix, target): + m = len(matrix) + if m == 0: + return False + + n = len(matrix[0]) + if n == 0: + return False + + count, i, j = 0, 0, n - 1 + while i < m and j >= 0: + if matrix[i][j] == target: + return True + elif matrix[i][j] > target: + j -= 1 + else: + i += 1 + + return False diff --git a/Python/search-a-2d-matrix.py b/Python/search-a-2d-matrix.py index 712bc4dc1..cc0e67e95 100644 --- a/Python/search-a-2d-matrix.py +++ b/Python/search-a-2d-matrix.py @@ -17,26 +17,28 @@ # Given target = 3, return true. # -class Solution: - # @param matrix, a list of lists of integers - # @param target, an integer - # @return a boolean +class Solution(object): def searchMatrix(self, matrix, target): - m = len(matrix) - n = len(matrix[0]) - i, j = 0, m * n + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + if not matrix: + return False - while i < j: - mid = i + (j - i) / 2 - val = matrix[mid / n][mid % n] - if val == target: - return True - elif val < target: - i = mid + 1 + m, n = len(matrix), len(matrix[0]) + left, right = 0, m * n + while left < right: + mid = left + (right - left) / 2 + if matrix[mid / n][mid % n] >= target: + right = mid else: - j = mid - return False + left = mid + 1 + + return left < m * n and matrix[left / n][left % n] == target + if __name__ == "__main__": matrix = [[1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50]] - print Solution().searchMatrix(matrix, 3) \ No newline at end of file + print Solution().searchMatrix(matrix, 3) diff --git a/Python/search-for-a-range.py b/Python/search-for-a-range.py index 505961eed..74bf58ac7 100644 --- a/Python/search-for-a-range.py +++ b/Python/search-for-a-range.py @@ -12,27 +12,52 @@ # return [3, 4]. # -class Solution: - # @param A, a list of integers - # @param target, an integer to be searched - # @return a list of length 2, [index1, index2] - def searchRange(self, A, target): - left = self.binarySearch(lambda x, y: x > y, A, target) - if left >= len(A) or A[left] != target: +class Solution(object): + def searchRange(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + # Find the first idx where nums[idx] >= target + left = self.binarySearch(lambda x, y: x >= y, nums, target) + if left >= len(nums) or nums[left] != target: return [-1, -1] - right = self.binarySearch(lambda x, y: x >= y, A, target) + # Find the first idx where nums[idx] > target + right = self.binarySearch(lambda x, y: x > y, nums, target) return [left, right - 1] - def binarySearch(self, compare, A, target): - start, end = 0, len(A) - while start < end: - mid = start + (end - start) / 2 - if compare(target, A[mid]): - start = mid + 1 + def binarySearch(self, compare, nums, target): + left, right = 0, len(nums) + while left < right: + mid = left + (right - left) / 2 + if compare(nums[mid], target): + right = mid else: - end = mid - return start + left = mid + 1 + return left + + def binarySearch2(self, compare, nums, target): + left, right = 0, len(nums) - 1 + while left <= right: + mid = left + (right - left) / 2 + if compare(nums[mid], target): + right = mid - 1 + else: + left = mid + 1 + return left + + def binarySearch3(self, compare, nums, target): + left, right = -1, len(nums) + while left + 1 < right: + mid = left + (right - left) / 2 + if compare(nums[mid], target): + right = mid + else: + left = mid + return left if left != -1 and compare(nums[left], target) else right + if __name__ == "__main__": print Solution().searchRange([2, 2], 3) - print Solution().searchRange([5, 7, 7, 8, 8, 10], 8) \ No newline at end of file + print Solution().searchRange([5, 7, 7, 8, 8, 10], 8) diff --git a/Python/search-in-rotated-sorted-array-ii.py b/Python/search-in-rotated-sorted-array-ii.py index cd623c3c9..8649ec528 100644 --- a/Python/search-in-rotated-sorted-array-ii.py +++ b/Python/search-in-rotated-sorted-array-ii.py @@ -9,36 +9,32 @@ # Write a function to determine if a given target is in the array. # -class Solution: - # @param A a list of integers - # @param target an integer - # @return a boolean - def search(self, A, target): - low, high = 0, len(A) +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left, right = 0, len(nums) - 1 - while low < high: - mid = low + (high - low) / 2 + while left <= right: + mid = left + (right - left) / 2 - if A[mid] == target: + if nums[mid] == target: return True - - if A[low] < A[mid]: - if A[low] <= target and target < A[mid]: - high = mid - else: - low = mid + 1 - elif A[low] > A[mid]: - if A[mid] < target and target <= A[high - 1]: - low = mid + 1 - else: - high = mid + elif nums[mid] == nums[left]: + left += 1 + elif (nums[mid] > nums[left] and nums[left] <= target < nums[mid]) or \ + (nums[mid] < nums[left] and not (nums[mid] < target <= nums[right])): + right = mid - 1 else: - low += 1 - + left = mid + 1 + return False if __name__ == "__main__": print Solution().search([3, 5, 1], 3) print Solution().search([2, 2, 3, 3, 4, 1], 1) - print Solution().search([4, 4, 5, 6, 7, 0, 1, 2], 5) \ No newline at end of file + print Solution().search([4, 4, 5, 6, 7, 0, 1, 2], 5) diff --git a/Python/search-in-rotated-sorted-array.py b/Python/search-in-rotated-sorted-array.py index fc35c8073..d95d92382 100644 --- a/Python/search-in-rotated-sorted-array.py +++ b/Python/search-in-rotated-sorted-array.py @@ -10,34 +10,30 @@ # You may assume no duplicate exists in the array. # -class Solution: - # @param A, a list of integers - # @param target, an integer to be searched - # @return an integer - def search(self, A, target): - low, high = 0, len(A) +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left, right = 0, len(nums) - 1 - while low < high: - mid = low + (high - low) / 2 + while left <= right: + mid = left + (right - left) / 2 - if A[mid] == target: + if nums[mid] == target: return mid - - if A[low] <= A[mid]: - if A[low] <= target and target < A[mid]: - high = mid - else: - low = mid + 1 + elif (nums[mid] >= nums[left] and nums[left] <= target < nums[mid]) or \ + (nums[mid] < nums[left] and not (nums[mid] < target <= nums[right])): + right = mid - 1 else: - if A[mid] < target and target <= A[high - 1]: - low = mid + 1 - else: - high = mid - + left = mid + 1 + return -1 if __name__ == "__main__": print Solution().search([3, 5, 1], 3) print Solution().search([1], 1) - print Solution().search([4, 5, 6, 7, 0, 1, 2], 5) \ No newline at end of file + print Solution().search([4, 5, 6, 7, 0, 1, 2], 5) diff --git a/Python/search-insert-position.py b/Python/search-insert-position.py index be71509c7..a5be023ed 100644 --- a/Python/search-insert-position.py +++ b/Python/search-insert-position.py @@ -14,26 +14,26 @@ # [1,3,5,6], 0 -> 0 # -class Solution: - # @param A, a list of integers - # @param target, an integer to be inserted - # @return integer - def searchInsert(self, A, target): - low, high = 0, len(A) - 1 - - while low <= high: - mid = low + (high - low) / 2 - if A[mid] == target: - return mid - elif A[mid] < target: - low = mid + 1 +class Solution(object): + def searchInsert(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left, right = 0, len(nums) - 1 + while left <= right: + mid = left + (right - left) / 2 + if nums[mid] >= target: + right = mid - 1 else: - high = mid - 1 - - return low + left = mid + 1 + + return left + if __name__ == "__main__": print Solution().searchInsert([1, 3, 5, 6], 5) print Solution().searchInsert([1, 3, 5, 6], 2) print Solution().searchInsert([1, 3, 5, 6], 7) - print Solution().searchInsert([1, 3, 5, 6], 0) \ No newline at end of file + print Solution().searchInsert([1, 3, 5, 6], 0) diff --git a/Python/second-minimum-node-in-a-binary-tree.py b/Python/second-minimum-node-in-a-binary-tree.py new file mode 100644 index 000000000..ac2b21761 --- /dev/null +++ b/Python/second-minimum-node-in-a-binary-tree.py @@ -0,0 +1,60 @@ +# Time: O(n) +# Space: O(h) + +# Given a non-empty special binary tree consisting of nodes with the non-negative value, +# where each node in this tree has exactly two or zero sub-node. If the node has two sub-nodes, +# then this node's value is the smaller value among its two sub-nodes. +# +# Given such a binary tree, you need to output the second minimum value in the set made of +# all the nodes' value in the whole tree. +# +# If no such second minimum value exists, output -1 instead. +# +# Example 1: +# Input: +# 2 +# / \ +# 2 5 +# / \ +# 5 7 +# +# Output: 5 +# Explanation: The smallest value is 2, the second smallest value is 5. +# Example 2: +# Input: +# 2 +# / \ +# 2 2 +# +# Output: -1 +# Explanation: The smallest value is 2, but there isn't any second smallest value. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findSecondMinimumValue(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def findSecondMinimumValueHelper(root, max_heap, lookup): + if not root: + return + if root.val not in lookup: + heapq.heappush(max_heap, -root.val) + lookup.add(root.val) + if len(max_heap) > 2: + lookup.remove(-heapq.heappop(max_heap)) + findSecondMinimumValueHelper(root.left, max_heap, lookup) + findSecondMinimumValueHelper(root.right, max_heap, lookup) + + max_heap, lookup = [], set() + findSecondMinimumValueHelper(root, max_heap, lookup) + if len(max_heap) < 2: + return -1 + return -max_heap[0] diff --git a/Python/self-crossing.py b/Python/self-crossing.py new file mode 100644 index 000000000..cdb4439ab --- /dev/null +++ b/Python/self-crossing.py @@ -0,0 +1,70 @@ +# Time: O(n) +# Space: O(1) + +# You are given an array x of n positive numbers. +# You start at point (0,0) and moves x[0] metres to the north, +# then x[1] metres to the west, x[2] metres to the south, +# x[3] metres to the east and so on. In other words, +# after each move your direction changes counter-clockwise. +# +# Write a one-pass algorithm with O(1) extra space to determine, +# if your path crosses itself, or not. +# +# Example 1: +# Given x = [2, 1, 1, 2], +# ┌───┐ +# │ │ +# └───┼──> +# │ +# +# Return true (self crossing) +# Example 2: +# Given x = [1, 2, 3, 4], +# ┌──────┐ +# │ │ +# │ +# │ +# └────────────> +# +# Return false (not self crossing) +# Example 3: +# Given x = [1, 1, 1, 1], +# ┌───┐ +# │ │ +# └───┼> +# +# Return true (self crossing) + +class Solution(object): + def isSelfCrossing(self, x): + """ + :type x: List[int] + :rtype: bool + """ + if len(x) >= 5 and x[3] == x[1] and x[4] + x[0] >= x[2]: + # Crossing in a loop: + # 2 + # 3 ┌────┐ + # └─══>┘1 + # 4 0 (overlapped) + return True + + for i in xrange(3, len(x)): + if x[i] >= x[i - 2] and x[i - 3] >= x[i - 1]: + # Case 1: + # i-2 + # i-1┌─┐ + # └─┼─>i + # i-3 + return True + elif i >= 5 and x[i - 4] <= x[i - 2] and x[i] + x[i - 4] >= x[i - 2] and \ + x[i - 1] <= x[i - 3] and x[i - 5] + x[i - 1] >= x[i - 3]: + # Case 2: + # i-4 + # ┌──┐ + # │i<┼─┐ + # i-3│ i-5│i-1 + # └────┘ + # i-2 + return True + return False diff --git a/Python/self-dividing-numbers.py b/Python/self-dividing-numbers.py new file mode 100644 index 000000000..84050e5a8 --- /dev/null +++ b/Python/self-dividing-numbers.py @@ -0,0 +1,41 @@ +# Time: O(nlogr) = O(n) +# Space: O(logr) = O(1) + +# A self-dividing number is a number that is divisible by every digit it contains. +# +# For example, 128 is a self-dividing number because 128 % 1 == 0, +# 128 % 2 == 0, and 128 % 8 == 0. +# +# Also, a self-dividing number is not allowed to contain the digit zero. +# +# Given a lower and upper number bound, output a list of every possible self dividing number, +# including the bounds if possible. +# +# Example 1: +# Input: +# left = 1, right = 22 +# Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22] +# +# Note: +# - The boundaries of each input argument are 1 <= left <= right <= 10000. + +class Solution(object): + def selfDividingNumbers(self, left, right): + """ + :type left: int + :type right: int + :rtype: List[int] + """ + def isDividingNumber(num): + n = num + while n > 0: + if (n%10) == 0 or (num%(n%10)) != 0: + return False + n /= 10 + return True + + result = [] + for num in xrange(left, right+1): + if isDividingNumber(num): + result.append(num) + return result diff --git a/Python/sentence-screen-fitting.py b/Python/sentence-screen-fitting.py new file mode 100644 index 000000000..91f45ca0c --- /dev/null +++ b/Python/sentence-screen-fitting.py @@ -0,0 +1,32 @@ +# Time: O(r + n * c) +# Space: O(n) + +class Solution(object): + def wordsTyping(self, sentence, rows, cols): + """ + :type sentence: List[str] + :type rows: int + :type cols: int + :rtype: int + """ + def words_fit(sentence, start, cols): + if len(sentence[start]) > cols: + return 0 + + s, count = len(sentence[start]), 1 + i = (start + 1) % len(sentence) + while s + 1 + len(sentence[i]) <= cols: + s += 1 + len(sentence[i]) + count += 1 + i = (i + 1) % len(sentence) + return count + + wc = [0] * len(sentence) + for i in xrange(len(sentence)): + wc[i] = words_fit(sentence, i, cols) + + words, start = 0, 0 + for i in xrange(rows): + words += wc[start] + start = (start + wc[start]) % len(sentence) + return words / len(sentence) diff --git a/Python/sentence-similarity-ii.py b/Python/sentence-similarity-ii.py new file mode 100644 index 000000000..3e0d8895a --- /dev/null +++ b/Python/sentence-similarity-ii.py @@ -0,0 +1,70 @@ +# Time: O(n + p) +# Space: O(p) + +# Given two sentences words1, words2 (each represented as an array of strings), +# and a list of similar word pairs pairs, determine if two sentences are similar. +# +# For example, words1 = ["great", "acting", "skills"] and +# words2 = ["fine", "drama", "talent"] are similar, +# if the similar word pairs are pairs = +# [["great", "good"], ["fine", "good"], ["acting","drama"], ["skills","talent"]]. +# +# Note that the similarity relation is transitive. +# For example, if "great" and "good" are similar, +# and "fine" and "good" are similar, then "great" and "fine" are similar. +# +# Similarity is also symmetric. +# For example, "great" and "fine" being similar is the same as "fine" and "great" being similar. +# +# Also, a word is always similar with itself. +# For example, the sentences words1 = ["great"], +# words2 = ["great"], pairs = [] are similar, even though there are no specified similar word pairs. +# +# Finally, sentences can only be similar if they have the same number of words. +# So a sentence like words1 = ["great"] can never be similar to words2 = ["doubleplus","good"]. +# +# Note: +# - The length of words1 and words2 will not exceed 1000. +# - The length of pairs will not exceed 2000. +# - The length of each pairs[i] will be 2. +# - The length of each words[i] and pairs[i][j] will be in the range [1, 20]. + +class UnionFind(object): + def __init__(self, n): + self.set = range(n) + + def find_set(self, x): + if self.set[x] != x: + self.set[x] = self.find_set(self.set[x]) # path compression. + return self.set[x] + + def union_set(self, x, y): + x_root, y_root = map(self.find_set, (x, y)) + if x_root == y_root: + return False + self.set[min(x_root, y_root)] = max(x_root, y_root) + return True + + +class Solution(object): + def areSentencesSimilarTwo(self, words1, words2, pairs): + """ + :type words1: List[str] + :type words2: List[str] + :type pairs: List[List[str]] + :rtype: bool + """ + if len(words1) != len(words2): return False + + lookup = {} + union_find = UnionFind(2 * len(pairs)) + for pair in pairs: + for p in pair: + if p not in lookup: + lookup[p] = len(lookup) + union_find.union_set(lookup[pair[0]], lookup[pair[1]]) + + return all(w1 == w2 or + w1 in lookup and w2 in lookup and + union_find.find_set(lookup[w1]) == union_find.find_set(lookup[w2]) + for w1, w2 in itertools.izip(words1, words2)) diff --git a/Python/sentence-similarity.py b/Python/sentence-similarity.py new file mode 100644 index 000000000..02ee74720 --- /dev/null +++ b/Python/sentence-similarity.py @@ -0,0 +1,41 @@ +# Time: O(n + p) +# Space: O(p) + +# Given two sentences words1, words2 (each represented as an array of strings), +# and a list of similar word pairs pairs, determine if two sentences are similar. +# +# For example, "great acting skills" and "fine drama talent" are similar, +# if the similar word pairs are pairs = [["great", "fine"], ["acting","drama"], ["skills","talent"]]. +# +# Note that the similarity relation is not transitive. +# For example, if "great" and "fine" are similar, and "fine" and "good" are similar, +# "great" and "good" are not necessarily similar. +# +# However, similarity is symmetric. +# For example, "great" and "fine" being similar is the same as "fine" and "great" being similar. +# +# Also, a word is always similar with itself. +# For example, the sentences words1 = ["great"], words2 = ["great"], pairs = [] are similar, +# even though there are no specified similar word pairs. +# +# Finally, sentences can only be similar if they have the same number of words. +# So a sentence like words1 = ["great"] can never be similar to words2 = ["doubleplus","good"]. +# +# Note: +# - The length of words1 and words2 will not exceed 1000. +# - The length of pairs will not exceed 2000. +# - The length of each pairs[i] will be 2. +# - The length of each words[i] and pairs[i][j] will be in the range [1, 20]. + +class Solution(object): + def areSentencesSimilar(self, words1, words2, pairs): + """ + :type words1: List[str] + :type words2: List[str] + :type pairs: List[List[str]] + :rtype: bool + """ + if len(words1) != len(words2): return False + lookup = set(map(tuple, pairs)) + return all(w1 == w2 or (w1, w2) in lookup or (w2, w1) in lookup \ + for w1, w2 in itertools.izip(words1, words2)) diff --git a/Python/sequence-reconstruction.py b/Python/sequence-reconstruction.py new file mode 100644 index 000000000..8b492df2a --- /dev/null +++ b/Python/sequence-reconstruction.py @@ -0,0 +1,82 @@ +# Time: O(n * s), n is the size of org, s is the size of seqs +# Space: O(n) + +class Solution(object): + def sequenceReconstruction(self, org, seqs): + """ + :type org: List[int] + :type seqs: List[List[int]] + :rtype: bool + """ + if not seqs: + return False + pos = [0] * (len(org) + 1) + for i in xrange(len(org)): + pos[org[i]] = i + + is_matched = [False] * (len(org) + 1) + cnt_to_match = len(org) - 1 + for seq in seqs: + for i in xrange(len(seq)): + if not 0 < seq[i] <= len(org): + return False + if i == 0: + continue + if pos[seq[i-1]] >= pos[seq[i]]: + return False + if is_matched[seq[i-1]] == False and pos[seq[i-1]] + 1 == pos[seq[i]]: + is_matched[seq[i-1]] = True + cnt_to_match -= 1 + + return cnt_to_match == 0 + + +# Time: O(|V| + |E|) +# Space: O(|E|) +class Solution2(object): + def sequenceReconstruction(self, org, seqs): + """ + :type org: List[int] + :type seqs: List[List[int]] + :rtype: bool + """ + graph = collections.defaultdict(set) + indegree = collections.defaultdict(int) + integer_set = set() + for seq in seqs: + for i in seq: + integer_set.add(i) + if len(seq) == 1: + if seq[0] not in indegree: + indegree[seq[0]] = 0 + continue + for i in xrange(len(seq)-1): + if seq[i] not in indegree: + indegree[seq[i]] = 0 + if seq[i+1] not in graph[seq[i]]: + graph[seq[i]].add(seq[i+1]) + indegree[seq[i+1]] += 1 + + cnt_of_zero_indegree = 0 + res = [] + q = [] + for i in indegree: + if indegree[i] == 0: + cnt_of_zero_indegree += 1 + if cnt_of_zero_indegree > 1: + return False + q.append(i) + + while q: + i = q.pop() + res.append(i) + cnt_of_zero_indegree = 0 + for j in graph[i]: + indegree[j] -= 1 + if indegree[j] == 0: + cnt_of_zero_indegree += 1 + if cnt_of_zero_indegree > 1: + return False + q.append(j) + return res == org and len(org) == len(integer_set) + diff --git a/Python/serialize-and-deserialize-binary-tree.py b/Python/serialize-and-deserialize-binary-tree.py new file mode 100644 index 000000000..d69f43dd0 --- /dev/null +++ b/Python/serialize-and-deserialize-binary-tree.py @@ -0,0 +1,85 @@ +# Time: O(n) +# Space: O(h) + +# Serialization is the process of converting a data structure or +# object into a sequence of bits so that it can be stored in a file +# or memory buffer, or transmitted across a network connection link +# to be reconstructed later in the same or another computer environment. +# +# Design an algorithm to serialize and deserialize a binary tree. +# There is no restriction on how your serialization/deserialization +# algorithm should work. You just need to ensure that a binary tree can +# be serialized to a string and this string can be deserialized to the +# original tree structure. +# +# For example, you may serialize the following tree +# +# 1 +# / \ +# 2 3 +# / \ +# 4 5 +# as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes +# a binary tree. You do not necessarily need to follow this format, so +# please be creative and come up with different approaches yourself. +# Note: Do not use class member/global/static variables to store states. +# Your serialize and deserialize algorithms should be stateless. +# + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Codec: + + def serialize(self, root): + """Encodes a tree to a single string. + + :type root: TreeNode + :rtype: str + """ + def serializeHelper(node): + if not node: + vals.append('#') + else: + vals.append(str(node.val)) + serializeHelper(node.left) + serializeHelper(node.right) + vals = [] + serializeHelper(root) + return ' '.join(vals) + + + def deserialize(self, data): + """Decodes your encoded data to tree. + + :type data: str + :rtype: TreeNode + """ + def deserializeHelper(): + val = next(vals) + if val == '#': + return None + else: + node = TreeNode(int(val)) + node.left = deserializeHelper() + node.right = deserializeHelper() + return node + def isplit(source, sep): + sepsize = len(sep) + start = 0 + while True: + idx = source.find(sep, start) + if idx == -1: + yield source[start:] + return + yield source[start:idx] + start = idx + sepsize + vals = iter(isplit(data, ' ')) + return deserializeHelper() + +# Your Codec object will be instantiated and called as such: +# codec = Codec() +# codec.deserialize(codec.serialize(root)) diff --git a/Python/serialize-and-deserialize-bst.py b/Python/serialize-and-deserialize-bst.py new file mode 100644 index 000000000..811fa44c2 --- /dev/null +++ b/Python/serialize-and-deserialize-bst.py @@ -0,0 +1,72 @@ +# Time: O(n) +# Space: O(h) + +# Serialization is the process of converting a data structure or +# object into a sequence of bits so that it can be stored in a file or +# memory buffer, or transmitted across a network connection link to be +# reconstructed later in the same or another computer environment. +# +# Design an algorithm to serialize and deserialize a binary search tree. +# There is no restriction on how your serialization/deserialization algorithm should work. +# You just need to ensure that a binary search tree can be serialized to a string and +# this string can be deserialized to the original tree structure. +# +# The encoded string should be as compact as possible. +# +# Note: Do not use class member/global/static variables to store states. +# Your serialize and deserialize algorithms should be stateless. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Codec: + + def serialize(self, root): + """Encodes a tree to a single string. + + :type root: TreeNode + :rtype: str + """ + def serializeHelper(node, vals): + if node: + vals.append(node.val) + serializeHelper(node.left, vals) + serializeHelper(node.right, vals) + + vals = [] + serializeHelper(root, vals) + + return ' '.join(map(str, vals)) + + + def deserialize(self, data): + """Decodes your encoded data to tree. + + :type data: str + :rtype: TreeNode + """ + def deserializeHelper(minVal, maxVal, vals): + if not vals: + return None + + if minVal < vals[0] < maxVal: + val = vals.popleft() + node = TreeNode(val) + node.left = deserializeHelper(minVal, val, vals) + node.right = deserializeHelper(val, maxVal, vals) + return node + else: + return None + + vals = collections.deque([int(val) for val in data.split()]) + + return deserializeHelper(float('-inf'), float('inf'), vals) + + +# Your Codec object will be instantiated and called as such: +# codec = Codec() +# codec.deserialize(codec.serialize(root)) diff --git a/Python/set-mismatch.py b/Python/set-mismatch.py new file mode 100644 index 000000000..662ae25d4 --- /dev/null +++ b/Python/set-mismatch.py @@ -0,0 +1,72 @@ +# Time: O(n) +# Space: O(1) + +# The set S originally contains numbers from 1 to n. +# But unfortunately, due to the data error, one of the numbers +# in the set got duplicated to another number in the set, which results +# in repetition of one number and loss of another number. +# +# Given an array nums representing the data status of this set after the error. +# Your task is to firstly find the number occurs twice and then find the number +# that is missing. Return them in the form of an array. +# +# Example 1: +# Input: nums = [1,2,2,4] +# Output: [2,3] +# Note: +# The given array size will in the range [2, 10000]. +# The given array's numbers won't have any order. + +class Solution(object): + def findErrorNums(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + x_xor_y = 0 + for i in xrange(len(nums)): + x_xor_y ^= nums[i] ^ (i+1) + bit = x_xor_y & ~(x_xor_y-1) + result = [0] * 2 + for i, num in enumerate(nums): + result[bool(num & bit)] ^= num + result[bool((i+1) & bit)] ^= i+1 + if result[0] not in nums: + result[0], result[1] = result[1], result[0] + return result + + +# Time: O(n) +# Space: O(1) +class Solution2(object): + def findErrorNums(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + result = [0] * 2 + for i in nums: + if nums[abs(i)-1] < 0: + result[0] = abs(i) + else: + nums[abs(i)-1] *= -1 + for i in xrange(len(nums)): + if nums[i] > 0: + result[1] = i+1 + else: + nums[i] *= -1 + return result + + +# Time: O(n) +# Space: O(1) +class Solution3(object): + def findErrorNums(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + N = len(nums) + x_minus_y = sum(nums) - N*(N+1)//2 + x_plus_y = (sum(x*x for x in nums) - N*(N+1)*(2*N+1)/6) // x_minus_y + return (x_plus_y+x_minus_y) // 2, (x_plus_y-x_minus_y) // 2 diff --git a/Python/shopping-offers.py b/Python/shopping-offers.py new file mode 100644 index 000000000..63fe142b0 --- /dev/null +++ b/Python/shopping-offers.py @@ -0,0 +1,60 @@ +# Time: O(n * 2^n) +# Space: O(n) + +# In LeetCode Store, there are some kinds of items to sell. Each item has a price. +# +# However, there are some special offers, and a special offer consists of one or +# more different kinds of items with a sale price. +# +# You are given the each item's price, a set of special offers, +# and the number we need to buy for each item. The job is to output the lowest price you have to pay +# for exactly certain items as given, where you could make optimal use of the special offers. +# +# Each special offer is represented in the form of an array, +# the last number represents the price you need to pay for this special offer, +# other numbers represents how many specific items you could get if you buy this offer. +# +# You could use any of special offers as many times as you want. +# +# Example 1: +# Input: [2,5], [[3,0,5],[1,2,10]], [3,2] +# Output: 14 +# Explanation: +# There are two kinds of items, A and B. Their prices are $2 and $5 respectively. +# In special offer 1, you can pay $5 for 3A and 0B +# In special offer 2, you can pay $10 for 1A and 2B. +# You need to buy 3A and 2B, so you may pay $10 for 1A and 2B (special offer #2), and $4 for 2A. +# Example 2: +# Input: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1] +# Output: 11 +# Explanation: +# The price of A is $2, and $3 for B, $4 for C. +# You may pay $4 for 1A and 1B, and $9 for 2A ,2B and 1C. +# You need to buy 1A ,2B and 1C, so you may pay $4 for 1A and 1B (special offer #1), and $3 for 1B, $4 for 1C. +# You cannot add more items, though only $9 for 2A ,2B and 1C. +# Note: +# There are at most 6 kinds of items, 100 special offers. +# For each item, you need to buy at most 6 of them. +# You are not allowed to buy more items than you want, even if that would lower the overall price. + +class Solution(object): + def shoppingOffers(self, price, special, needs): + """ + :type price: List[int] + :type special: List[List[int]] + :type needs: List[int] + :rtype: int + """ + def shoppingOffersHelper(price, special, needs, i): + if i == len(special): + return sum(map(lambda x, y: x*y, price, needs)) + result = shoppingOffersHelper(price, special, needs, i+1) + for j in xrange(len(needs)): + needs[j] -= special[i][j] + if all(need >= 0 for need in needs): + result = min(result, special[i][-1] + shoppingOffersHelper(price, special, needs, i)) + for j in xrange(len(needs)): + needs[j] += special[i][j] + return result + + return shoppingOffersHelper(price, special, needs, 0) diff --git a/Python/shortest-completing-word.py b/Python/shortest-completing-word.py new file mode 100644 index 000000000..49c50fe11 --- /dev/null +++ b/Python/shortest-completing-word.py @@ -0,0 +1,53 @@ +# Time: O(n) +# Space: O(1) + +# Find the minimum length word from a given dictionary words, +# which has all the letters from the string licensePlate. +# Such a word is said to complete the given string licensePlate +# +# Here, for letters we ignore case. +# For example, "P" on the licensePlate still matches "p" on the word. +# +# It is guaranteed an answer exists. +# If there are multiple answers, return the one that occurs first in the array. +# +# The license plate might have the same letter occurring multiple times. +# For example, given a licensePlate of "PP", +# the word "pair" does not complete the licensePlate, but the word "supper" does. +# +# Example 1: +# Input: licensePlate = "1s3 PSt", words = ["step", "steps", "stripe", "stepple"] +# Output: "steps" +# Explanation: The smallest length word that contains the letters "S", "P", "S", and "T". +# Note that the answer is not "step", because the letter "s" must occur in the word twice. +# Also note that we ignored case for the purposes of comparing whether a letter exists in the word. +# Example 2: +# Input: licensePlate = "1s3 456", words = ["looks", "pest", "stew", "show"] +# Output: "pest" +# Explanation: There are 3 smallest length words that contains the letters "s". +# We return the one that occurred first. +# Note: +# - licensePlate will be a string with length in range [1, 7]. +# - licensePlate will contain digits, spaces, or letters (uppercase or lowercase). +# - words will have a length in the range [10, 1000]. +# - Every words[i] will consist of lowercase letters, and have length in range [1, 15]. + +class Solution(object): + def shortestCompletingWord(self, licensePlate, words): + """ + :type licensePlate: str + :type words: List[str] + :rtype: str + """ + def contains(counter1, w2): + c2 = collections.Counter(w2.lower()) + c2.subtract(counter1) + return all(map(lambda x: x >= 0, c2.values())) + + result = None + counter = collections.Counter(c.lower() for c in licensePlate if c.isalpha()) + for word in words: + if (result is None or (len(word) < len(result))) and \ + contains(counter, word): + result = word + return result diff --git a/Python/shortest-distance-from-all-buildings.py b/Python/shortest-distance-from-all-buildings.py new file mode 100644 index 000000000..7b5fd2ae5 --- /dev/null +++ b/Python/shortest-distance-from-all-buildings.py @@ -0,0 +1,46 @@ +# Time: O(k * m * n), k is the number of the buildings +# Space: O(m * n) + +class Solution(object): + def shortestDistance(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + def bfs(grid, dists, cnts, x, y): + dist, m, n = 0, len(grid), len(grid[0]) + visited = [[False for _ in xrange(n)] for _ in xrange(m)] + + pre_level = [(x, y)] + visited[x][y] = True + while pre_level: + dist += 1 + cur_level = [] + for i, j in pre_level: + for dir in [(-1, 0), (1, 0), (0, -1), (0, 1)]: + I, J = i+dir[0], j+dir[1] + if 0 <= I < m and 0 <= J < n and grid[I][J] == 0 and not visited[I][J]: + cnts[I][J] += 1 + dists[I][J] += dist + cur_level.append((I, J)) + visited[I][J] = True + + pre_level = cur_level + + + m, n, cnt = len(grid), len(grid[0]), 0 + dists = [[0 for _ in xrange(n)] for _ in xrange(m)] + cnts = [[0 for _ in xrange(n)] for _ in xrange(m)] + for i in xrange(m): + for j in xrange(n): + if grid[i][j] == 1: + cnt += 1 + bfs(grid, dists, cnts, i, j) + + shortest = float("inf") + for i in xrange(m): + for j in xrange(n): + if dists[i][j] < shortest and cnts[i][j] == cnt: + shortest = dists[i][j] + + return shortest if shortest != float("inf") else -1 diff --git a/Python/shortest-palindrome.py b/Python/shortest-palindrome.py new file mode 100644 index 000000000..f092ca4bf --- /dev/null +++ b/Python/shortest-palindrome.py @@ -0,0 +1,82 @@ +# Time: O(n) +# Space: O(n) +# +# Given a string S, you are allowed to convert it to a palindrome +# by adding characters in front of it. Find and return the shortest +# palindrome you can find by performing this transformation. +# +# For example: +# +# Given "aacecaaa", return "aaacecaaa". +# +# Given "abcd", return "dcbabcd". +# + +# KMP Algorithm +class Solution(object): + def shortestPalindrome(self, s): + """ + :type s: str + :rtype: str + """ + def getPrefix(pattern): + prefix = [-1] * len(pattern) + j = -1 + for i in xrange(1, len(pattern)): + while j > -1 and pattern[j+1] != pattern[i]: + j = prefix[j] + if pattern[j+1] == pattern[i]: + j += 1 + prefix[i] = j + return prefix + + if not s: + return s + + A = s + s[::-1] + prefix = getPrefix(A) + i = prefix[-1] + while i >= len(s): + i = prefix[i] + return s[i+1:][::-1] + s + + +# Time: O(n) +# Space: O(n) +# Manacher's Algorithm +class Solution2(object): + def shortestPalindrome(self, s): + """ + :type s: str + :rtype: str + """ + def preProcess(s): + if not s: + return ['^', '$'] + string = ['^'] + for c in s: + string += ['#', c] + string += ['#', '$'] + return string + + string = preProcess(s) + palindrome = [0] * len(string) + center, right = 0, 0 + for i in xrange(1, len(string) - 1): + i_mirror = 2 * center - i + if right > i: + palindrome[i] = min(right - i, palindrome[i_mirror]) + else: + palindrome[i] = 0 + + while string[i + 1 + palindrome[i]] == string[i - 1 - palindrome[i]]: + palindrome[i] += 1 + + if i + palindrome[i] > right: + center, right = i, i + palindrome[i] + + max_len = 0 + for i in xrange(1, len(string) - 1): + if i - palindrome[i] == 1: + max_len = palindrome[i] + return s[len(s)-1:max_len-1:-1] + s diff --git a/Python/shortest-unsorted-continuous-subarray.py b/Python/shortest-unsorted-continuous-subarray.py new file mode 100644 index 000000000..bed6c7a6a --- /dev/null +++ b/Python/shortest-unsorted-continuous-subarray.py @@ -0,0 +1,34 @@ +# Time: O(n) +# Space: O(1) + +# Given an integer array, you need to find one continuous subarray that +# if you only sort this subarray in ascending order, +# then the whole array will be sorted in ascending order, too. +# +# You need to find the shortest such subarray and output its length. +# +# Example 1: +# Input: [2, 6, 4, 8, 10, 9, 15] +# Output: 5 +# Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order +# to make the whole array sorted in ascending order. +# +# Note: +# Then length of the input array is in range [1, 10,000]. +# The input array may contain duplicates, so ascending order here means <=. + +class Solution(object): + def findUnsortedSubarray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + left, right = -1, -2 + min_from_right, max_from_left = nums[-1], nums[0] + for i in xrange(1, n): + max_from_left = max(max_from_left, nums[i]) + min_from_right = min(min_from_right, nums[n-1-i]) + if nums[i] < max_from_left: right = i + if nums[n-1-i] > min_from_right: left = n-1-i + return right - left + 1 diff --git a/Python/shortest-word-distance-ii.py b/Python/shortest-word-distance-ii.py new file mode 100644 index 000000000..fb76a188c --- /dev/null +++ b/Python/shortest-word-distance-ii.py @@ -0,0 +1,29 @@ +# Time: init: O(n), lookup: O(a + b), a, b is occurences of word1, word2 +# Space: O(n) + +class WordDistance: + # initialize your data structure here. + # @param {string[]} words + def __init__(self, words): + self.wordIndex = collections.defaultdict(list) + for i in xrange(len(words)): + self.wordIndex[words[i]].append(i) + + # @param {string} word1 + # @param {string} word2 + # @return {integer} + # Adds a word into the data structure. + def shortest(self, word1, word2): + indexes1 = self.wordIndex[word1] + indexes2 = self.wordIndex[word2] + + i, j, dist = 0, 0, float("inf") + while i < len(indexes1) and j < len(indexes2): + dist = min(dist, abs(indexes1[i] - indexes2[j])) + if indexes1[i] < indexes2[j]: + i += 1 + else: + j += 1 + + return dist + diff --git a/Python/shortest-word-distance-iii.py b/Python/shortest-word-distance-iii.py new file mode 100644 index 000000000..021aea8f7 --- /dev/null +++ b/Python/shortest-word-distance-iii.py @@ -0,0 +1,25 @@ +# Time: O(n) +# Space: O(1) + +class Solution: + # @param {string[]} words + # @param {string} word1 + # @param {string} word2 + # @return {integer} + def shortestWordDistance(self, words, word1, word2): + dist = float("inf") + is_same = (word1 == word2) + i, index1, index2 = 0, None, None + while i < len(words): + if words[i] == word1: + if is_same and index1 is not None: + dist = min(dist, abs(index1 - i)) + index1 = i + elif words[i] == word2: + index2 = i + + if index1 is not None and index2 is not None: + dist = min(dist, abs(index1 - index2)) + i += 1 + + return dist diff --git a/Python/shortest-word-distance.py b/Python/shortest-word-distance.py new file mode 100644 index 000000000..c57352eb7 --- /dev/null +++ b/Python/shortest-word-distance.py @@ -0,0 +1,22 @@ +# Time: O(n) +# Space: O(1) + +class Solution: + # @param {string[]} words + # @param {string} word1 + # @param {string} word2 + # @return {integer} + def shortestDistance(self, words, word1, word2): + dist = float("inf") + i, index1, index2 = 0, None, None + while i < len(words): + if words[i] == word1: + index1 = i + elif words[i] == word2: + index2 = i + + if index1 is not None and index2 is not None: + dist = min(dist, abs(index1 - index2)) + i += 1 + + return dist diff --git a/Python/shuffle-an-array.py b/Python/shuffle-an-array.py new file mode 100644 index 000000000..0d373852a --- /dev/null +++ b/Python/shuffle-an-array.py @@ -0,0 +1,56 @@ +# Time: O(n) +# Space: O(n) + +# Shuffle a set of numbers without duplicates. +# +# Example: +# +# // Init an array with set 1, 2, and 3. +# int[] nums = {1,2,3}; +# Solution solution = new Solution(nums); +# +# // Shuffle the array [1,2,3] and return its result. +# Any permutation of [1,2,3] must equally likely to be returned. +# solution.shuffle(); +# +# // Resets the array back to its original configuration [1,2,3]. +# solution.reset(); +# +# // Returns the random shuffling of array [1,2,3]. +# solution.shuffle(); + +class Solution(object): + + def __init__(self, nums): + """ + + :type nums: List[int] + :type size: int + """ + self.__nums = nums + + + def reset(self): + """ + Resets the array to its original configuration and return it. + :rtype: List[int] + """ + return self.__nums + + + def shuffle(self): + """ + Returns a random shuffling of the array. + :rtype: List[int] + """ + nums = list(self.__nums) + for i in xrange(len(nums)): + j = random.randint(i, len(nums)-1) + nums[i], nums[j] = nums[j], nums[i] + return nums + + +# Your Solution object will be instantiated and called as such: +# obj = Solution(nums) +# param_1 = obj.reset() +# param_2 = obj.shuffle() diff --git a/Python/single-element-in-a-sorted-array.py b/Python/single-element-in-a-sorted-array.py new file mode 100644 index 000000000..4a7dcb18b --- /dev/null +++ b/Python/single-element-in-a-sorted-array.py @@ -0,0 +1,31 @@ +# Time: O(logn) +# Space: O(1) + +# Given a sorted array consisting of only integers +# where every element appears twice except for one element +# which appears once. Find this single element that appears only once. +# +# Example 1: +# Input: [1,1,2,3,3,4,4,8,8] +# Output: 2 +# Example 2: +# Input: [3,3,7,7,10,11,11] +# Output: 10 +# Note: Your solution should run in O(log n) time and O(1) space. + +class Solution(object): + def singleNonDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums)-1 + while left <= right: + mid = left + (right - left) / 2 + if not (mid%2 == 0 and mid+1 < len(nums) and \ + nums[mid] == nums[mid+1]) and \ + not (mid%2 == 1 and nums[mid] == nums[mid-1]): + right = mid-1 + else: + left = mid+1 + return nums[left] diff --git a/Python/single-number-ii.py b/Python/single-number-ii.py index e725ccf8a..e87276c96 100644 --- a/Python/single-number-ii.py +++ b/Python/single-number-ii.py @@ -5,9 +5,19 @@ # # Note: # Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? -# +import collections -class Solution: + +class Solution(object): + # @param A, a list of integer + # @return an integer + def singleNumber(self, A): + one, two = 0, 0 + for x in A: + one, two = (~x & one) | (x & ~one & ~two), (~x & two) | (x & one) + return one + +class Solution2(object): # @param A, a list of integer # @return an integer def singleNumber(self, A): @@ -20,5 +30,35 @@ def singleNumber(self, A): two &= ~carry return one + +class Solution3(object): + def singleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return (collections.Counter(list(set(nums)) * 3) - collections.Counter(nums)).keys()[0] + + +class Solution4(object): + def singleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return (sum(set(nums)) * 3 - sum(nums)) / 2 + + +# every element appears 4 times except for one with 2 times +class SolutionEX(object): + # @param A, a list of integer + # @return an integer + # [1, 1, 1, 1, 2, 2, 2, 2, 3, 3] + def singleNumber(self, A): + one, two, three = 0, 0, 0 + for x in A: + one, two, three = (~x & one) | (x & ~one & ~two & ~three), (~x & two) | (x & one), (~x & three) | (x & two) + return two + if __name__ == "__main__": - print Solution().singleNumber([1, 1, 1, 2, 2, 2, 3]) \ No newline at end of file + print Solution().singleNumber([1, 1, 1, 2, 2, 2, 3]) diff --git a/Python/single-number-iii.py b/Python/single-number-iii.py new file mode 100644 index 000000000..49d0e53ba --- /dev/null +++ b/Python/single-number-iii.py @@ -0,0 +1,57 @@ +# Time: O(n) +# Space: O(1) +# +# Given an array of numbers nums, in which exactly two +# elements appear only once and all the other elements +# appear exactly twice. Find the two elements that appear only once. +# +# For example: +# +# Given nums = [1, 2, 1, 3, 2, 5], return [3, 5]. +# +# Note: +# The order of the result is not important. So in the +# above example, [5, 3] is also correct. +# Your algorithm should run in linear runtime complexity. +# Could you implement it using only constant space complexity? +import operator +import collections + + +class Solution: + # @param {integer[]} nums + # @return {integer[]} + def singleNumber(self, nums): + x_xor_y = reduce(operator.xor, nums) + bit = x_xor_y & -x_xor_y + result = [0, 0] + for i in nums: + result[bool(i & bit)] ^= i + return result + + +class Solution2: + # @param {integer[]} nums + # @return {integer[]} + def singleNumber(self, nums): + x_xor_y = 0 + for i in nums: + x_xor_y ^= i + + bit = x_xor_y & ~(x_xor_y - 1) + + x = 0 + for i in nums: + if i & bit: + x ^= i + + return [x, x ^ x_xor_y] + + +class Solution3(object): + def singleNumber(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + return [x[0] for x in sorted(collections.Counter(nums).items(), key=lambda i: i[1], reverse=False)[:2]] diff --git a/Python/single-number.py b/Python/single-number.py index adcb1cba6..88047ae25 100644 --- a/Python/single-number.py +++ b/Python/single-number.py @@ -9,11 +9,14 @@ import operator + class Solution: - # @param A, a list of integer - # @return an integer + """ + :type nums: List[int] + :rtype: int + """ def singleNumber(self, A): return reduce(operator.xor, A) if __name__ == '__main__': - print Solution().singleNumber([1, 1, 2, 2, 3]) \ No newline at end of file + print Solution().singleNumber([1, 1, 2, 2, 3]) diff --git a/Python/sliding-window-maximum.py b/Python/sliding-window-maximum.py new file mode 100644 index 000000000..eeaffeedb --- /dev/null +++ b/Python/sliding-window-maximum.py @@ -0,0 +1,49 @@ +# Time: O(n) +# Space: O(k) + +# Given an array nums, there is a sliding window of size k +# which is moving from the very left of the array to the +# very right. You can only see the k numbers in the window. +# Each time the sliding window moves right by one position. +# +# For example, +# Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. +# +# Window position Max +# --------------- ----- +# [1 3 -1] -3 5 3 6 7 3 +# 1 [3 -1 -3] 5 3 6 7 3 +# 1 3 [-1 -3 5] 3 6 7 5 +# 1 3 -1 [-3 5 3] 6 7 5 +# 1 3 -1 -3 [5 3 6] 7 6 +# 1 3 -1 -3 5 [3 6 7] 7 +# Therefore, return the max sliding window as [3,3,5,5,6,7]. +# +# Note: +# You may assume k is always valid, ie: 1 <= k <= input array's size for non-empty array. +# +# Follow up: +# Could you solve it in linear time? + +from collections import deque + +class Solution(object): + def maxSlidingWindow(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + dq = deque() + max_numbers = [] + + for i in xrange(len(nums)): + while dq and nums[i] >= nums[dq[-1]]: + dq.pop() + dq.append(i) + if i >= k and dq and dq[0] <= i - k: + dq.popleft() + if i >= k - 1: + max_numbers.append(nums[dq[0]]) + + return max_numbers diff --git a/Python/smallest-good-base.py b/Python/smallest-good-base.py new file mode 100644 index 000000000..c63d418b6 --- /dev/null +++ b/Python/smallest-good-base.py @@ -0,0 +1,36 @@ +# Time: O(logn * log(logn)) +# Space: O(1) + +# For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1. +# +# Now given a string representing n, you should return the smallest good base of n in string format. +# +# Example 1: +# Input: "13" +# Output: "3" +# Explanation: 13 base 3 is 111. +# Example 2: +# Input: "4681" +# Output: "8" +# Explanation: 4681 base 8 is 11111. +# Example 3: +# Input: "1000000000000000000" +# Output: "999999999999999999" +# Explanation: 1000000000000000000 base 999999999999999999 is 11. +# Note: +# The range of n is [3, 10^18]. +# The string representing n is always valid and will not have leading zeros. + +class Solution(object): + def smallestGoodBase(self, n): + """ + :type n: str + :rtype: str + """ + num = int(n) + max_len = int(math.log(num,2)) + for l in xrange(max_len, 1, -1): + b = int(num ** (l**-1)) + if (b**(l+1)-1) // (b-1) == num: + return str(b) + return str(num-1) diff --git a/Python/smallest-range.py b/Python/smallest-range.py new file mode 100644 index 000000000..280dd05cf --- /dev/null +++ b/Python/smallest-range.py @@ -0,0 +1,47 @@ +# Time: O(nlogk) +# Space: O(k) + +# You have k lists of sorted integers in ascending order. +# Find the smallest range that includes at least one number from each of the k lists. +# +# We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a == d-c. +# +# Example 1: +# Input:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]] +# Output: [20,24] +# Explanation: +# List 1: [4, 10, 15, 24,26], 24 is in range [20,24]. +# List 2: [0, 9, 12, 20], 20 is in range [20,24]. +# List 3: [5, 18, 22, 30], 22 is in range [20,24]. +# Note: +# The given list may contain duplicates, so ascending order means >= here. +# 1 <= k <= 3500 +# -10^5 <= value of elements <= 10^5. +# For Java users, please note that the input type has been changed to List>. +# And after you reset the code template, you'll see this point. + +class Solution(object): + def smallestRange(self, nums): + """ + :type nums: List[List[int]] + :rtype: List[int] + """ + left, right = float("inf"), float("-inf") + min_heap = [] + for row in nums: + left = min(left, row[0]) + right = max(right, row[0]) + it = iter(row) + heapq.heappush(min_heap, (next(it, None), it)) + + result = (left, right) + while min_heap: + (val, it) = heapq.heappop(min_heap) + val = next(it, None) + if val is None: + break + heapq.heappush(min_heap, (val, it)) + left, right = min_heap[0][0], max(right, val); + if right - left < result[1] - result[0]: + result = (left, right) + return result diff --git a/Python/smallest-rectangle-enclosing-black-pixels.py b/Python/smallest-rectangle-enclosing-black-pixels.py new file mode 100644 index 000000000..a410c374f --- /dev/null +++ b/Python/smallest-rectangle-enclosing-black-pixels.py @@ -0,0 +1,30 @@ +# Time: O(nlogn) +# Space: O(1) + +class Solution(object): + def minArea(self, image, x, y): + """ + :type image: List[List[str]] + :type x: int + :type y: int + :rtype: int + """ + def binarySearch(left, right, find, image, has_one): + while left <= right: # O(logn) times + mid = left + (right - left) / 2 + if find(image, has_one, mid): # Time: O(n) + right = mid - 1 + else: + left = mid + 1 + return left + + + searchColumns = lambda image, has_one, mid: any([int(row[mid]) for row in image]) == has_one + left = binarySearch(0, y - 1, searchColumns, image, True) + right = binarySearch(y + 1, len(image[0]) - 1, searchColumns, image, False) + + searchRows = lambda image, has_one, mid: any(itertools.imap(int, image[mid])) == has_one + top = binarySearch(0, x - 1, searchRows, image, True) + bottom = binarySearch(x + 1, len(image) - 1, searchRows, image, False) + + return (right - left) * (bottom - top) diff --git a/Python/solve-the-equation.py b/Python/solve-the-equation.py new file mode 100644 index 000000000..a5ccdb1bb --- /dev/null +++ b/Python/solve-the-equation.py @@ -0,0 +1,43 @@ +# Time: O(n) +# Space: O(n) + +# Solve a given equation and return the value of x in the form of string "x=#value". +# The equation contains only '+', '-' operation, the variable x and its coefficient. +# +# If there is no solution for the equation, return "No solution". +# +# If there are infinite solutions for the equation, return "Infinite solutions". +# +# If there is exactly one solution for the equation, we ensure that the value of x is an integer. +# +# Example 1: +# Input: "x+5-3+x=6+x-2" +# Output: "x=2" +# Example 2: +# Input: "x=x" +# Output: "Infinite solutions" +# Example 3: +# Input: "2x=x" +# Output: "x=0" +# Example 4: +# Input: "2x+3x-6x=x+2" +# Output: "x=-1" +# Example 5: +# Input: "x=x+2" +# Output: "No solution" + +class Solution(object): + def solveEquation(self, equation): + """ + :type equation: str + :rtype: str + """ + a, b, side = 0, 0, 1 + for eq, sign, num, isx in re.findall('(=)|([-+]?)(\d*)(x?)', equation): + if eq: + side = -1 + elif isx: + a += side * int(sign + '1') * int(num or 1) + elif num: + b -= side * int(sign + num) + return 'x=%d' % (b / a) if a else 'No solution' if b else 'Infinite solutions' diff --git a/Python/sort-characters-by-frequency.py b/Python/sort-characters-by-frequency.py new file mode 100644 index 000000000..72712cf14 --- /dev/null +++ b/Python/sort-characters-by-frequency.py @@ -0,0 +1,55 @@ +# Time: O(n) +# Space: O(n) + +# Input: +# "tree" +# +# Output: +# "eert" +# +# Explanation: +# 'e' appears twice while 'r' and 't' both appear once. +# So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer. +# Example 2: +# +# Input: +# "cccaaa" +# +# Output: +# "cccaaa" +# +# Explanation: +# Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer. +# Note that "cacaca" is incorrect, as the same characters must be together. +# Example 3: +# +# Input: +# "Aabb" +# +# Output: +# "bbAa" +# +# Explanation: +# "bbaA" is also a valid answer, but "Aabb" is incorrect. +# Note that 'A' and 'a' are treated as two different characters. + +class Solution(object): + def frequencySort(self, s): + """ + :type s: str + :rtype: str + """ + freq = collections.defaultdict(int) + for c in s: + freq[c] += 1 + + counts = [""] * (len(s)+1) + for c in freq: + counts[freq[c]] += c + + result = "" + for count in reversed(xrange(len(counts)-1)): + for c in counts[count]: + result += c * count + + return result diff --git a/Python/sort-colors.py b/Python/sort-colors.py index d6bef9682..5e42aa69b 100644 --- a/Python/sort-colors.py +++ b/Python/sort-colors.py @@ -19,23 +19,29 @@ # Could you come up with an one-pass algorithm using only constant space? # -class Solution: - # @param A a list of integers - # @return nothing, sort in place - def sortColors(self, A): - i, last_zero, first_two = 0, -1, len(A) - - while i < first_two: - if A[i] == 0: - last_zero += 1 - A[last_zero], A[i] = A[i], A[last_zero] - elif A[i] == 2: - first_two -= 1 - A[first_two], A[i] = A[i], A[first_two] - i -= 1 - i += 1 +class Solution(object): + def sortColors(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + def triPartition(nums, target): + i, j, n = 0, 0, len(nums) - 1 + + while j <= n: + if nums[j] < target: + nums[i], nums[j] = nums[j], nums[i] + i += 1 + j += 1 + elif nums[j] > target: + nums[j], nums[n] = nums[n], nums[j] + n -= 1 + else: + j += 1 + + triPartition(nums, 1) if __name__ == "__main__": A = [2, 1, 1, 0, 0, 2] Solution().sortColors(A) - print A \ No newline at end of file + print A diff --git a/Python/sort-list.py b/Python/sort-list.py index bd56db074..5427a88bd 100644 --- a/Python/sort-list.py +++ b/Python/sort-list.py @@ -1,5 +1,5 @@ # Time: O(nlogn) -# Space: O(1) +# Space: O(logn) for stack call # # Sort a linked list in O(n log n) time using constant space complexity. # @@ -53,4 +53,4 @@ def mergeTwoLists(self, l1, l2): head.next = ListNode(4) head.next.next = ListNode(1) head.next.next.next= ListNode(2) - print Solution().sortList(head) \ No newline at end of file + print Solution().sortList(head) diff --git a/Python/sort-transformed-array.py b/Python/sort-transformed-array.py new file mode 100644 index 000000000..01eb27de1 --- /dev/null +++ b/Python/sort-transformed-array.py @@ -0,0 +1,29 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def sortTransformedArray(self, nums, a, b, c): + """ + :type nums: List[int] + :type a: int + :type b: int + :type c: int + :rtype: List[int] + """ + f = lambda x, a, b, c : a * x * x + b * x + c + + result = [] + if not nums: + return result + + left, right = 0, len(nums) - 1 + d = -1 if a > 0 else 1 + while left <= right: + if d * f(nums[left], a, b, c) < d * f(nums[right], a, b, c): + result.append(f(nums[left], a, b, c)) + left += 1 + else: + result.append(f(nums[right], a, b, c)) + right -= 1 + + return result[::d] diff --git a/Python/sparse-matrix-multiplication.py b/Python/sparse-matrix-multiplication.py new file mode 100644 index 000000000..30dc340eb --- /dev/null +++ b/Python/sparse-matrix-multiplication.py @@ -0,0 +1,18 @@ +# Time: O(m * n * l), A is m x n matrix, B is n x l matrix +# Space: O(m * l) + +class Solution(object): + def multiply(self, A, B): + """ + :type A: List[List[int]] + :type B: List[List[int]] + :rtype: List[List[int]] + """ + m, n, l = len(A), len(A[0]), len(B[0]) + res = [[0 for _ in xrange(l)] for _ in xrange(m)] + for i in xrange(m): + for k in xrange(n): + if A[i][k]: + for j in xrange(l): + res[i][j] += A[i][k] * B[k][j] + return res diff --git a/Python/spiral-matrix-ii.py b/Python/spiral-matrix-ii.py index 554c9f7a8..d0b870bd5 100644 --- a/Python/spiral-matrix-ii.py +++ b/Python/spiral-matrix-ii.py @@ -17,7 +17,7 @@ class Solution: # @return a list of lists of integer def generateMatrix(self, n): - matrix = [[0 for i in range(n)] for i in range(n)] + matrix = [[0 for _ in xrange(n)] for _ in xrange(n)] left, right, top, bottom, num = 0, n - 1, 0, n - 1, 1 @@ -43,4 +43,4 @@ def generateMatrix(self, n): if __name__ == "__main__": print Solution().generateMatrix(3) - print Solution().generateMatrix(8) \ No newline at end of file + print Solution().generateMatrix(8) diff --git a/Python/split-array-into-consecutive-subsequences.py b/Python/split-array-into-consecutive-subsequences.py new file mode 100644 index 000000000..c5c0008ca --- /dev/null +++ b/Python/split-array-into-consecutive-subsequences.py @@ -0,0 +1,55 @@ +# Time: O(n) +# Space: O(1) + +# You are given an integer array sorted in ascending order (may contain duplicates), +# you need to split them into several subsequences, +# where each subsequences consist of at least 3 consecutive integers. Return whether you can make such a split. +# +# Example 1: +# Input: [1,2,3,3,4,5] +# Output: True +# Explanation: +# You can split them into two consecutive subsequences : +# 1, 2, 3 +# 3, 4, 5 +# Example 2: +# Input: [1,2,3,3,4,4,5,5] +# Output: True +# Explanation: +# You can split them into two consecutive subsequences : +# 1, 2, 3, 4, 5 +# 3, 4, 5 +# Example 3: +# Input: [1,2,3,4,4,5] +# Output: False +# Note: +# The length of the input is in range of [1, 10000] + +class Solution(object): + def isPossible(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + pre, cur = float("-inf"), 0 + cnt1, cnt2, cnt3 = 0, 0, 0 + i = 0 + while i < len(nums): + cnt = 0 + cur = nums[i] + while i < len(nums) and cur == nums[i]: + cnt += 1 + i += 1 + + if cur != pre + 1: + if cnt1 != 0 or cnt2 != 0: + return False + cnt1, cnt2, cnt3 = cnt, 0, 0 + else: + if cnt < cnt1 + cnt2: + return False + cnt1, cnt2, cnt3 = max(0, cnt - (cnt1 + cnt2 + cnt3)), \ + cnt1, \ + cnt2 + min(cnt3, cnt - (cnt1 + cnt2)) + pre = cur + return cnt1 == 0 and cnt2 == 0 diff --git a/Python/split-array-largest-sum.py b/Python/split-array-largest-sum.py new file mode 100644 index 000000000..5c67d4692 --- /dev/null +++ b/Python/split-array-largest-sum.py @@ -0,0 +1,52 @@ +# Time: O(nlogs), s is the sum of nums +# Space: O(1) + +# Given an array which consists of non-negative integers and an integer m, +# you can split the array into m non-empty continuous subarrays. +# Write an algorithm to minimize the largest sum among these m subarrays. +# +# Note: +# Given m satisfies the following constraint: 1 <= m <= length(nums) <= 14,000. +# +# Examples: +# +# Input: +# nums = [7,2,5,10,8] +# m = 2 +# +# Output: +# 18 +# +# Explanation: +# There are four ways to split nums into two subarrays. +# The best way is to split it into [7,2,5] and [10,8], +# where the largest sum among the two subarrays is only 18. + +class Solution(object): + def splitArray(self, nums, m): + """ + :type nums: List[int] + :type m: int + :rtype: int + """ + def canSplit(nums, m, s): + cnt, curr_sum = 1, 0 + for num in nums: + curr_sum += num + if curr_sum > s: + curr_sum = num + cnt += 1 + return cnt <= m + + left, right = 0, 0 + for num in nums: + left = max(left, num) + right += num + + while left <= right: + mid = left + (right - left) / 2; + if canSplit(nums, m, mid): + right = mid - 1 + else: + left = mid + 1 + return left diff --git a/Python/split-array-with-equal-sum.py b/Python/split-array-with-equal-sum.py new file mode 100644 index 000000000..036df2334 --- /dev/null +++ b/Python/split-array-with-equal-sum.py @@ -0,0 +1,26 @@ +# Time: O(n^2) +# Space: O(n) + +class Solution(object): + def splitArray(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + if len(nums) < 7: + return False + + accumulated_sum = [0] * len(nums) + accumulated_sum[0] = nums[0] + for i in xrange(1, len(nums)): + accumulated_sum[i] = accumulated_sum[i-1] + nums[i] + for j in xrange(3, len(nums)-3): + lookup = set() + for i in xrange(1, j-1): + if accumulated_sum[i-1] == accumulated_sum[j-1] - accumulated_sum[i]: + lookup.add(accumulated_sum[i-1]) + for k in xrange(j+2, len(nums)-1): + if accumulated_sum[-1] - accumulated_sum[k] == accumulated_sum[k-1] - accumulated_sum[j] and \ + accumulated_sum[k - 1] - accumulated_sum[j] in lookup: + return True + return False diff --git a/Python/split-concatenated-strings.py b/Python/split-concatenated-strings.py new file mode 100644 index 000000000..4693b532e --- /dev/null +++ b/Python/split-concatenated-strings.py @@ -0,0 +1,47 @@ +# Time: O(n^2) +# Space: O(n) + +# Given a list of strings, you could concatenate these strings together into a loop, +# where for each string you could choose to reverse it or not. +# Among all the possible loops, you need to find the lexicographically +# biggest string after cutting the loop, which will make the looped string into a regular one. +# +# Specifically, to find the lexicographically biggest string, you need to experience two phases: +# +# Concatenate all the strings into a loop, where you can reverse some strings or +# not and connect them in the same order as given. +# Cut and make one breakpoint in any place of the loop, which will make the looped string +# into a regular one starting from the character at the cutpoint. +# And your job is to find the lexicographically biggest one among all the possible regular strings. +# +# Example: +# Input: "abc", "xyz" +# Output: "zyxcba" +# Explanation: You can get the looped string "-abcxyz-", "-abczyx-", "-cbaxyz-", "-cbazyx-", +# where '-' represents the looped status. +# The answer string came from the fourth looped one, +# where you could cut from the middle character 'a' and get "zyxcba". +# Note: +# The input strings will only contain lowercase letters. +# The total length of all the strings will not over 1,000. + +class Solution(object): + def splitLoopedString(self, strs): + """ + :type strs: List[str] + :rtype: str + """ + tmp = [] + for s in strs: + tmp += max(s, s[::-1]) + s = "".join(tmp) + + result, st = "a", 0 + for i in xrange(len(strs)): + body = "".join([s[st + len(strs[i]):], s[0:st]]) + for p in strs[i], strs[i][::-1]: + for j in xrange(len(strs[i])): + if p[j] >= result[0]: + result = max(result, "".join([p[j:], body, p[:j]])) + st += len(strs[i]) + return result diff --git a/Python/split-linked-list-in-parts.py b/Python/split-linked-list-in-parts.py new file mode 100644 index 000000000..27b6e791f --- /dev/null +++ b/Python/split-linked-list-in-parts.py @@ -0,0 +1,71 @@ +# Time: O(n + k) +# Space: O(1) + +# Given a (singly) linked list with head node root, +# write a function to split the linked list into k consecutive linked list "parts". +# +# The length of each part should be as equal as possible: +# no two parts should have a size differing by more than 1. +# This may lead to some parts being null. +# +# The parts should be in order of occurrence in the input list, +# and parts occurring earlier should always have a size greater than or equal parts occurring later. +# +# Return a List of ListNode's representing the linked list parts that are formed. +# +# Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ] +# Example 1: +# Input: +# root = [1, 2, 3], k = 5 +# Output: [[1],[2],[3],[],[]] +# Explanation: +# The input and each element of the output are ListNodes, not arrays. +# For example, the input root has root.val = 1, root.next.val = 2, \root.next.next.val = 3, +# and root.next.next.next = null. +# The first element output[0] has output[0].val = 1, output[0].next = null. +# The last element output[4] is null, but it's string representation as a ListNode is []. +# +# Example 2: +# Input: +# root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3 +# Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]] +# Explanation: +# The input has been split into consecutive parts with size difference at most 1, +# and earlier parts are a larger size than the later parts. +# +# Note: +# - The length of root will be in the range [0, 1000]. +# - Each value of a node in the input will be an integer in the range [0, 999]. +# - k will be an integer in the range [1, 50]. +# +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution(object): + def splitListToParts(self, root, k): + """ + :type root: ListNode + :type k: int + :rtype: List[ListNode] + """ + n = 0 + curr = root + while curr: + curr = curr.next + n += 1 + width, remainder = divmod(n, k) + + result = [] + curr = root + for i in xrange(k): + head = curr + for j in xrange(width-1+int(i < remainder)): + if curr: + curr = curr.next + if curr: + curr.next, curr = None, curr.next + result.append(head) + return result diff --git a/Python/sqrtx.py b/Python/sqrtx.py index aab364874..6429b9180 100644 --- a/Python/sqrtx.py +++ b/Python/sqrtx.py @@ -1,27 +1,30 @@ # Time: O(logn) # Space: O(1) -# + # Implement int sqrt(int x). # # Compute and return the square root of x. -# -class Solution: - # @param x, an integer - # @return an integer - def sqrt(self, x): +class Solution(object): + def mySqrt(self, x): + """ + :type x: int + :rtype: int + """ if x < 2: return x - low, high = 1, x / 2 - while high >= low: - mid = low + (high - low) / 2 - if x / mid < mid: - high = mid - 1 + left, right = 1, x // 2 + while left <= right: + mid = left + (right - left) // 2 + if mid > x / mid: + right = mid - 1 else: - low = mid + 1 - return high + left = mid + 1 + + return left - 1 + if __name__ == "__main__": print Solution().sqrt(10) - \ No newline at end of file + diff --git a/Python/squirrel-simulation.py b/Python/squirrel-simulation.py new file mode 100644 index 000000000..11935ae5e --- /dev/null +++ b/Python/squirrel-simulation.py @@ -0,0 +1,22 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def minDistance(self, height, width, tree, squirrel, nuts): + """ + :type height: int + :type width: int + :type tree: List[int] + :type squirrel: List[int] + :type nuts: List[List[int]] + :rtype: int + """ + def distance(a, b): + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + + result = 0 + d = float("inf") + for nut in nuts: + result += (distance(nut, tree) * 2) + d = min(d, distance(nut, squirrel) - distance(nut, tree)) + return result + d diff --git a/Python/stickers-to-spell-word.py b/Python/stickers-to-spell-word.py new file mode 100644 index 000000000..6309f76ef --- /dev/null +++ b/Python/stickers-to-spell-word.py @@ -0,0 +1,76 @@ +# Time: O(T * S^T) +# Space: O(T * S^T) + +# We are given N different types of stickers. Each sticker has a lowercase English word on it. +# +# You would like to spell out the given target string by cutting individual letters +# from your collection of stickers and rearranging them. +# +# You can use each sticker more than once if you want, and you have infinite quantities of each sticker. +# +# What is the minimum number of stickers that you need to spell out the target? +# If the task is impossible, return -1. +# +# Example 1: +# +# Input: +# ["with", "example", "science"], "thehat" +# +# Output: +# 3 +# +# Explanation: +# We can use 2 "with" stickers, and 1 "example" sticker. +# After cutting and rearrange the letters of those stickers, we can form the target "thehat". +# Also, this is the minimum number of stickers necessary to form the target string. +# +# Example 2: +# +# Input: +# ["notice", "possible"], "basicbasic" +# +# Output: +# -1 +# +# Explanation: +# We can't form the target "basicbasic" from cutting letters from the given stickers. +# +# Note: +# - stickers has length in the range [1, 50]. +# - stickers consists of lowercase English words (without apostrophes). +# - target has length in the range [1, 15], and consists of lowercase English letters. +# - In all test cases, all words were chosen randomly from the 1000 most common US English words, +# and the target was chosen as a concatenation of two random words. +# - The time limit may be more challenging than usual. +# It is expected that a 50 sticker test case can be solved within 35ms on average. + +class Solution(object): + def minStickers(self, stickers, target): + """ + :type stickers: List[str] + :type target: str + :rtype: int + """ + def minStickersHelper(sticker_counts, target, dp): + if "".join(target) in dp: + return dp["".join(target)] + target_count = collections.Counter(target) + result = float("inf") + for sticker_count in sticker_counts: + if sticker_count[target[0]] == 0: + continue + new_target = [] + for k in target_count.keys(): + if target_count[k] > sticker_count[k]: + new_target += [k]*(target_count[k] - sticker_count[k]) + if len(new_target) != len(target): + num = minStickersHelper(sticker_counts, new_target, dp) + if num != -1: + result = min(result, 1+num) + dp["".join(target)] = -1 if result == float("inf") else result + return dp["".join(target)] + + sticker_counts = map(collections.Counter, stickers) + dp = { "":0 } + return minStickersHelper(sticker_counts, target, dp) + diff --git a/Python/strange-printer.py b/Python/strange-printer.py new file mode 100644 index 000000000..534463942 --- /dev/null +++ b/Python/strange-printer.py @@ -0,0 +1,43 @@ +# Time: O(n^3) +# Space: O(n^2) + +# There is a strange printer with the following two special requirements: +# +# The printer can only print a sequence of the same character each time. +# At each turn, the printer can print new characters starting from +# and ending at any places, and will cover the original existing characters. +# +# Given a string consists of lower English letters only, +# your job is to count the minimum number of turns the printer needed in order to print it. +# +# Example 1: +# Input: "aaabbb" +# Output: 2 +# Explanation: Print "aaa" first and then print "bbb". +# Example 2: +# Input: "aba" +# Output: 2 +# Explanation: Print "aaa" first and then print "b" from +# the second place of the string, which will cover the existing character 'a'. +# +# Hint: Length of the given string will not exceed 100. + +class Solution(object): + def strangePrinter(self, s): + """ + :type s: str + :rtype: int + """ + def dp(s, i, j, lookup): + if i > j: + return 0 + if (i, j) not in lookup: + lookup[(i, j)] = dp(s, i, j-1, lookup) + 1 + for k in xrange(i, j): + if s[k] == s[j]: + lookup[(i, j)] = min(lookup[(i, j)], \ + dp(s, i, k, lookup) + dp(s, k+1, j-1, lookup)) + return lookup[(i, j)] + + lookup = {} + return dp(s, 0, len(s)-1, lookup) diff --git a/Python/string-compression.py b/Python/string-compression.py new file mode 100644 index 000000000..cf57ce2e9 --- /dev/null +++ b/Python/string-compression.py @@ -0,0 +1,67 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of characters, compress it in-place. +# The length after compression must always be smaller than or equal to the original array. +# Every element of the array should be a character (not int) of length 1. +# After you are done modifying the input array in-place, return the new length of the array. +# +# Follow up: +# Could you solve it using only O(1) extra space? +# +# Example 1: +# Input: +# ["a","a","b","b","c","c","c"] +# +# Output: +# Return 6, and the first 6 characters of the input array should be: ["a","2","b","2","c","3"] +# +# Explanation: +# "aa" is replaced by "a2". "bb" is replaced by "b2". "ccc" is replaced by "c3". +# Example 2: +# Input: +# ["a"] +# +# Output: +# Return 1, and the first 1 characters of the input array should be: ["a"] +# +# Explanation: +# Nothing is replaced. +# Example 3: +# Input: +# ["a","b","b","b","b","b","b","b","b","b","b","b","b"] +# +# Output: +# Return 4, and the first 4 characters of the input array should be: ["a","b","1","2"]. +# +# Explanation: +# Since the character "a" does not repeat, it is not compressed. "bbbbbbbbbbbb" is replaced by "b12". +# Notice each digit has it's own entry in the array. +# Note: +# All characters have an ASCII value in [35, 126]. +# 1 <= len(chars) <= 1000. + +class Solution(object): + def compress(self, chars): + """ + :type chars: List[str] + :rtype: int + """ + anchor, write = 0, 0 + for read, c in enumerate(chars): + if read+1 == len(chars) or chars[read+1] != c: + chars[write] = chars[anchor] + write += 1 + if read > anchor: + n, left = read-anchor+1, write + while n > 0: + chars[write] = chr(n%10+ord('0')) + write += 1 + n /= 10 + right = write-1 + while left < right: + chars[left], chars[right] = chars[right], chars[left] + left += 1 + right -= 1 + anchor = read+1 + return write diff --git a/Python/string-to-integer-atoi.py b/Python/string-to-integer-atoi.py index b10431638..56b6c78e8 100644 --- a/Python/string-to-integer-atoi.py +++ b/Python/string-to-integer-atoi.py @@ -26,18 +26,21 @@ # If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned. # -class Solution: - # @return an integer - def atoi(self, str): +class Solution(object): + def myAtoi(self, str): + """ + :type str: str + :rtype: int + """ INT_MAX = 2147483647 INT_MIN = -2147483648 result = 0 - if len(str) == 0: + if not str: return result i = 0 - while i < len(str) and str[i] == " ": + while i < len(str) and str[i].isspace(): i += 1 sign = 1 @@ -47,14 +50,10 @@ def atoi(self, str): sign = -1 i += 1 - while i < len(str) and str[i] >= '0' and str[i] <= '9': - if result > INT_MAX / 10 or (result == INT_MAX / 10 and ord(str[i]) - ord('0') > INT_MAX % 10): - if sign > 0: - return INT_MAX - else: - return INT_MIN - - result = result * 10 + ord(str[i]) - ord('0') + while i < len(str) and '0' <= str[i] <= '9': + if result > (INT_MAX - int(str[i])) / 10: + return INT_MAX if sign > 0 else INT_MIN + result = result * 10 + int(str[i]) i += 1 return sign * result @@ -65,4 +64,4 @@ def atoi(self, str): print Solution().atoi("2147483647") print Solution().atoi("2147483648") print Solution().atoi("-2147483648") - print Solution().atoi("-2147483649") \ No newline at end of file + print Solution().atoi("-2147483649") diff --git a/Python/strobogrammatic-number-ii.py b/Python/strobogrammatic-number-ii.py new file mode 100644 index 000000000..da089c481 --- /dev/null +++ b/Python/strobogrammatic-number-ii.py @@ -0,0 +1,24 @@ +# Time: O(n^2 * 5^(n/2)) +# Space: O(n) + +class Solution: + lookup = {'0':'0', '1':'1', '6':'9', '8':'8', '9':'6'} + + # @param {integer} n + # @return {string[]} + def findStrobogrammatic(self, n): + return self.findStrobogrammaticRecu(n, n) + + def findStrobogrammaticRecu(self, n, k): + if k == 0: + return [''] + elif k == 1: + return ['0', '1', '8'] + + result = [] + for num in self.findStrobogrammaticRecu(n, k - 2): + for key, val in self.lookup.iteritems(): + if n != k or key != '0': + result.append(key + num + val) + + return result diff --git a/Python/strobogrammatic-number-iii.py b/Python/strobogrammatic-number-iii.py new file mode 100644 index 000000000..d45aa3d49 --- /dev/null +++ b/Python/strobogrammatic-number-iii.py @@ -0,0 +1,74 @@ +# Time: O(5^(n/2)) +# Space: O(n) + +class Solution: + lookup = {'0':'0', '1':'1', '6':'9', '8':'8', '9':'6'} + cache = {} + + # @param {string} low + # @param {string} high + # @return {integer} + def strobogrammaticInRange(self, low, high): + count = self.countStrobogrammaticUntil(high, False) - \ + self.countStrobogrammaticUntil(low, False) + \ + self.isStrobogrammatic(low) + return count if count >= 0 else 0 + + def countStrobogrammaticUntil(self, num, can_start_with_0): + if can_start_with_0 and num in self.cache: + return self.cache[num] + + count = 0 + if len(num) == 1: + for c in ['0', '1', '8']: + if num[0] >= c: + count += 1 + self.cache[num] = count + return count + + for key, val in self.lookup.iteritems(): + if can_start_with_0 or key != '0': + if num[0] > key: + if len(num) == 2: # num is like "21" + count += 1 + else: # num is like "201" + count += self.countStrobogrammaticUntil('9' * (len(num) - 2), True) + elif num[0] == key: + if len(num) == 2: # num is like 12". + if num[-1] >= val: + count += 1 + else: + if num[-1] >= val: # num is like "102". + count += self.countStrobogrammaticUntil(self.getMid(num), True); + elif (self.getMid(num) != '0' * (len(num) - 2)): # num is like "110". + count += self.countStrobogrammaticUntil(self.getMid(num), True) - \ + self.isStrobogrammatic(self.getMid(num)) + + if not can_start_with_0: # Sum up each length. + for i in xrange(len(num) - 1, 0, -1): + count += self.countStrobogrammaticByLength(i) + else: + self.cache[num] = count + + return count + + def getMid(self, num): + return num[1:len(num) - 1] + + def countStrobogrammaticByLength(self, n): + if n == 1: + return 3 + elif n == 2: + return 4 + elif n == 3: + return 4 * 3 + else: + return 5 * self.countStrobogrammaticByLength(n - 2) + + def isStrobogrammatic(self, num): + n = len(num) + for i in xrange((n+1) / 2): + if num[n-1-i] not in self.lookup or \ + num[i] != self.lookup[num[n-1-i]]: + return False + return True diff --git a/Python/strobogrammatic-number.py b/Python/strobogrammatic-number.py new file mode 100644 index 000000000..37a542b93 --- /dev/null +++ b/Python/strobogrammatic-number.py @@ -0,0 +1,16 @@ +# Time: O(n) +# Space: O(1) + +class Solution: + lookup = {'0':'0', '1':'1', '6':'9', '8':'8', '9':'6'} + + # @param {string} num + # @return {boolean} + def isStrobogrammatic(self, num): + n = len(num) + for i in xrange((n+1) / 2): + if num[n-1-i] not in self.lookup or \ + num[i] != self.lookup[num[n-1-i]]: + return False + i += 1 + return True diff --git a/Python/strong-password-checker.py b/Python/strong-password-checker.py new file mode 100644 index 000000000..90269f9fc --- /dev/null +++ b/Python/strong-password-checker.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(1) + +# A password is considered strong if below conditions are all met: +# +# It has at least 6 characters and at most 20 characters. +# It must contain at least one lowercase letter, at least one uppercase letter, +# and at least one digit. +# It must NOT contain three repeating characters in a row ("...aaa..." is weak, +# but "...aa...a..." is strong, assuming other conditions are met). +# Write a function strongPasswordChecker(s), that takes a string s as input, +# and return the MINIMUM change required to make s a strong password. If s is already strong, return 0. +# +# Insertion, deletion or replace of any one character are all considered as one change. + +class Solution(object): + def strongPasswordChecker(self, s): + """ + :type s: str + :rtype: int + """ + missing_type_cnt = 3 + if any('a' <= c <= 'z' for c in s): + missing_type_cnt -= 1 + if any('A' <= c <= 'Z' for c in s): + missing_type_cnt -= 1 + if any(c.isdigit() for c in s): + missing_type_cnt -= 1 + + total_change_cnt = 0 + one_change_cnt, two_change_cnt, three_change_cnt = 0, 0, 0 + i = 2 + while i < len(s): + if s[i] == s[i-1] == s[i-2]: + length = 2 + while i < len(s) and s[i] == s[i-1]: + length += 1 + i += 1 + + total_change_cnt += length / 3 + if length % 3 == 0: + one_change_cnt += 1 + elif length % 3 == 1: + two_change_cnt += 1 + else: + three_change_cnt += 1 + else: + i += 1 + + if len(s) < 6: + return max(missing_type_cnt, 6 - len(s)) + elif len(s) <= 20: + return max(missing_type_cnt, total_change_cnt) + else: + delete_cnt = len(s) - 20 + + total_change_cnt -= min(delete_cnt, one_change_cnt * 1) / 1 + total_change_cnt -= min(max(delete_cnt - one_change_cnt, 0), two_change_cnt * 2) / 2 + total_change_cnt -= min(max(delete_cnt - one_change_cnt - 2 * two_change_cnt, 0), three_change_cnt * 3) / 3 + + return delete_cnt + max(missing_type_cnt, total_change_cnt) diff --git a/Python/student-attendance-record-i.py b/Python/student-attendance-record-i.py new file mode 100644 index 000000000..07c836558 --- /dev/null +++ b/Python/student-attendance-record-i.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(1) + +# You are given a string representing an attendance record for a student. +# The record only contains the following three characters: +# +# 'A' : Absent. +# 'L' : Late. +# 'P' : Present. +# A student could be rewarded if his attendance record +# doesn't contain more than one 'A' (absent) or more than two continuous 'L' (late). +# +# You need to return whether the student could be rewarded according to his attendance record. +# +# Example 1: +# Input: "PPALLP" +# Output: True +# Example 2: +# Input: "PPALLL" +# Output: False + +class Solution(object): + def checkRecord(self, s): + """ + :type s: str + :rtype: bool + """ + count_A = 0 + for i in xrange(len(s)): + if s[i] == 'A': + count_A += 1 + if count_A == 2: + return False + if i < len(s) - 2 and s[i] == s[i+1] == s[i+2] == 'L': + return False + return True + diff --git a/Python/student-attendance-record-ii.py b/Python/student-attendance-record-ii.py new file mode 100644 index 000000000..2b1cc99b6 --- /dev/null +++ b/Python/student-attendance-record-ii.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(1) + +# Given a positive integer n, return the number of all possible attendance records with length n, +# which will be regarded as rewardable. The answer may be very large, return it after mod 10^9 + 7. +# +# A student attendance record is a string that only contains the following three characters: +# +# 'A' : Absent. +# 'L' : Late. +# 'P' : Present. +# A record is regarded as rewardable if it doesn't +# contain more than one 'A' (absent) or more than two continuous 'L' (late). +# +# Example 1: +# Input: n = 2 +# Output: 8 +# Explanation: +# There are 8 records with length 2 will be regarded as rewardable: +# "PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL" +# Only "AA" won't be regarded as rewardable owing to more than one absent times. +# Note: The value of n won't exceed 100,000. + +class Solution(object): + def checkRecord(self, n): + """ + :type n: int + :rtype: int + """ + M = 1000000007 + a0l0, a0l1, a0l2, a1l0, a1l1, a1l2 = 1, 0, 0, 0, 0, 0 + for i in xrange(n+1): + a0l2, a0l1, a0l0 = a0l1, a0l0, (a0l0 + a0l1 + a0l2) % M + a1l2, a1l1, a1l0 = a1l1, a1l0, (a0l0 + a1l0 + a1l1 + a1l2) % M; + return a1l0 diff --git a/Python/subarray-product-less-than-k.py b/Python/subarray-product-less-than-k.py new file mode 100644 index 000000000..3650ab757 --- /dev/null +++ b/Python/subarray-product-less-than-k.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space: O(1) + +# Your are given an array of positive integers nums. +# +# Count and print the number of (contiguous) subarrays where the product of all the elements +# in the subarray is less than k. +# +# Example 1: +# Input: nums = [10, 5, 2, 6], k = 100 +# Output: 8 +# Explanation: The 8 subarrays that have product less than 100 are: +# [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. +# Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k. +# +# Note: +# 0 < nums.length <= 50000. +# 0 < nums[i] < 1000. +# 0 <= k < 10^6. + +# Sliding window solution. +class Solution(object): + def numSubarrayProductLessThanK(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + if k <= 1: return 0 + result, start, prod = 0, 0, 1 + for i, num in enumerate(nums): + prod *= num + while prod >= k: + prod /= nums[start] + start += 1 + result += i-start+1 + return result + diff --git a/Python/subarray-sum-equals-k.py b/Python/subarray-sum-equals-k.py new file mode 100644 index 000000000..98e7d8ae0 --- /dev/null +++ b/Python/subarray-sum-equals-k.py @@ -0,0 +1,30 @@ +# Time: O(n) +# Space: O(n) + +# Given an array of integers and an integer k, +# you need to find the total number of continuous subarrays whose sum equals to k. +# +# Example 1: +# Input:nums = [1,1,1], k = 2 +# Output: 2 +# +# Note: +# The length of the array is in range [1, 20,000]. +# The range of numbers in the array is [-1000, 1000] and the range of the integer k is [-1e7, 1e7]. + +class Solution(object): + def subarraySum(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + result = 0 + accumulated_sum = 0 + lookup = collections.defaultdict(int) + lookup[0] += 1 + for num in nums: + accumulated_sum += num + result += lookup[accumulated_sum - k] + lookup[accumulated_sum] += 1 + return result diff --git a/Python/subsets-ii.py b/Python/subsets-ii.py index a22bedb27..f30e20486 100644 --- a/Python/subsets-ii.py +++ b/Python/subsets-ii.py @@ -1,6 +1,6 @@ -# Time: O(2^n) +# Time: O(n * 2^n) # Space: O(1) -# + # Given a collection of integers that might contain duplicates, S, return all possible subsets. # # Note: @@ -17,41 +17,71 @@ # [1,2], # [] # ] -# -class Solution: - # @param num, a list of integer - # @return a list of lists of integer - def subsetsWithDup(self, S): +class Solution(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + result = [[]] + previous_size = 0 + for i in xrange(len(nums)): + size = len(result) + for j in xrange(size): + # Only union non-duplicate element or new union set. + if i == 0 or nums[i] != nums[i - 1] or j >= previous_size: + result.append(list(result[j])) + result[-1].append(nums[i]) + previous_size = size + return result + + +# Time: O(n * 2^n) ~ O((n * 2^n)^2) +# Space: O(1) +class Solution2(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ result = [] - i, count = 0, 1 << len(S) - S = sorted(S) + i, count = 0, 1 << len(nums) + nums.sort() while i < count: cur = [] - for j in xrange(len(S)): + for j in xrange(len(nums)): if i & 1 << j: - cur.append(S[j]) + cur.append(nums[j]) if cur not in result: result.append(cur) i += 1 return result -class Solution2: - # @param num, a list of integer - # @return a list of lists of integer - def subsetsWithDup(self, S): + +# Time: O(n * 2^n) ~ O((n * 2^n)^2) +# Space: O(1) +class Solution3(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ result = [] - self.subsetsWithDupRecu(result, [], sorted(S)) + self.subsetsWithDupRecu(result, [], sorted(nums)) return result - def subsetsWithDupRecu(self, result, cur, S): - if len(S) == 0 and cur not in result: - result.append(cur) - elif S: - self.subsetsWithDupRecu(result, cur, S[1:]) - self.subsetsWithDupRecu(result, cur + [S[0]], S[1:]) - + def subsetsWithDupRecu(self, result, cur, nums): + if not nums: + if cur not in result: + result.append(cur) + else: + self.subsetsWithDupRecu(result, cur, nums[1:]) + self.subsetsWithDupRecu(result, cur + [nums[0]], nums[1:]) + + if __name__ == "__main__": - print Solution().subsetsWithDup([1, 2, 2]) \ No newline at end of file + print Solution().subsetsWithDup([1, 2, 2]) diff --git a/Python/subsets.py b/Python/subsets.py index 5143a2d62..113b810e7 100644 --- a/Python/subsets.py +++ b/Python/subsets.py @@ -1,6 +1,6 @@ -# Time: O(2^n) +# Time: O(n * 2^n) # Space: O(1) -# + # Given a set of distinct integers, S, return all possible subsets. # # Note: @@ -19,37 +19,62 @@ # [1,2], # [] # ] -# -class Solution: - # @param S, a list of integer - # @return a list of lists of integer - def subsets(self, S): +class Solution(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + result = [[]] + for i in xrange(len(nums)): + size = len(result) + for j in xrange(size): + result.append(list(result[j])) + result[-1].append(nums[i]) + return result + + +# Time: O(n * 2^n) +# Space: O(1) +class Solution2(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ result = [] - i, count = 0, 1 << len(S) - S = sorted(S) + i, count = 0, 1 << len(nums) + nums.sort() while i < count: cur = [] - for j in xrange(len(S)): + for j in xrange(len(nums)): if i & 1 << j: - cur.append(S[j]) + cur.append(nums[j]) result.append(cur) i += 1 return result -class Solution2: - # @param S, a list of integer - # @return a list of lists of integer - def subsets(self, S): - return self.subsetsRecu([], sorted(S)) + +# Time: O(n * 2^n) +# Space: O(1) +class Solution3(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + return self.subsetsRecu([], sorted(nums)) - def subsetsRecu(self, cur, S): - if len(S) == 0: + def subsetsRecu(self, cur, nums): + if not nums: return [cur] - return self.subsetsRecu(cur, S[1:]) + self.subsetsRecu(cur + [S[0]], S[1:]) - + return self.subsetsRecu(cur, nums[1:]) + self.subsetsRecu(cur + [nums[0]], nums[1:]) + + if __name__ == "__main__": - print Solution().subsets([1, 2, 3]) \ No newline at end of file + print Solution().subsets([1, 2, 3]) diff --git a/Python/substring-with-concatenation-of-all-words.py b/Python/substring-with-concatenation-of-all-words.py index a6aeb0d27..f1127a886 100644 --- a/Python/substring-with-concatenation-of-all-words.py +++ b/Python/substring-with-concatenation-of-all-words.py @@ -1,48 +1,94 @@ -# Time: O(m * n * k), where m is string length, n is dictionary size, k is word length - +# Time: O((m + n) * k), where m is string length, n is dictionary size, k is word length # Space: O(n * k) + +# You are given a string, s, and a list of words, words, +# that are all of the same length. Find all starting indices of substring(s) +# in s that is a concatenation of each word in words exactly once and +# without any intervening characters. # -# You are given a string, S, and a list of words, L, that are all of the same length. -# Find all starting indices of substring(s) in S that is a concatenation of each word -# in L exactly once and without any intervening characters. -# # For example, given: -# S: "barfoothefoobarman" -# L: ["foo", "bar"] -# +# s: "barfoothefoobarman" +# words: ["foo", "bar"] +# # You should return the indices: [0,9]. # (order does not matter). -# -class Solution: - # @param S, a string - # @param L, a list of string - # @return a list of integer - def findSubstring(self, S, L): - result, words, word_num, word_len = [], {}, len(L), len(L[0]) - for i in L: - if i not in words: - words[i] = 1 - else: - words[i] += 1 - - for i in xrange(len(S) + 1 - word_len * word_num): - cur, j = {}, 0 - while j < word_num: - word = S[i + j * word_len:i + j * word_len + word_len] - if word not in words: - break - if word not in cur: - cur[word] = 1 +# Sliding window solution +class Solution(object): + def findSubstring(self, s, words): + """ + :type s: str + :type words: List[str] + :rtype: List[int] + """ + result, m, n, k = [], len(s), len(words), len(words[0]) + if m < n*k: + return result + + lookup = collections.defaultdict(int) + for i in words: + lookup[i] += 1 # Space: O(n * k) + + for i in xrange(k): # Time: O(k) + left, count = i, 0 + tmp = collections.defaultdict(int) + for j in xrange(i, m-k+1, k): # Time: O(m / k) + s1 = s[j:j+k]; # Time: O(k) + if s1 in lookup: + tmp[s1] += 1 + if tmp[s1] <= lookup[s1]: + count += 1 + else: + while tmp[s1] > lookup[s1]: + s2 = s[left:left+k] + tmp[s2] -= 1 + if tmp[s2] < lookup[s2]: + count -= 1 + left += k + if count == n: + result.append(left) + tmp[s[left:left+k]] -= 1 + count -= 1 + left += k else: - cur[word] += 1 - if cur[word] > words[word]: + tmp = collections.defaultdict(int) + count = 0 + left = j+k + return result + + +# Time: O(m * n * k), where m is string length, n is dictionary size, k is word length +# Space: O(n * k) +class Solution2(object): + def findSubstring(self, s, words): + """ + :type s: str + :type words: List[str] + :rtype: List[int] + """ + result, m, n, k = [], len(s), len(words), len(words[0]) + if m < n*k: + return result + + lookup = collections.defaultdict(int) + for i in words: + lookup[i] += 1 # Space: O(n * k) + + for i in xrange(m+1-k*n): # Time: O(m) + cur, j = collections.defaultdict(int), 0 + while j < n: # Time: O(n) + word = s[i+j*k:i+j*k+k] # Time: O(k) + if word not in lookup: + break + cur[word] += 1 + if cur[word] > lookup[word]: break j += 1 - if j == word_num: + if j == n: result.append(i) return result + if __name__ == "__main__": print Solution().findSubstring("barfoothefoobarman", ["foo", "bar"]) diff --git a/Python/subtree-of-another-tree.py b/Python/subtree-of-another-tree.py new file mode 100644 index 000000000..9b0987f33 --- /dev/null +++ b/Python/subtree-of-another-tree.py @@ -0,0 +1,68 @@ +# Time: O(m * n), m is the number of nodes of s, n is the number of nodes of t +# Space: O(h), h is the height of s + +# Given two non-empty binary trees s and t, +# check whether tree t has exactly the same structure and +# node values with a subtree of s. +# A subtree of s is a tree consists of a node in s and all of this node's descendants. +# The tree s could also be considered as a subtree of itself. +# +# Example 1: +# Given tree s: +# +# 3 +# / \ +# 4 5 +# / \ +# 1 2 +# Given tree t: +# 4 +# / \ +# 1 2 +# Return true, because t has the same structure and node values with a subtree of s. +# Example 2: +# Given tree s: +# +# 3 +# / \ +# 4 5 +# / \ +# 1 2 +# / +# 0 +# Given tree t: +# 4 +# / \ +# 1 2 +# Return false. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def isSubtree(self, s, t): + """ + :type s: TreeNode + :type t: TreeNode + :rtype: bool + """ + def isSame(x, y): + if not x and not y: + return True + if not x or not y: + return False + return x.val == y.val and \ + isSame(x.left, y.left) and \ + isSame(x.right, y.right) + + def preOrderTraverse(s, t): + return s != None and \ + (isSame(s, t) or \ + preOrderTraverse(s.left, t) or \ + preOrderTraverse(s.right, t)) + + return preOrderTraverse(s, t) diff --git a/Python/sudoku-solver.py b/Python/sudoku-solver.py index ed997c11f..fff654616 100644 --- a/Python/sudoku-solver.py +++ b/Python/sudoku-solver.py @@ -13,46 +13,33 @@ class Solution: # Solve the Sudoku by modifying the input board in-place. # Do not return any value. def solveSudoku(self, board): - for i in xrange(len(board)): - for j in xrange(len(board[0])): - if(board[i][j] == '.'): - for k in xrange(9): - board[i][j] = chr(ord('1') + k) - if self.isValid(board, i, j) and self.solveSudoku(board): - return True - board[i][j] = '.' + def isValid(board, x, y): + for i in xrange(9): + if i != x and board[i][y] == board[x][y]: return False - return True - - def isValid(self, board, x, y): - for i in xrange(9): - if i != x and board[i][y] == board[x][y]: - return False - - for j in xrange(9): - if j != y and board[x][j] == board[x][y]: - return False - - i = 3 * (x / 3) - while i < 3 * (x / 3 + 1): - j = 3 * (y / 3) - while j < 3 * (y / 3 + 1): - if (i != x or j != y) and board[i][j] == board[x][y]: + for j in xrange(9): + if j != y and board[x][j] == board[x][y]: return False - j += 1 - i += 1 - - return True + i = 3 * (x / 3) + while i < 3 * (x / 3 + 1): + j = 3 * (y / 3) + while j < 3 * (y / 3 + 1): + if (i != x or j != y) and board[i][j] == board[x][y]: + return False + j += 1 + i += 1 + return True + + def solver(board): + for i in xrange(len(board)): + for j in xrange(len(board[0])): + if(board[i][j] == '.'): + for k in xrange(9): + board[i][j] = chr(ord('1') + k) + if isValid(board, i, j) and solver(board): + return True + board[i][j] = '.' + return False + return True - -if __name__ == "__main__": - board = [['5', '3', '.', '.', '7', '.', '.', '.', '.'], - ['6', '.', '.', '1', '9', '5', '.', '.', '.'], - ['.', '9', '8', '.', '.', '.', '.', '6', '.'], - ['8', '.', '.', '.', '6', '.', '.', '.', '3'], - ['4', '.', '.', '8', '.', '3', '.', '.', '1'], - ['7', '.', '.', '.', '2', '.', '.', '.', '6'], - ['.', '6', '.', '.', '.', '.', '2', '8', '.'], - ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9']] - print Solution().solveSudoku(board) + solver(board) diff --git a/Python/sum-of-left-leaves.py b/Python/sum-of-left-leaves.py new file mode 100644 index 000000000..4ca0bd5c0 --- /dev/null +++ b/Python/sum-of-left-leaves.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space: O(h) + +# Find the sum of all left leaves in a given binary tree. +# +# Example: +# +# 3 +# / \ +# 9 20 +# / \ +# 15 7 +# +# There are two left leaves in the binary tree, +# with values 9 and 15 respectively. Return 24. + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def sumOfLeftLeaves(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def sumOfLeftLeavesHelper(root, is_left): + if not root: + return 0 + if not root.left and not root.right: + return root.val if is_left else 0 + return sumOfLeftLeavesHelper(root.left, True) + \ + sumOfLeftLeavesHelper(root.right, False) + + return sumOfLeftLeavesHelper(root, False) diff --git a/Python/sum-of-square-numbers.py b/Python/sum-of-square-numbers.py new file mode 100644 index 000000000..bf1a22f24 --- /dev/null +++ b/Python/sum-of-square-numbers.py @@ -0,0 +1,25 @@ +# Time: O(sqrt(c) * logc) +# Space: O(1) + +# Given a non-negative integer c, your task is to decide +# whether there're two integers a and b such that a2 + b2 = c. +# +# Example 1: +# Input: 5 +# Output: True +# Explanation: 1 * 1 + 2 * 2 = 5 +# Example 2: +# Input: 3 +# Output: False + +class Solution(object): + def judgeSquareSum(self, c): + """ + :type c: int + :rtype: bool + """ + for a in xrange(int(math.sqrt(c))+1): + b = int(math.sqrt(c-a**2)) + if a**2 + b**2 == c: + return True + return False diff --git a/Python/sum-of-two-integers.py b/Python/sum-of-two-integers.py new file mode 100644 index 000000000..1990ef06b --- /dev/null +++ b/Python/sum-of-two-integers.py @@ -0,0 +1,77 @@ +# Time: O(1) +# Space: O(1) + +# Calculate the sum of two integers a and b, +# but you are not allowed to use the operator + and -. +# +# Example: +# Given a = 1 and b = 2, return 3. + + +class Solution(object): + def getSum(self, a, b): + """ + :type a: int + :type b: int + :rtype: int + """ + bit_length = 32 + neg_bit, mask = (1 << bit_length) >> 1, ~(~0 << bit_length) + + a = (a | ~mask) if (a & neg_bit) else (a & mask) + b = (b | ~mask) if (b & neg_bit) else (b & mask) + + while b: + carry = a & b + a ^= b + a = (a | ~mask) if (a & neg_bit) else (a & mask) + b = carry << 1 + b = (b | ~mask) if (b & neg_bit) else (b & mask) + + return a + + def getSum2(self, a, b): + """ + :type a: int + :type b: int + :rtype: int + """ + # 32 bits integer max + MAX = 0x7FFFFFFF + # 32 bits interger min + MIN = 0x80000000 + # mask to get last 32 bits + mask = 0xFFFFFFFF + while b: + # ^ get different bits and & gets double 1s, << moves carry + a, b = (a ^ b) & mask, ((a & b) << 1) & mask + # if a is negative, get a's 32 bits complement positive first + # then get 32-bit positive's Python complement negative + return a if a <= MAX else ~(a ^ mask) + + def minus(self, a, b): + b = self.getSum(~b, 1) + return self.getSum(a, b) + + def multiply(self, a, b): + isNeg = (a > 0) ^ (b > 0) + x = a if a > 0 else self.getSum(~a, 1) + y = b if b > 0 else self.getSum(~b, 1) + ans = 0 + while y & 0x01: + ans = self.getSum(ans, x) + y >>= 1 + x <<= 1 + return self.getSum(~ans, 1) if isNeg else ans + + def divide(self, a, b): + isNeg = (a > 0) ^ (b > 0) + x = a if a > 0 else self.getSum(~a, 1) + y = b if b > 0 else self.getSum(~b, 1) + ans = 0 + for i in range(31, -1, -1): + if (x >> i) >= y: + x = self.minus(x, y << i) + ans = self.getSum(ans, 1 << i) + return self.getSum(~ans, 1) if isNeg else ans + diff --git a/Python/sum-root-to-leaf-numbers.py b/Python/sum-root-to-leaf-numbers.py index 763a9faba..775c1920b 100644 --- a/Python/sum-root-to-leaf-numbers.py +++ b/Python/sum-root-to-leaf-numbers.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. # @@ -44,4 +44,4 @@ def sumNumbersRecu(self, root, num): root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) - print Solution().sumNumbers(root) \ No newline at end of file + print Solution().sumNumbers(root) diff --git a/Python/summary-ranges.py b/Python/summary-ranges.py new file mode 100644 index 000000000..f602a5282 --- /dev/null +++ b/Python/summary-ranges.py @@ -0,0 +1,40 @@ +# Time: O(n) +# Space: O(1) +# +# Given a sorted integer array without duplicates, +# return the summary of its ranges. +# +# For example, given [0,1,2,4,5,7], +# return ["0->2","4->5","7"]. +# + +class Solution: + # @param {integer[]} nums + # @return {string[]} + def summaryRanges(self, nums): + ranges = [] + if not nums: + return ranges + + start, end = nums[0], nums[0] + for i in xrange(1, len(nums) + 1): + if i < len(nums) and nums[i] == end + 1: + end = nums[i] + else: + interval = str(start) + if start != end: + interval += "->" + str(end) + ranges.append(interval) + if i < len(nums): + start = end = nums[i] + + return ranges + +# Time: O(n) +# Space: O(n) +class Solution2: + # @param {integer[]} nums + # @return {string[]} + def summaryRanges(self, nums): + return [re.sub('->.*>', '->', '->'.join(`n` for _, n in g)) + for _, g in itertools.groupby(enumerate(nums), lambda (i, n): n-i)] diff --git a/Python/super-pow.py b/Python/super-pow.py new file mode 100644 index 000000000..70caf17c8 --- /dev/null +++ b/Python/super-pow.py @@ -0,0 +1,40 @@ +# Time: O(n), n is the size of b. +# Space: O(1) + +# Your task is to calculate a^b mod 1337 where a is a positive integer +# and b is an extremely large positive integer given in the form of an array. +# +# Example1: +# +# a = 2 +# b = [3] +# +# Result: 8 +# Example2: +# +# a = 2 +# b = [1,0] +# +# Result: 1024 + +class Solution(object): + def superPow(self, a, b): + """ + :type a: int + :type b: List[int] + :rtype: int + """ + def myPow(a, n, b): + result = 1 + x = a % b + while n: + if n & 1: + result = result * x % b + n >>= 1 + x = x * x % b + return result % b + + result = 1 + for digit in b: + result = myPow(result, 10, 1337) * myPow(a, digit, 1337) % 1337 + return result diff --git a/Python/super-ugly-number.py b/Python/super-ugly-number.py new file mode 100644 index 000000000..993afd326 --- /dev/null +++ b/Python/super-ugly-number.py @@ -0,0 +1,139 @@ +# Time: O(n * logk) ~ O(n * k) +# Space: O(n + k) + +# Write a program to find the nth super ugly number. +# +# Super ugly numbers are positive numbers whose all +# prime factors are in the given prime list primes of size k. +# For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] +# is the sequence of the first 12 super ugly numbers given +# primes = [2, 7, 13, 19] of size 4. +# +# Note: +# (1) 1 is a super ugly number for any given primes. +# (2) The given numbers in primes are in ascending order. +# (3) 0 < k <= 100, 0 < n <= 106, 0 < primes[i] < 1000. + +# Heap solution. (620ms) +class Solution(object): + def nthSuperUglyNumber(self, n, primes): + """ + :type n: int + :type primes: List[int] + :rtype: int + """ + heap, uglies, idx, ugly_by_last_prime = [], [0] * n, [0] * len(primes), [0] * n + uglies[0] = 1 + + for k, p in enumerate(primes): + heapq.heappush(heap, (p, k)) + + for i in xrange(1, n): + uglies[i], k = heapq.heappop(heap) + ugly_by_last_prime[i] = k + idx[k] += 1 + while ugly_by_last_prime[idx[k]] > k: + idx[k] += 1 + heapq.heappush(heap, (primes[k] * uglies[idx[k]], k)) + + return uglies[-1] + +# Time: O(n * k) +# Space: O(n + k) +# Hash solution. (932ms) +class Solution2(object): + def nthSuperUglyNumber(self, n, primes): + """ + :type n: int + :type primes: List[int] + :rtype: int + """ + uglies, idx, heap, ugly_set = [0] * n, [0] * len(primes), [], set([1]) + uglies[0] = 1 + + for k, p in enumerate(primes): + heapq.heappush(heap, (p, k)) + ugly_set.add(p) + + for i in xrange(1, n): + uglies[i], k = heapq.heappop(heap) + while (primes[k] * uglies[idx[k]]) in ugly_set: + idx[k] += 1 + heapq.heappush(heap, (primes[k] * uglies[idx[k]], k)) + ugly_set.add(primes[k] * uglies[idx[k]]) + + return uglies[-1] + +# Time: O(n * logk) ~ O(n * klogk) +# Space: O(n + k) +class Solution3(object): + def nthSuperUglyNumber(self, n, primes): + """ + :type n: int + :type primes: List[int] + :rtype: int + """ + uglies, idx, heap = [1], [0] * len(primes), [] + for k, p in enumerate(primes): + heapq.heappush(heap, (p, k)) + + for i in xrange(1, n): + min_val, k = heap[0] + uglies += [min_val] + + while heap[0][0] == min_val: # worst time: O(klogk) + min_val, k = heapq.heappop(heap) + idx[k] += 1 + heapq.heappush(heap, (primes[k] * uglies[idx[k]], k)) + + return uglies[-1] + +# Time: O(n * k) +# Space: O(n + k) +# TLE due to the last test case, but it passess and performs the best in C++. +class Solution4(object): + def nthSuperUglyNumber(self, n, primes): + """ + :type n: int + :type primes: List[int] + :rtype: int + """ + uglies = [0] * n + uglies[0] = 1 + ugly_by_prime = list(primes) + idx = [0] * len(primes) + + for i in xrange(1, n): + uglies[i] = min(ugly_by_prime) + for k in xrange(len(primes)): + if uglies[i] == ugly_by_prime[k]: + idx[k] += 1 + ugly_by_prime[k] = primes[k] * uglies[idx[k]] + + return uglies[-1] + +# Time: O(n * logk) ~ O(n * klogk) +# Space: O(k^2) +# TLE due to the last test case, but it passess and performs well in C++. +class Solution5(object): + def nthSuperUglyNumber(self, n, primes): + """ + :type n: int + :type primes: List[int] + :rtype: int + """ + ugly_number = 0 + + heap = [] + heapq.heappush(heap, 1) + for p in primes: + heapq.heappush(heap, p) + for _ in xrange(n): + ugly_number = heapq.heappop(heap) + for i in xrange(len(primes)): + if ugly_number % primes[i] == 0: + for j in xrange(i + 1): + heapq.heappush(heap, ugly_number * primes[j]) + break + + return ugly_number diff --git a/Python/super-washing-machines.py b/Python/super-washing-machines.py new file mode 100644 index 000000000..1db926366 --- /dev/null +++ b/Python/super-washing-machines.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(1) + +# You have n super washing machines on a line. +# Initially, each washing machine has some dresses or is empty. +# +# For each move, you could choose any m (1 <= m <= n) washing machines, +# and pass one dress of each washing machine to one of +# its adjacent washing machines at the same time . +# +# Given an integer array representing the number of dresses +# in each washing machine from left to right on the line, +# you should find the minimum number of moves to make +# all the washing machines have the same number of dresses. +# If it is not possible to do it, return -1. +# +# Example1 +# +# Input: [1,0,5] +# +# Output: 3 +# +# Explanation: +# 1st move: 1 0 <-- 5 => 1 1 4 +# 2nd move: 1 <-- 1 <-- 4 => 2 1 3 +# 3rd move: 2 1 <-- 3 => 2 2 2 +# Example2 +# +# Input: [0,3,0] +# +# Output: 2 +# +# Explanation: +# 1st move: 0 <-- 3 0 => 1 2 0 +# 2nd move: 1 2 --> 0 => 1 1 1 +# Example3 +# +# Input: [0,2,0] +# +# Output: -1 +# +# Explanation: +# It's impossible to make all the three washing machines have the same number of dresses. +# Note: +# The range of n is [1, 10000]. +# The range of dresses number in a super washing machine is [0, 1e5]. + +class Solution(object): + def findMinMoves(self, machines): + """ + :type machines: List[int] + :rtype: int + """ + total = sum(machines) + if total % len(machines): return -1 + + result, target, curr = 0, total / len(machines), 0 + for n in machines: + curr += n - target + result = max(result, max(n - target, abs(curr))) + return result diff --git a/Python/surrounded-region.py b/Python/surrounded-regions.py similarity index 73% rename from Python/surrounded-region.py rename to Python/surrounded-regions.py index a16bbee0b..98e7a65ad 100644 --- a/Python/surrounded-region.py +++ b/Python/surrounded-regions.py @@ -23,29 +23,30 @@ class Solution: # Capture all regions by modifying the input board in-place. # Do not return any value. def solve(self, board): - if len(board) == 0: + if not board: return - current = [] + q = collections.deque([]) for i in xrange(len(board)): - current.append((i, 0)) - current.append((i, len(board[0]) - 1)) + q.append((i, 0)) + q.append((i, len(board[0]) - 1)) - for i in xrange(len(board[0])): - current.append((0, i)) - current.append((len(board) - 1, i)) + for j in xrange(len(board[0])): + q.append((0, j)) + q.append((len(board) - 1, j)) - while current: - i, j = current.pop() + while q: + i, j = q.popleft() if board[i][j] in ['O', 'V']: board[i][j] = 'V' for x, y in [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]: - if 0 <= x < len(board) and 0 <= y < len(board[0]) and board[x][y] == 'O': + if 0 <= x < len(board) and 0 <= y < len(board[0]) and \ + board[x][y] == 'O': board[x][y] = 'V' - current.append((x, y)) + q.append((x, y)) for i in xrange(len(board)): - for j in range(len(board[0])): + for j in xrange(len(board[0])): if board[i][j] != 'V': board[i][j] = 'X' else: @@ -57,4 +58,4 @@ def solve(self, board): ['X', 'X', 'O', 'X'], ['X', 'O', 'X', 'X']] Solution().solve(board) - print board \ No newline at end of file + print board diff --git a/Python/symmetric-tree.py b/Python/symmetric-tree.py index 6b2a1c991..709864217 100644 --- a/Python/symmetric-tree.py +++ b/Python/symmetric-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). # # For example, this binary tree is symmetric: @@ -77,4 +77,4 @@ def isSymmetricRecu(self, left, right): root.left.left, root.right.right = TreeNode(3), TreeNode(3) root.left.right, root.right.left = TreeNode(4), TreeNode(4) print Solution().isSymmetric(root) - \ No newline at end of file + diff --git a/Python/tag-validator.py b/Python/tag-validator.py new file mode 100644 index 000000000..25946efa0 --- /dev/null +++ b/Python/tag-validator.py @@ -0,0 +1,133 @@ +# Time: O(n) +# Space: O(n) + +# Given a string representing a code snippet, +# you need to implement a tag validator to parse the code and return whether it is valid. +# A code snippet is valid if all the following rules hold: +# +# 1. The code must be wrapped in a valid closed tag. Otherwise, the code is invalid. +# 2. A closed tag (not necessarily valid) has exactly the following format : +# TAG_CONTENT. Among them, is the start tag, +# and is the end tag. The TAG_NAME in start and end tags should be the same. +# A closed tag is valid if and only if the TAG_NAME and TAG_CONTENT are valid. +# 3. A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. +# Otherwise, the TAG_NAME is invalid. +# 4. A valid TAG_CONTENT may contain other valid closed tags, +# cdata and any characters (see note1) EXCEPT unmatched <, +# unmatched start and end tag, and unmatched or closed tags with invalid TAG_NAME. +# Otherwise, the TAG_CONTENT is invalid. +# 5. A start tag is unmatched if no end tag exists with the same TAG_NAME, +# and vice versa. However, you also need to consider the issue of unbalanced when tags are nested. +# 6. A < is unmatched if you cannot find a subsequent >. +# And when you find a < or should be +# parsed as TAG_NAME (not necessarily valid). +# 7. The cdata has the following format : . +# The range of CDATA_CONTENT is defined as the characters between . +# 8. CDATA_CONTENT may contain any characters. +# The function of cdata is to forbid the validator to parse CDATA_CONTENT, +# so even it has some characters that can be parsed as tag (no matter valid or invalid), +# you should treat it as regular characters. +# +# Valid Code Examples: +# Input: "

This is the first line ]]>
" +# Output: True +# Explanation: +# The code is wrapped in a closed tag :
and
. +# The TAG_NAME is valid, the TAG_CONTENT consists of some characters and cdata. +# Although CDATA_CONTENT has unmatched start tag with invalid TAG_NAME, +# it should be considered as plain text, not parsed as tag. +# So TAG_CONTENT is valid, and then the code is valid. Thus return true. +# +# Input: "
>> ![cdata[]] ]>]]>]]>>]
" +# Output: True +# Explanation: +# We first separate the code into : start_tag|tag_content|end_tag. +# start_tag -> "
" +# end_tag -> "
" +# tag_content could also be separated into : text1|cdata|text2. +# text1 -> ">> ![cdata[]] " +# cdata -> "]>]]>", where the CDATA_CONTENT is "
]>" +# text2 -> "]]>>]" +# +# The reason why start_tag is NOT "
>>" is because of the rule 6. +# The reason why cdata is NOT "]>]]>]]>" is because of the rule 7. +# Invalid Code Examples: +# Input: " " +# Output: False +# Explanation: Unbalanced. If "" is closed, then "" must be unmatched, and vice versa. +# +# Input: "
div tag is not closed
" +# Output: False +# +# Input: "
unmatched <
" +# Output: False +# +# Input: "
closed tags with invalid tag name 123
" +# Output: False +# +# Input: "
unmatched tags with invalid tag name and
" +# Output: False +# +# Input: "
unmatched start tag and unmatched end tag
" +# Output: False +# Note: +# For simplicity, you could assume the input code (including the any characters mentioned above) +# only contain letters, digits, '<','>','/','!','[',']' and ' '. + +class Solution(object): + def isValid(self, code): + """ + :type code: str + :rtype: bool + """ + def validText(s, i): + j = i + i = s.find("<", i) + return i != j, i + + def validCData(s, i): + if s.find("", i) + if j == -1: + return False, i + return True, j+3 + + def parseTagName(s, i): + if s[i] != '<': + return "", i + j = s.find('>', i) + if j == -1 or not (1 <= (j-1-i) <= 9): + return "", i + tag = s[i+1:j] + for c in tag: + if not (ord('A') <= ord(c) <= ord('Z')): + return "", i + return tag, j+1 + + def parseContent(s, i): + while i < len(s): + result, i = validText(s, i) + if result: + continue + result, i = validCData(s, i) + if result: + continue + result, i = validTag(s, i) + if result: + continue + break + return i + + def validTag(s, i): + tag, j = parseTagName(s, i) + if not tag: + return False, i + j = parseContent(s, j) + k = j + len(tag) + 2 + if k >= len(s) or s[j:k+1] != "": + return False, i + return True, k+1 + + result, i = validTag(code, 0) + return result and i == len(code) diff --git a/Python/target-sum.py b/Python/target-sum.py new file mode 100644 index 000000000..602767865 --- /dev/null +++ b/Python/target-sum.py @@ -0,0 +1,46 @@ +# Time: O(n * S) +# Space: O(S) + +# You are given a list of non-negative integers, a1, a2, ..., an, +# and a target, S. Now you have 2 symbols + and -. +# For each integer, you should choose one from + and - as its new symbol. +# +# Find out how many ways to assign symbols to make sum of integers equal to target S. +# +# Example 1: +# Input: nums is [1, 1, 1, 1, 1], S is 3. +# Output: 5 +# Explanation: +# +# -1+1+1+1+1 = 3 +# +1-1+1+1+1 = 3 +# +1+1-1+1+1 = 3 +# +1+1+1-1+1 = 3 +# +1+1+1+1-1 = 3 +# +# There are 5 ways to assign symbols to make the sum of nums be target 3. +# Note: +# The length of the given array is positive and will not exceed 20. +# The sum of elements in the given array will not exceed 1000. +# Your output answer is guaranteed to be fitted in a 32-bit integer. + +class Solution(object): + def findTargetSumWays(self, nums, S): + """ + :type nums: List[int] + :type S: int + :rtype: int + """ + def subsetSum(nums, S): + dp = collections.defaultdict(int) + dp[0] = 1 + for n in nums: + for i in reversed(xrange(n, S+1)): + if i-n in dp: + dp[i] += dp[i-n] + return dp[S] + + total = sum(nums) + if total < S or (S + total) % 2: return 0 + P = (S + total) // 2 + return subsetSum(nums, P) diff --git a/Python/task-scheduler.py b/Python/task-scheduler.py new file mode 100644 index 000000000..4ee3eacc2 --- /dev/null +++ b/Python/task-scheduler.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(26) = O(1) + +# Given a char array representing tasks CPU need to do. +# It contains capital letters A to Z where different letters represent +# different tasks.Tasks could be done without original order. +# Each task could be done in one interval. +# For each interval, CPU could finish one task or just be idle. +# +# However, there is a non-negative cooling interval n that +# means between two same tasks, there must be at least n intervals that +# CPU are doing different tasks or just be idle. +# +# You need to return the least number of intervals the CPU +# will take to finish all the given tasks. +# +# Example 1: +# Input: tasks = ['A','A','A','B','B','B'], n = 2 +# Output: 8 +# Explanation: A -> B -> idle -> A -> B -> idle -> A -> B. +# Note: +# The number of tasks is in the range [1, 10000]. +# The integer n is in the range [0, 100]. + +class Solution(object): + def leastInterval(self, tasks, n): + """ + :type tasks: List[str] + :type n: int + :rtype: int + """ + count = collections.defaultdict(int) + max_count = 0 + for task in tasks: + count[task] += 1 + max_count = max(max_count, count[task]) + + result = (max_count-1) * (n+1) + for count in count.values(): + if count == max_count: + result += 1 + return max(result, len(tasks)) diff --git a/Python/teemo-attacking.py b/Python/teemo-attacking.py new file mode 100644 index 000000000..4ae1d8435 --- /dev/null +++ b/Python/teemo-attacking.py @@ -0,0 +1,42 @@ +# Time: O(n) +# Space: O(1) + +# In LLP world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned condition. +# Now, given the Teemo's attacking ascending time series towards Ashe and +# the poisoning time duration per Teemo's attacking, you need to output the total time that Ashe is in poisoned condition. +# +# You may assume that Teemo attacks at the very beginning of a specific time point, +# and makes Ashe be in poisoned condition immediately. +# +# Example 1: +# Input: [1,4], 2 +# Output: 4 +# Explanation: At time point 1, Teemo starts attacking Ashe and makes Ashe be poisoned immediately. +# This poisoned status will last 2 seconds until the end of time point 2. +# And at time point 4, Teemo attacks Ashe again, and causes Ashe to be in poisoned status for another 2 seconds. +# So you finally need to output 4. +# Example 2: +# Input: [1,2], 2 +# Output: 3 +# Explanation: At time point 1, Teemo starts attacking Ashe and makes Ashe be poisoned. +# This poisoned status will last 2 seconds until the end of time point 2. +# However, at the beginning of time point 2, Teemo attacks Ashe again who is already in poisoned status. +# Since the poisoned status won't add up together, though the second poisoning attack will still work at time point 2, +# it will stop at the end of time point 3. +# So you finally need to output 3. +# Note: +# You may assume the length of given time series array won't exceed 10000. +# You may assume the numbers in the Teemo's attacking time series and his poisoning time +# duration per attacking are non-negative integers, which won't exceed 10,000,000. + +class Solution(object): + def findPoisonedDuration(self, timeSeries, duration): + """ + :type timeSeries: List[int] + :type duration: int + :rtype: int + """ + result = duration * len(timeSeries) + for i in xrange(1, len(timeSeries)): + result -= max(0, duration - (timeSeries[i] - timeSeries[i-1])) + return result diff --git a/Python/ternary-expression-parser.py b/Python/ternary-expression-parser.py new file mode 100644 index 000000000..f8928be3e --- /dev/null +++ b/Python/ternary-expression-parser.py @@ -0,0 +1,29 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def parseTernary(self, expression): + """ + :type expression: str + :rtype: str + """ + if not expression: + return "" + + stack = [] + for c in expression[::-1]: + if stack and stack[-1] == '?': + stack.pop() # pop '?' + first = stack.pop() + stack.pop() # pop ':' + second = stack.pop() + + if c == 'T': + stack.append(first) + else: + stack.append(second) + else: + stack.append(c) + + + return str(stack[-1]) diff --git a/Python/text-justification.py b/Python/text-justification.py index c1a18d1e9..b292c30f7 100644 --- a/Python/text-justification.py +++ b/Python/text-justification.py @@ -1,15 +1,19 @@ # Time: O(n) -# Space: O(1) +# Space: O(k), k is maxWidth. # -# Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified. +# Given an array of words and a length L, format the text such that +# each line has exactly L characters and is fully (left and right) justified. # -# You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' +# You should pack your words in a greedy approach; that is, pack +# as many words as you can in each line. Pad extra spaces ' ' # when necessary so that each line has exactly L characters. # # Extra spaces between words should be distributed as evenly as possible. -# If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right. +# If the number of spaces on a line do not divide evenly between words, +# the empty slots on the left will be assigned more spaces than the slots on the right. # -# For the last line of text, it should be left justified and no extra space is inserted between words. +# For the last line of text, it should be left justified and no extra space +# is inserted between words. # # For example, # words: ["This", "is", "an", "example", "of", "text", "justification."] @@ -23,52 +27,44 @@ # ] # Note: Each word is guaranteed not to exceed L in length. -class Solution: - # @param words, a list of strings - # @param L, an integer - # @return a list of strings - def fullJustify(self, words, L): - result = [] - - i = 0 - while i < len(words): - # count words in one line - size, begin = 0, i - while i < len(words): - if size == 0: - newsize = len(words[i]) - else: - newsize = size + len(words[i]) + 1 - if newsize <= L: - size = newsize - else: - break - i += 1 - - # count space number - spaceCount = L - size - if i - begin - 1 > 0 and i < len(words): - everyCount = spaceCount / (i - begin - 1) - spaceCount %= i - begin - 1 - else: - everyCount = 0 - - # add space - j = begin - while j < i: - if j == begin: - s = words[j] - else: - s += ' ' * (everyCount + 1) - if spaceCount > 0 and i < len(words): - s += ' ' - spaceCount -= 1 - s += words[j] - j += 1 - s += ' ' * spaceCount - result.append(s) - - return result +class Solution(object): + def fullJustify(self, words, maxWidth): + """ + :type words: List[str] + :type maxWidth: int + :rtype: List[str] + """ + def addSpaces(i, spaceCnt, maxWidth, is_last): + if i < spaceCnt: + # For the last line of text, it should be left justified, + # and no extra space is inserted between words. + return 1 if is_last else (maxWidth // spaceCnt) + int(i < maxWidth % spaceCnt) + return 0 + + def connect(words, maxWidth, begin, end, length, is_last): + s = [] # The extra space O(k) is spent here. + n = end - begin + for i in xrange(n): + s += words[begin + i], + s += ' ' * addSpaces(i, n - 1, maxWidth - length, is_last), + # For only one word in a line. + line = "".join(s) + if len(line) < maxWidth: + line += ' ' * (maxWidth - len(line)) + return line + + res = [] + begin, length = 0, 0 + for i in xrange(len(words)): + if length + len(words[i]) + (i - begin) > maxWidth: + res += connect(words, maxWidth, begin, i, length, False), + begin, length = i, 0 + length += len(words[i]) + + # Last line. + res += connect(words, maxWidth, begin, len(words), length, True), + return res + if __name__ == "__main__": print Solution().fullJustify(["This", "is", "an", "example", "of", "text", "justification."], 16) diff --git a/Python/the-maze-ii.py b/Python/the-maze-ii.py new file mode 100644 index 000000000..534ad0925 --- /dev/null +++ b/Python/the-maze-ii.py @@ -0,0 +1,36 @@ +# Time: O(max(r, c) * wlogw) +# Space: O(w) + +class Solution(object): + def shortestDistance(self, maze, start, destination): + """ + :type maze: List[List[int]] + :type start: List[int] + :type destination: List[int] + :rtype: int + """ + start, destination = tuple(start), tuple(destination) + + def neighbors(maze, node): + for dir in [(-1, 0), (0, 1), (0, -1), (1, 0)]: + cur_node, dist = list(node), 0 + while 0 <= cur_node[0]+dir[0] < len(maze) and \ + 0 <= cur_node[1]+dir[1] < len(maze[0]) and \ + not maze[cur_node[0]+dir[0]][cur_node[1]+dir[1]]: + cur_node[0] += dir[0] + cur_node[1] += dir[1] + dist += 1 + yield dist, tuple(cur_node) + + heap = [(0, start)] + visited = set() + while heap: + dist, node = heapq.heappop(heap) + if node in visited: continue + if node == destination: + return dist + visited.add(node) + for neighbor_dist, neighbor in neighbors(maze, node): + heapq.heappush(heap, (dist+neighbor_dist, neighbor)) + + return -1 diff --git a/Python/the-maze-iii.py b/Python/the-maze-iii.py new file mode 100644 index 000000000..02be0681a --- /dev/null +++ b/Python/the-maze-iii.py @@ -0,0 +1,38 @@ +# Time: O(max(r, c) * wlogw) +# Space: O(w^2) + +class Solution(object): + def findShortestWay(self, maze, ball, hole): + """ + :type maze: List[List[int]] + :type ball: List[int] + :type hole: List[int] + :rtype: str + """ + ball, hole = tuple(ball), tuple(hole) + dirs = {'u' : (-1, 0), 'r' : (0, 1), 'l' : (0, -1), 'd': (1, 0)} + + def neighbors(maze, node): + for dir, vec in dirs.iteritems(): + cur_node, dist = list(node), 0 + while 0 <= cur_node[0]+vec[0] < len(maze) and \ + 0 <= cur_node[1]+vec[1] < len(maze[0]) and \ + not maze[cur_node[0]+vec[0]][cur_node[1]+vec[1]]: + cur_node[0] += vec[0] + cur_node[1] += vec[1] + dist += 1 + if tuple(cur_node) == hole: + break + yield tuple(cur_node), dir, dist + + heap = [(0, '', ball)] + visited = set() + while heap: + dist, path, node = heapq.heappop(heap) + if node in visited: continue + if node == hole: return path + visited.add(node) + for neighbor, dir, neighbor_dist in neighbors(maze, node): + heapq.heappush(heap, (dist+neighbor_dist, path+dir, neighbor)) + + return "impossible" diff --git a/Python/the-maze.py b/Python/the-maze.py new file mode 100644 index 000000000..573eeebd4 --- /dev/null +++ b/Python/the-maze.py @@ -0,0 +1,36 @@ +# Time: O(max(r, c) * w) +# Space: O(w) + +class Solution(object): + def hasPath(self, maze, start, destination): + """ + :type maze: List[List[int]] + :type start: List[int] + :type destination: List[int] + :rtype: bool + """ + start, destination = tuple(start), tuple(destination) + + def neighbors(maze, node): + for dir in [(-1, 0), (0, 1), (0, -1), (1, 0)]: + cur_node, dist = list(node), 0 + while 0 <= cur_node[0]+dir[0] < len(maze) and \ + 0 <= cur_node[1]+dir[1] < len(maze[0]) and \ + not maze[cur_node[0]+dir[0]][cur_node[1]+dir[1]]: + cur_node[0] += dir[0] + cur_node[1] += dir[1] + dist += 1 + yield dist, tuple(cur_node) + + queue = collections.deque([(0, start)]) + visited = set() + while queue: + dist, node = queue.popleft() + if node in visited: continue + if node == destination: + return True + visited.add(node) + for neighbor_dist, neighbor in neighbors(maze, node): + queue.append((dist+neighbor_dist, neighbor)) + + return False diff --git a/Python/the-skyline-problem.py b/Python/the-skyline-problem.py new file mode 100644 index 000000000..d7e17a89c --- /dev/null +++ b/Python/the-skyline-problem.py @@ -0,0 +1,115 @@ +# Time: O(nlogn) +# Space: O(n) +# +# A city's skyline is the outer contour of the silhouette formed +# by all the buildings in that city when viewed from a distance. +# Now suppose you are given the locations and height of all the +# buildings as shown on a cityscape photo (Figure A), write a +# program to output the skyline formed by these buildings +# collectively (Figure B). +# +# The geometric information of each building is represented by a +# triplet of integers [Li, Ri, Hi], where Li and Ri are the x +# coordinates of the left and right edge of the ith building, +# respectively, and Hi is its height. It is guaranteed that 0 <= Li, +# Ri <= INT_MAX, 0 < Hi <= INT_MAX, and Ri - Li > 0. You may assume +# all buildings are perfect rectangles grounded on an absolutely +# flat surface at height 0. +# +# Notes: +# +# The number of buildings in any input list is guaranteed to be +# in the range [0, 10000]. +# The input list is already sorted in ascending order by the +# left x position Li. +# The output list must be sorted by the x position. +# There must be no consecutive horizontal lines of equal height +# in the output skyline. +# For instance, [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is +# not acceptable; +# the three lines of height 5 should be merged into one +# in the final output as such: [...[2 3], [4 5], [12 7], ...] +# + +# Divide and conquer solution. +start, end, height = 0, 1, 2 +class Solution: + # @param {integer[][]} buildings + # @return {integer[][]} + def getSkyline(self, buildings): + intervals = self.ComputeSkylineInInterval(buildings, 0, len(buildings)) + + res = [] + last_end = -1 + for interval in intervals: + if last_end != -1 and last_end < interval[start]: + res.append([last_end, 0]) + res.append([interval[start], interval[height]]) + last_end = interval[end] + if last_end != -1: + res.append([last_end, 0]) + + return res + + # Divide and Conquer. + def ComputeSkylineInInterval(self, buildings, left_endpoint, right_endpoint): + if right_endpoint - left_endpoint <= 1: + return buildings[left_endpoint:right_endpoint] + mid = left_endpoint + ((right_endpoint - left_endpoint) / 2) + left_skyline = self.ComputeSkylineInInterval(buildings, left_endpoint, mid) + right_skyline = self.ComputeSkylineInInterval(buildings, mid, right_endpoint) + return self.MergeSkylines(left_skyline, right_skyline) + + # Merge Sort. + def MergeSkylines(self, left_skyline, right_skyline): + i, j = 0, 0 + merged = [] + + while i < len(left_skyline) and j < len(right_skyline): + if left_skyline[i][end] < right_skyline[j][start]: + merged.append(left_skyline[i]) + i += 1 + elif right_skyline[j][end] < left_skyline[i][start]: + merged.append(right_skyline[j]) + j += 1 + elif left_skyline[i][start] <= right_skyline[j][start]: + i, j = self.MergeIntersectSkylines(merged, left_skyline[i], i,\ + right_skyline[j], j) + else: # left_skyline[i][start] > right_skyline[j][start]. + j, i = self.MergeIntersectSkylines(merged, right_skyline[j], j, \ + left_skyline[i], i) + + # Insert the remaining skylines. + merged += left_skyline[i:] + merged += right_skyline[j:] + return merged + + # a[start] <= b[start] + def MergeIntersectSkylines(self, merged, a, a_idx, b, b_idx): + if a[end] <= b[end]: + if a[height] > b[height]: # |aaa| + if b[end] != a[end]: # |abb|b + b[start] = a[end] + merged.append(a) + a_idx += 1 + else: # aaa + b_idx += 1 # abb + elif a[height] == b[height]: # abb + b[start] = a[start] # abb + a_idx += 1 + else: # a[height] < b[height]. + if a[start] != b[start]: # bb + merged.append([a[start], b[start], a[height]]) # |a|bb + a_idx += 1 + else: # a[end] > b[end]. + if a[height] >= b[height]: # aaaa + b_idx += 1 # abba + else: + # |bb| + # |a||bb|a + if a[start] != b[start]: + merged.append([a[start], b[start], a[height]]) + a[start] = b[end] + merged.append(b) + b_idx += 1 + return a_idx, b_idx diff --git a/Python/third-maximum-number.py b/Python/third-maximum-number.py new file mode 100644 index 000000000..ec9e2152f --- /dev/null +++ b/Python/third-maximum-number.py @@ -0,0 +1,30 @@ +# Time: O(n) +# Space: O(1) + +# Given an array of integers, return the 3rd Maximum Number in this array, +# if it doesn't exist, return the Maximum Number. +# The time complexity must be O(n) or less. + +class Solution(object): + def thirdMax(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + count = 0 + top = [float("-inf")] * 3 + for num in nums: + if num > top[0]: + top[0], top[1], top[2] = num, top[0], top[1] + count += 1 + elif num != top[0] and num > top[1]: + top[1], top[2] = num, top[1] + count += 1 + elif num != top[0] and num != top[1] and num >= top[2]: + top[2] = num + count += 1 + + if count < 3: + return top[0] + + return top[2] diff --git a/Python/top-k-frequent-elements.py b/Python/top-k-frequent-elements.py new file mode 100644 index 000000000..dd08c34ff --- /dev/null +++ b/Python/top-k-frequent-elements.py @@ -0,0 +1,96 @@ +# Time: O(n) +# Space: O(n) + +# Given a non-empty array of integers, +# return the k most frequent elements. +# +# For example, +# Given [1,1,1,2,2,3] and k = 2, return [1,2]. +# +# Note: +# You may assume k is always valid, +# 1 <= k <= number of unique elements. +# Your algorithm's time complexity must be better +# than O(n log n), where n is the array's size. + +# Bucket Sort Solution +class Solution(object): + def topKFrequent(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + counts = collections.Counter(words) + buckets = [[] for _ in xrange(len(nums)+1)] + for i, count in counts.iteritems(): + buckets[count].append(i) + + result = [] + for i in reversed(xrange(len(buckets))): + for j in xrange(len(buckets[i])): + result.append(buckets[i][j]) + if len(result) == k: + return result + return result + + +# Time: O(n) ~ O(n^2), O(n) on average. +# Space: O(n) +# Quick Select Solution +from random import randint +class Solution2(object): + def topKFrequent(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + counts = collections.Counter(words) + p = [] + for key, val in counts.iteritems(): + p.append((-val, key)) + self.kthElement(p, k); + + result = [] + for i in xrange(k): + result.append(p[i][1]) + return result + + + def kthElement(self, nums, k): + def PartitionAroundPivot(left, right, pivot_idx, nums): + pivot_value = nums[pivot_idx] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i] < pivot_value: + nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] + new_pivot_idx += 1 + + nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] + return new_pivot_idx + + left, right = 0, len(nums) - 1 + while left <= right: + pivot_idx = randint(left, right) + new_pivot_idx = PartitionAroundPivot(left, right, pivot_idx, nums) + if new_pivot_idx == k - 1: + return + elif new_pivot_idx > k - 1: + right = new_pivot_idx - 1 + else: # new_pivot_idx < k - 1. + left = new_pivot_idx + 1 + + +# Time: O(nlogk) +# Space: O(n) +class Solution3(object): + def topKFrequent(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + return [key for key, _ in collections.Counter(nums).most_common(k)] + diff --git a/Python/top-k-frequent-words.py b/Python/top-k-frequent-words.py new file mode 100644 index 000000000..d88d416bd --- /dev/null +++ b/Python/top-k-frequent-words.py @@ -0,0 +1,125 @@ +# Time: O(n + klogk) on average +# Space: O(n) + +# Given a non-empty list of words, return the k most frequent elements. +# +# Your answer should be sorted by frequency from highest to lowest. +# If two words have the same frequency, then the word with the lower alphabetical order comes first. +# +# Example 1: +# Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2 +# Output: ["i", "love"] +# Explanation: "i" and "love" are the two most frequent words. +# Note that "i" comes before "love" due to a lower alphabetical order. +# Example 2: +# Input: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4 +# Output: ["the", "is", "sunny", "day"] +# Explanation: "the", "is", "sunny" and "day" are the four most frequent words, +# with the number of occurrence being 4, 3, 2 and 1 respectively. +# Note: +# You may assume k is always valid, 1 ≤ k ≤ number of unique elements. +# Input words contain only lowercase letters. +# +# Follow up: +# Try to solve it in O(n log k) time and O(n) extra space. +# Can you solve it in O(n) time with only O(k) extra space? + +# Quick Select Solution +from random import randint +class Solution(object): + def topKFrequent(self, words, k): + """ + :type words: List[str] + :type k: int + :rtype: List[str] + """ + counts = collections.Counter(words) + p = [] + for key, val in counts.iteritems(): + p.append((-val, key)) + self.kthElement(p, k); + + result = [] + sorted_p = sorted(p[:k]) + for i in xrange(k): + result.append(sorted_p[i][1]) + return result + + + def kthElement(self, nums, k): # O(n) on average + def PartitionAroundPivot(left, right, pivot_idx, nums): + pivot_value = nums[pivot_idx] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i] < pivot_value: + nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] + new_pivot_idx += 1 + + nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] + return new_pivot_idx + + left, right = 0, len(nums) - 1 + while left <= right: + pivot_idx = randint(left, right) + new_pivot_idx = PartitionAroundPivot(left, right, pivot_idx, nums) + if new_pivot_idx == k - 1: + return + elif new_pivot_idx > k - 1: + right = new_pivot_idx - 1 + else: # new_pivot_idx < k - 1. + left = new_pivot_idx + 1 + + +# Time: O(nlogk) +# Space: O(n) +# Heap Solution +class Solution2(object): + def topKFrequent(self, words, k): + """ + :type words: List[str] + :type k: int + :rtype: List[str] + """ + class MinHeapObj(object): + def __init__(self,val): self.val = val + def __lt__(self,other): + return self.val[1] > other.val[1] if self.val[0] == other.val[0] else \ + self.val < other.val + def __eq__(self,other): return self.val == other.val + def __str__(self): return str(self.val) + + counts = collections.Counter(words) + min_heap = [] + for word, count in counts.iteritems(): + heapq.heappush(min_heap, MinHeapObj((count, word))) + if len(min_heap) == k+1: + heapq.heappop(min_heap) + result = [] + while min_heap: + result.append(heapq.heappop(min_heap).val[1]) + return result[::-1] + + +# Time: O(n + klogk) ~ O(n + nlogn) +# Space: O(n) +# Bucket Sort Solution +class Solution3(object): + def topKFrequent(self, words, k): + """ + :type words: List[str] + :type k: int + :rtype: List[str] + """ + counts = collections.Counter(words) + buckets = [[] for _ in xrange(len(words)+1)] + for word, count in counts.iteritems(): + buckets[count].append(word) + pairs = [] + for i in reversed(xrange(len(words))): + for word in buckets[i]: + pairs.append((-i, word)) + if len(pairs) >= k: + break + pairs.sort() + return [pair[1] for pair in pairs[:k]] diff --git a/Python/total-hamming-distance.py b/Python/total-hamming-distance.py new file mode 100644 index 000000000..fac26b25b --- /dev/null +++ b/Python/total-hamming-distance.py @@ -0,0 +1,34 @@ +# Time: O(n) +# Space: O(1) + +# The Hamming distance between two integers is the number of positions +# at which the corresponding bits are different. +# +# Now your job is to find the total Hamming distance between all pairs of the given numbers. +# +# Example: +# Input: 4, 14, 2 +# +# Output: 6 +# +# Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just +# showing the four bits relevant in this case). So the answer will be: +# HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6. +# Note: +# Elements of the given array are in the range of 0 to 10^9 +# Length of the array will not exceed 10^4. + +class Solution(object): + def totalHammingDistance(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result = 0 + for i in xrange(32): + counts = [0] * 2 + for num in nums: + counts[(num >> i) & 1] += 1 + result += counts[0] * counts[1] + return result + diff --git a/Python/trapping-rain-water-ii.py b/Python/trapping-rain-water-ii.py new file mode 100644 index 000000000..8a1037979 --- /dev/null +++ b/Python/trapping-rain-water-ii.py @@ -0,0 +1,60 @@ +# Time: O(m * n * log(m + n)) ~ O(m * n * log(m * n)) +# Space: O(m * n) + +# Given an m x n matrix of positive integers representing the height of each unit cell in +# a 2D elevation map, compute the volume of water it is able to trap after raining. +# +# Note: +# Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000. +# +# Example: +# +# Given the following 3x6 height map: +# [ +# [1,4,3,1,3,2], +# [3,2,1,3,2,4], +# [2,3,3,2,3,1] +# ] +# +# Return 4. + +from heapq import heappush, heappop + +class Solution(object): + def trapRainWater(self, heightMap): + """ + :type heightMap: List[List[int]] + :rtype: int + """ + m = len(heightMap) + if not m: + return 0 + n = len(heightMap[0]) + if not n: + return 0 + + is_visited = [[False for i in xrange(n)] for j in xrange(m)] + + heap = [] + for i in xrange(m): + heappush(heap, [heightMap[i][0], i, 0]) + is_visited[i][0] = True + heappush(heap, [heightMap[i][n-1], i, n-1]) + is_visited[i][n-1] = True + for j in xrange(n): + heappush(heap, [heightMap[0][j], 0, j]) + is_visited[0][j] = True + heappush(heap, [heightMap[m-1][j], m-1, j]) + is_visited[m-1][j] = True + + trap = 0 + while heap: + height, i, j = heappop(heap) + for (dx, dy) in [(1,0), (-1,0), (0,1), (0,-1)]: + x, y = i+dx, j+dy + if 0 <= x < m and 0 <= y < n and not is_visited[x][y]: + trap += max(0, height - heightMap[x][y]) + heappush(heap, [max(height, heightMap[x][y]), x, y]) + is_visited[x][y] = True + + return trap diff --git a/Python/triangle.py b/Python/triangle.py index 40cf9c627..e05906104 100644 --- a/Python/triangle.py +++ b/Python/triangle.py @@ -20,7 +20,7 @@ class Solution: # @param triangle, a list of lists of integers # @return an integer def minimumTotal(self, triangle): - if len(triangle) == 0: + if not triangle: return 0 cur = triangle[0] + [float("inf")] @@ -35,4 +35,4 @@ def minimumTotal(self, triangle): if __name__ == "__main__": print Solution().minimumTotal([[-1], [2, 3], [1, -1, -3]]) - \ No newline at end of file + diff --git a/Python/trim-a-binary-search-tree.py b/Python/trim-a-binary-search-tree.py new file mode 100644 index 000000000..992b05378 --- /dev/null +++ b/Python/trim-a-binary-search-tree.py @@ -0,0 +1,65 @@ +# Time: O(n) +# Space: O(h) + +# Given a binary search tree and the lowest and highest boundaries as L and R, +# trim the tree so that all its elements lies in [L, R] (R >= L). +# You might need to change the root of the tree, so the result should +# return the new root of the trimmed binary search tree. +# +# Example 1: +# Input: +# 1 +# / \ +# 0 2 +# +# L = 1 +# R = 2 +# +# Output: +# 1 +# \ +# 2 +# Example 2: +# Input: +# 3 +# / \ +# 0 4 +# \ +# 2 +# / +# 1 +# +# L = 1 +# R = 3 +# +# Output: +# 3 +# / +# 2 +# / +# 1 + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def trimBST(self, root, L, R): + """ + :type root: TreeNode + :type L: int + :type R: int + :rtype: TreeNode + """ + if not root: + return None + if root.val < L: + return self.trimBST(root.right, L, R) + if root.val > R: + return self.trimBST(root.left, L, R) + root.left, root.right = self.trimBST(root.left, L, R), self.trimBST(root.right, L, R) + return root + diff --git a/Python/two-sum-iii-data-structure-design.py b/Python/two-sum-iii-data-structure-design.py index 0bcaf917e..808c80d91 100644 --- a/Python/two-sum-iii-data-structure-design.py +++ b/Python/two-sum-iii-data-structure-design.py @@ -1,6 +1,6 @@ # Time: O(n) # Space: O(n) -# + # Design and implement a TwoSum class. It should support the following operations: add and find. # # add - Add the number to an internal data structure. @@ -10,31 +10,40 @@ # add(1); add(3); add(5); # find(4) -> true # find(7) -> false -# -class TwoSum: +from collections import defaultdict + +class TwoSum(object): - # initialize your data structure here def __init__(self): - self.lookup = {} + """ + initialize your data structure here + """ + self.lookup = defaultdict(int) - # @return nothing + def add(self, number): - if number in self.lookup: - self.lookup[number] += 1 - else: - self.lookup[number] = 1 + """ + Add the number to an internal data structure. + :rtype: nothing + """ + self.lookup[number] += 1 + - # @param value, an integer - # @return a Boolean def find(self, value): + """ + Find if there exists any pair of numbers which sum is equal to the value. + :type value: int + :rtype: bool + """ for key in self.lookup: num = value - key if num in self.lookup and (num != key or self.lookup[key] > 1): return True return False + if __name__ == "__main__": Sol = TwoSum() @@ -44,4 +53,3 @@ def find(self, value): for i in (4, 7): print Sol.find(i) - \ No newline at end of file diff --git a/Python/two-sum-iv-input-is-a-bst.py b/Python/two-sum-iv-input-is-a-bst.py new file mode 100644 index 000000000..e55b985bc --- /dev/null +++ b/Python/two-sum-iv-input-is-a-bst.py @@ -0,0 +1,77 @@ +# Time: O(n) +# Space: O(h) + +# Given a Binary Search Tree and a target number, +# return true if there exist two elements in the BST such that their sum is equal to the given target. +# +# Example 1: +# Input: +# 5 +# / \ +# 3 6 +# / \ \ +# 2 4 7 +# +# Target = 9 +# +# Output: True +# Example 2: +# Input: +# 5 +# / \ +# 3 6 +# / \ \ +# 2 4 7 +# +# Target = 28 +# +# Output: False + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def findTarget(self, root, k): + """ + :type root: TreeNode + :type k: int + :rtype: bool + """ + class BSTIterator(object): + def __init__(self, root, forward): + self.__node = root + self.__forward = forward + self.__s = [] + self.__cur = None + self.next() + + def val(self): + return self.__cur + + def next(self): + while self.__node or self.__s: + if self.__node: + self.__s.append(self.__node) + self.__node = self.__node.left if self.__forward else self.__node.right + else: + self.__node = self.__s.pop() + self.__cur = self.__node.val + self.__node = self.__node.right if self.__forward else self.__node.left + break + + + if not root: + return False + left, right = BSTIterator(root, True), BSTIterator(root, False) + while left.val() < right.val(): + if left.val() + right.val() == k: + return True + elif left.val() + right.val() < k: + left.next() + else: + right.next() + return False diff --git a/Python/two-sum.py b/Python/two-sum.py index e89be65fe..d7f27f0f1 100644 --- a/Python/two-sum.py +++ b/Python/two-sum.py @@ -1,25 +1,46 @@ # Time: O(n) # Space: O(n) + +# Given an array of integers, return indices of the two numbers +# such that they add up to a specific target. # -# Given an array of integers, find two numbers such that -# they add up to a specific target number. -# The function twoSum should return indices of the two numbers such that -# they add up to the target, -# where index1 must be less than index2. Please note that -# your returned answers (both index1 and index2) are not zero-based. # You may assume that each input would have exactly one solution. # -# Input: numbers={2, 7, 11, 15}, target=9 -# Output: index1=1, index2=2 +# Example: +# Given nums = [2, 7, 11, 15], target = 9, # +# Because nums[0] + nums[1] = 2 + 7 = 9, +# return [0, 1]. + -class Solution: +class Solution(object): def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ lookup = {} for i, num in enumerate(nums): if target - num in lookup: - return (lookup[target - num] + 1, i + 1) + return [lookup[target - num], i] lookup[num] = i + return [] + + def twoSum2(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + k = 0 + for i in nums: + j = target - i + k += 1 + tmp_nums = nums[k:] + if j in tmp_nums: + return [k - 1, tmp_nums.index(j) + k] + if __name__ == '__main__': - print "index1=%d, index2=%d" % Solution().twoSum((2, 7, 11, 15), 9) \ No newline at end of file + print Solution().twoSum((2, 7, 11, 15), 9) diff --git a/Python/ugly-number-ii.py b/Python/ugly-number-ii.py new file mode 100644 index 000000000..f2eff1e9b --- /dev/null +++ b/Python/ugly-number-ii.py @@ -0,0 +1,73 @@ +# Time: O(n) +# Space: O(1) +# +# Write a program to find the n-th ugly number. +# +# Ugly numbers are positive numbers whose prime factors +# only include 2, 3, 5. For example, +# 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the +# first 10 ugly numbers. +# +# Note that 1 is typically treated as an ugly number. +# +# Hint: +# +# The naive approach is to call isUgly for every number +# until you reach the nth one. Most numbers are not ugly. +# Try to focus your effort on generating only the ugly ones. +# + +import heapq + +class Solution: + # @param {integer} n + # @return {integer} + def nthUglyNumber(self, n): + ugly_number = 0 + + heap = [] + heapq.heappush(heap, 1) + for _ in xrange(n): + ugly_number = heapq.heappop(heap) + if ugly_number % 2 == 0: + heapq.heappush(heap, ugly_number * 2) + elif ugly_number % 3 == 0: + heapq.heappush(heap, ugly_number * 2) + heapq.heappush(heap, ugly_number * 3) + else: + heapq.heappush(heap, ugly_number * 2) + heapq.heappush(heap, ugly_number * 3) + heapq.heappush(heap, ugly_number * 5) + + return ugly_number + + def nthUglyNumber2(self, n): + ugly = [1] + i2 = i3 = i5 = 0 + while len(ugly) < n: + while ugly[i2] * 2 <= ugly[-1]: i2 += 1 + while ugly[i3] * 3 <= ugly[-1]: i3 += 1 + while ugly[i5] * 5 <= ugly[-1]: i5 += 1 + ugly.append(min(ugly[i2] * 2, ugly[i3] * 3, ugly[i5] * 5)) + return ugly[-1] + + def nthUglyNumber3(self, n): + q2, q3, q5 = [2], [3], [5] + ugly = 1 + for u in heapq.merge(q2, q3, q5): + if n == 1: + return ugly + if u > ugly: + ugly = u + n -= 1 + q2 += 2 * u, + q3 += 3 * u, + q5 += 5 * u, + + +class Solution2: + ugly = sorted(2**a * 3**b * 5**c + for a in range(32) for b in range(20) for c in range(14)) + + def nthUglyNumber(self, n): + return self.ugly[n-1] diff --git a/Python/ugly-number.py b/Python/ugly-number.py new file mode 100644 index 000000000..c4185bda9 --- /dev/null +++ b/Python/ugly-number.py @@ -0,0 +1,21 @@ +# Time: O(logn) = O(1) +# Space: O(1) +# +# Write a program to check whether a given number is an ugly number. +# +# Ugly numbers are positive numbers whose prime factors only include +# 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it +# includes another prime factor 7. +# +# Note that 1 is typically treated as an ugly number. +# +class Solution: + # @param {integer} num + # @return {boolean} + def isUgly(self, num): + if num == 0: + return False + for i in [2, 3, 5]: + while num % i == 0: + num /= i + return num == 1 diff --git a/Python/unique-binary-search-trees.py b/Python/unique-binary-search-trees.py index cac4cb41d..e5debe1eb 100644 --- a/Python/unique-binary-search-trees.py +++ b/Python/unique-binary-search-trees.py @@ -1,5 +1,5 @@ -# Time: O(n^2) -# Space: O(n) +# Time: O(n) +# Space: O(1) # # Given n, how many structurally unique BST's (binary search trees) that store values 1...n? # @@ -13,7 +13,29 @@ # 2 1 2 3 # -class Solution: +# Math solution. +class Solution(object): + def numTrees(self, n): + """ + :type n: int + :rtype: int + """ + if n == 0: + return 1 + + def combination(n, k): + count = 1 + # C(n, k) = (n) / 1 * (n - 1) / 2 ... * (n - k + 1) / k + for i in xrange(1, k + 1): + count = count * (n - i + 1) / i; + return count + + return combination(2 * n, n) - combination(2 * n, n - 1) + +# Time: O(n^2) +# Space: O(n) +# DP solution. +class Solution2: # @return an integer def numTrees(self, n): counts = [1, 1] diff --git a/Python/unique-paths-ii.py b/Python/unique-paths-ii.py index 8848514ca..ee53e127e 100644 --- a/Python/unique-paths-ii.py +++ b/Python/unique-paths-ii.py @@ -24,29 +24,23 @@ class Solution: # @param obstacleGrid, a list of lists of integers # @return an integer def uniquePathsWithObstacles(self, obstacleGrid): + """ + :type obstacleGrid: List[List[int]] + :rtype: int + """ m, n = len(obstacleGrid), len(obstacleGrid[0]) - ways = [0] * n - if obstacleGrid[0][0] == 0: - ways[0] = 1 - - for j in xrange(1, n): - if obstacleGrid[0][j] == 1: - ways[j] = 0 - else: - ways[j] = ways[j - 1] - - for i in xrange(1, m): + ways = [0]*n + ways[0] = 1 + for i in xrange(m): if obstacleGrid[i][0] == 1: ways[0] = 0 - - for j in xrange(1, n): + for j in xrange(n): if obstacleGrid[i][j] == 1: ways[j] = 0 - else: - ways[j] += ways[j - 1] - - return ways[n - 1] + elif j>0: + ways[j] += ways[j-1] + return ways[-1] if __name__ == "__main__": obstacleGrid = [ @@ -54,4 +48,4 @@ def uniquePathsWithObstacles(self, obstacleGrid): [0,1,0], [0,0,0] ] - print Solution().uniquePathsWithObstacles(obstacleGrid) \ No newline at end of file + print Solution().uniquePathsWithObstacles(obstacleGrid) diff --git a/Python/unique-substrings-in-wraparound-string.py b/Python/unique-substrings-in-wraparound-string.py new file mode 100644 index 000000000..33d6c3347 --- /dev/null +++ b/Python/unique-substrings-in-wraparound-string.py @@ -0,0 +1,45 @@ +# Time: O(n) +# Space: O(1) + +# Consider the string s to be the infinite wraparound string of +# "abcdefghijklmnopqrstuvwxyz", so s will look like this: +# "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....". +# +# Now we have another string p. Your job is to find out +# how many unique non-empty substrings of p are present in s. +# In particular, your input is the string p and you need to output +# the number of different non-empty substrings of p in the string s. +# +# Note: p consists of only lowercase English letters and the size of p might be over 10000. +# +# Example 1: +# Input: "a" +# Output: 1 +# +# Explanation: Only the substring "a" of string "a" is in the string s. +# Example 2: +# Input: "cac" +# Output: 2 +# Explanation: There are two substrings "a", "c" of string "cac" in the string s. +# Example 3: +# Input: "zab" +# Output: 6 +# Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s. + +class Solution(object): + def findSubstringInWraproundString(self, p): + """ + :type p: str + :rtype: int + """ + letters = [0] * 26 + result, length = 0, 0 + for i in xrange(len(p)): + curr = ord(p[i]) - ord('a') + if i > 0 and ord(p[i-1]) != (curr-1)%26 + ord('a'): + length = 0 + length += 1 + if length > letters[curr]: + result += length - letters[curr] + letters[curr] = length + return result diff --git a/Python/unique-word-abbreviation.py b/Python/unique-word-abbreviation.py new file mode 100644 index 000000000..f734f40c8 --- /dev/null +++ b/Python/unique-word-abbreviation.py @@ -0,0 +1,36 @@ +# Time: ctor: O(n), n is number of words in the dictionary. +# lookup: O(1) +# Space: O(k), k is number of unique words. + +class ValidWordAbbr(object): + def __init__(self, dictionary): + """ + initialize your data structure here. + :type dictionary: List[str] + """ + self.lookup_ = collections.defaultdict(set) + for word in dictionary: + abbr = self.abbreviation(word) + self.lookup_[abbr].add(word) + + + def isUnique(self, word): + """ + check if a word is unique. + :type word: str + :rtype: bool + """ + abbr = self.abbreviation(word) + return self.lookup_[abbr] <= {word} + + + def abbreviation(self, word): + if len(word) <= 2: + return word + return word[0] + str(len(word)-2) + word[-1] + + +# Your ValidWordAbbr object will be instantiated and called as such: +# vwa = ValidWordAbbr(dictionary) +# vwa.isUnique("word") +# vwa.isUnique("anotherWord") diff --git a/Python/utf-8-validation.py b/Python/utf-8-validation.py new file mode 100644 index 000000000..6a53dd5ac --- /dev/null +++ b/Python/utf-8-validation.py @@ -0,0 +1,61 @@ +# Time: O(n) +# Space: O(1) + +# A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules: +# +# For 1-byte character, the first bit is a 0, followed by its unicode code. +# For n-bytes character, the first n-bits are all one's, the n+1 bit is 0, +# followed by n-1 bytes with most significant 2 bits being 10. +# This is how the UTF-8 encoding would work: +# +# Char. number range | UTF-8 octet sequence +# (hexadecimal) | (binary) +# --------------------+--------------------------------------------- +# 0000 0000-0000 007F | 0xxxxxxx +# 0000 0080-0000 07FF | 110xxxxx 10xxxxxx +# 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx +# 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +# Given an array of integers representing the data, return whether it is a valid utf-8 encoding. +# +# Note: +# The input is an array of integers. +# Only the least significant 8 bits of each integer is used to store the data. +# This means each integer represents only 1 byte of data. +# +# Example 1: +# +# data = [197, 130, 1], which represents the octet sequence: 11000101 10000010 00000001. +# +# Return true. +# It is a valid utf-8 encoding for a 2-bytes character followed by a 1-byte character. +# Example 2: +# +# data = [235, 140, 4], which represented the octet sequence: 11101011 10001100 00000100. +# +# Return false. +# The first 3 bits are all one's and the 4th bit is 0 means it is a 3-bytes character. +# The next byte is a continuation byte which starts with 10 and that's correct. +# But the second continuation byte does not start with 10, so it is invalid. + +class Solution(object): + def validUtf8(self, data): + """ + :type data: List[int] + :rtype: bool + """ + count = 0 + for c in data: + if count == 0: + if (c >> 5) == 0b110: + count = 1 + elif (c >> 4) == 0b1110: + count = 2 + elif (c >> 3) == 0b11110: + count = 3 + elif (c >> 7): + return False + else: + if (c >> 6) != 0b10: + return False + count -= 1 + return count == 0 diff --git a/Python/valid-anagram.py b/Python/valid-anagram.py new file mode 100644 index 000000000..0477caec1 --- /dev/null +++ b/Python/valid-anagram.py @@ -0,0 +1,63 @@ +# Time: O(n) +# Space: O(1) +# +# Given two strings s and t, write a function to +# determine if t is an anagram of s. +# +# For example, +# s = "anagram", t = "nagaram", return true. +# s = "rat", t = "car", return false. +# +# Note: +# You may assume the string contains only lowercase alphabets. +# + +class Solution: + # @param {string} s + # @param {string} t + # @return {boolean} + def isAnagram(self, s, t): + if len(s) != len(t): + return False + + count = {} + + for c in s: + if c.lower() in count: + count[c.lower()] += 1 + else: + count[c.lower()] = 1 + + for c in t: + if c.lower() in count: + count[c.lower()] -= 1 + else: + count[c.lower()] = -1 + if count[c.lower()] < 0: + return False + + return True + + def isAnagram2(self, s, t): + return all([s.count(c)==t.count(c) for c in string.ascii_lowercase]) + + def isAnagram3(self, s, t): + if len(s) != len(t): + return False + count = collections.defaultdict(int) + for c in s: + count[c] += 1 + for c in t: + count[c] -= 1 + if count[c] < 0: + return False + return True + +# Time: O(nlogn) +# Space: O(n) +class Solution2: + # @param {string} s + # @param {string} t + # @return {boolean} + def isAnagram(self, s, t): + return sorted(s) == sorted(t) diff --git a/Python/valid-number.py b/Python/valid-number.py index c45fbaab7..75773c0df 100644 --- a/Python/valid-number.py +++ b/Python/valid-number.py @@ -21,12 +21,15 @@ class InputType: DOT = 4 EXPONENT = 5 -# regular expression: "^\s*[\+\-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?\d+)?\s*$" + +# regular expression: "^\s*[\+-]?((\d+(\.\d*)?)|\.\d+)([eE][\+-]?\d+)?\s*$" # automata: http://images.cnitblog.com/i/627993/201405/012016243309923.png -class Solution: - # @param s, a string - # @return a boolean +class Solution(object): def isNumber(self, s): + """ + :type s: str + :rtype: bool + """ transition_table = [[-1, 0, 3, 1, 2, -1], # next states for state 0 [-1, 8, -1, 1, 4, 5], # next states for state 1 [-1, -1, -1, 4, -1, -1], # next states for state 2 @@ -58,16 +61,20 @@ def isNumber(self, s): return state == 1 or state == 4 or state == 7 or state == 8 -class Solution2: - # @param s, a string - # @return a boolean + +class Solution2(object): def isNumber(self, s): + """ + :type s: str + :rtype: bool + """ import re - return bool(re.match("^\s*[\+\-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?\d+)?\s*$", s)) - + return bool(re.match("^\s*[\+-]?((\d+(\.\d*)?)|\.\d+)([eE][\+-]?\d+)?\s*$", s)) + + if __name__ == "__main__": print Solution().isNumber(" 0.1 ") print Solution().isNumber("abc") print Solution().isNumber("1 a") print Solution().isNumber("2e10") - \ No newline at end of file + diff --git a/Python/valid-palindrome-ii.py b/Python/valid-palindrome-ii.py new file mode 100644 index 000000000..5e814ca31 --- /dev/null +++ b/Python/valid-palindrome-ii.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Soace: O(1) + +# Given a non-empty string s, you may delete at most one character. +# Judge whether you can make it a palindrome. +# +# Example 1: +# Input: "aba" +# Output: True +# Example 2: +# Input: "abca" +# Output: True +# Explanation: You could delete the character 'c'. +# Note: +# The string will only contain lowercase characters a-z. The maximum length of the string is 50000. + +class Solution(object): + def validPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + def validPalindrome(s, left, right): + while left < right: + if s[left] != s[right]: + return False + left, right = left+1, right-1 + return True + + left, right = 0, len(s)-1 + while left < right: + if s[left] != s[right]: + return validPalindrome(s, left, right-1) or validPalindrome(s, left+1, right) + left, right = left+1, right-1 + return True diff --git a/Python/valid-palindrome.py b/Python/valid-palindrome.py index b9abbfc9b..c0c562059 100644 --- a/Python/valid-palindrome.py +++ b/Python/valid-palindrome.py @@ -19,9 +19,9 @@ class Solution: def isPalindrome(self, s): i, j = 0, len(s) - 1 while i < j: - while i < j and not (s[i].isalpha() or s[i].isdigit()): + while i < j and not s[i].isalnum(): i += 1 - while i < j and not (s[j].isalpha() or s[j].isdigit()): + while i < j and not s[j].isalnum(): j -= 1 if s[i].lower() != s[j].lower(): return False @@ -29,4 +29,4 @@ def isPalindrome(self, s): return True if __name__ == "__main__": - print Solution().isPalindrome("A man, a plan, a canal: Panama") \ No newline at end of file + print Solution().isPalindrome("A man, a plan, a canal: Panama") diff --git a/Python/valid-parenthesis-string.py b/Python/valid-parenthesis-string.py new file mode 100644 index 000000000..25c9700c6 --- /dev/null +++ b/Python/valid-parenthesis-string.py @@ -0,0 +1,36 @@ +# Time: O(n) +# Space: O(1) + +# Given a string containing only three types of characters: '(', ')' and '*', +# write a function to check whether this string is valid. We define the validity of a string by these rules: +# 1. Any left parenthesis '(' must have a corresponding right parenthesis ')'. +# 2. Any right parenthesis ')' must have a corresponding left parenthesis '('. +# 3. Left parenthesis '(' must go before the corresponding right parenthesis ')'. +# 4. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string. +# 5. An empty string is also valid. +# +# Example 1: +# Input: "()" +# Output: True +# Example 2: +# Input: "(*)" +# Output: True +# Example 3: +# Input: "(*))" +# Output: True +# Note: +# The string size will be in the range [1, 100]. + +class Solution(object): + def checkValidString(self, s): + """ + :type s: str + :rtype: bool + """ + lower, upper = 0, 0 # keep lower bound and upper bound of '(' counts + for c in s: + lower += 1 if c == '(' else -1 + upper -= 1 if c == ')' else -1 + if upper < 0: break + lower = max(lower, 0) + return lower == 0 # range of '(' count is valid diff --git a/Python/valid-perfect-square.py b/Python/valid-perfect-square.py new file mode 100644 index 000000000..1b77255fa --- /dev/null +++ b/Python/valid-perfect-square.py @@ -0,0 +1,31 @@ +# Time: O(logn) +# Space: O(1) + +# Given a positive integer num, write a function +# which returns True if num is a perfect square else False. +# +# Note: Do not use any built-in library function such as sqrt. +# +# Example 1: +# +# Input: 16 +# Returns: True +# Example 2: +# +# Input: 14 +# Returns: False + +class Solution(object): + def isPerfectSquare(self, num): + """ + :type num: int + :rtype: bool + """ + left, right = 1, num + while left <= right: + mid = left + (right - left) / 2 + if mid >= num / mid: + right = mid - 1 + else: + left = mid + 1 + return left == num / left and num % left == 0 diff --git a/Python/valid-square.py b/Python/valid-square.py new file mode 100644 index 000000000..a3855abbc --- /dev/null +++ b/Python/valid-square.py @@ -0,0 +1,34 @@ +# Time: O(1) +# Space: O(1) + +# Given the coordinates of four points in 2D space, +# return whether the four points could construct a square. +# +# The coordinate (x,y) of a point is represented by an integer array with two integers. +# +# Example: +# Input: p1 = [0,0], p2 = [1,1], p3 = [1,0], p4 = [0,1] +# Output: True +# Note: +# +# All the input integers are in the range [-10000, 10000]. +# A valid square has four equal sides with positive length +# and four equal angles (90-degree angles). +# Input points have no order. + +class Solution(object): + def validSquare(self, p1, p2, p3, p4): + """ + :type p1: List[int] + :type p2: List[int] + :type p3: List[int] + :type p4: List[int] + :rtype: bool + """ + def dist(p1, p2): + return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 + + lookup = set([dist(p1, p2), dist(p1, p3),\ + dist(p1, p4), dist(p2, p3),\ + dist(p2, p4), dist(p3, p4)]) + return 0 not in lookup and len(lookup) == 2 diff --git a/Python/valid-sudoku.py b/Python/valid-sudoku.py index 7de8b05c5..610964276 100644 --- a/Python/valid-sudoku.py +++ b/Python/valid-sudoku.py @@ -1,27 +1,32 @@ -# Time: O(n^2) -# Space: O(n) +# Time: O(9^2) +# Space: O(9) + +# Determine if a Sudoku is valid, +# according to: Sudoku Puzzles - The Rules. +# +# The Sudoku board could be partially filled, +# where empty cells are filled with the character '.'. # -# Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. -# -# The Sudoku board could be partially filled, where empty cells are filled with the character '.'. -# -# # A partially filled sudoku which is valid. -# -# Note: -# A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated. # +# Note: +# A valid Sudoku board (partially filled) is not necessarily solvable. +# Only the filled cells need to be validated. -class Solution: - # @param board, a 9x9 2D array - # @return a boolean +class Solution(object): def isValidSudoku(self, board): + """ + :type board: List[List[str]] + :rtype: bool + """ for i in xrange(9): - if not self.isValidList([board[i][j] for j in xrange(9)]) or not self.isValidList([board[j][i] for j in xrange(9)]): + if not self.isValidList([board[i][j] for j in xrange(9)]) or \ + not self.isValidList([board[j][i] for j in xrange(9)]): return False for i in xrange(3): for j in xrange(3): - if not self.isValidList([board[m][n] for n in xrange(3 * j, 3 * j + 3) for m in xrange(3 * i, 3 * i + 3)]): + if not self.isValidList([board[m][n] for n in xrange(3 * j, 3 * j + 3) \ + for m in xrange(3 * i, 3 * i + 3)]): return False return True @@ -29,6 +34,7 @@ def isValidList(self, xs): xs = filter(lambda x: x != '.', xs) return len(set(xs)) == len(xs) + if __name__ == "__main__": board = [[1, '.', '.', '.', '.', '.', '.', '.', '.'], ['.', 2, '.', '.', '.', '.', '.', '.', '.'], diff --git a/Python/valid-triangle-number.py b/Python/valid-triangle-number.py new file mode 100644 index 000000000..6e1dbbe04 --- /dev/null +++ b/Python/valid-triangle-number.py @@ -0,0 +1,37 @@ +# Time: O(n^2) +# Space: O(1) + +# Given an array consists of non-negative integers, +# your task is to count the number of triplets chosen +# from the array that can make triangles +# if we take them as side lengths of a triangle. +# +# Example 1: +# Input: [2,2,3,4] +# Output: 3 +# Explanation: +# Valid combinations are: +# 2,3,4 (using the first 2) +# 2,3,4 (using the second 2) +# 2,2,3 +# Note: +# The length of the given array won't exceed 1000. +# The integers in the given array are in the range of [0, 1000]. + +class Solution(object): + def triangleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + result = 0 + nums.sort() + for i in xrange(len(nums)-2): + if nums[i] == 0: + continue + k = i+2 + for j in xrange(i+1, len(nums)-1): + while k < len(nums) and nums[i] + nums[j] > nums[k]: + k += 1 + result += k-j-1 + return result diff --git a/Python/valid-word-abbreviation.py b/Python/valid-word-abbreviation.py new file mode 100644 index 000000000..e14d474e7 --- /dev/null +++ b/Python/valid-word-abbreviation.py @@ -0,0 +1,28 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def validWordAbbreviation(self, word, abbr): + """ + :type word: str + :type abbr: str + :rtype: bool + """ + i , digit = 0, 0 + for c in abbr: + if c.isdigit(): + if digit == 0 and c == '0': + return False + digit *= 10 + digit += int(c) + else: + if digit: + i += digit + digit = 0 + if i >= len(word) or word[i] != c: + return False + i += 1 + if digit: + i += digit + + return i == len(word) diff --git a/Python/valid-word-square.py b/Python/valid-word-square.py new file mode 100644 index 000000000..8f9fe8c4a --- /dev/null +++ b/Python/valid-word-square.py @@ -0,0 +1,15 @@ +# Time: O(m * n) +# Space: O(1) + +class Solution(object): + def validWordSquare(self, words): + """ + :type words: List[str] + :rtype: bool + """ + for i in xrange(len(words)): + for j in xrange(len(words[i])): + if j >= len(words) or i >= len(words[j]) or \ + words[j][i] != words[i][j]: + return False + return True diff --git a/Python/validate-binary-search-tree.py b/Python/validate-binary-search-tree.py index 9af8db35d..8425ef443 100644 --- a/Python/validate-binary-search-tree.py +++ b/Python/validate-binary-search-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(1) # # Given a binary tree, determine if it is a valid binary search tree (BST). # @@ -17,7 +17,39 @@ def __init__(self, x): self.left = None self.right = None +# Morris Traversal Solution class Solution: + # @param root, a tree node + # @return a list of integers + def isValidBST(self, root): + prev, cur = None, root + while cur: + if cur.left is None: + if prev and prev.val >= cur.val: + return False + prev = cur + cur = cur.right + else: + node = cur.left + while node.right and node.right != cur: + node = node.right + + if node.right is None: + node.right = cur + cur = cur.left + else: + if prev and prev.val >= cur.val: + return False + node.right = None + prev = cur + cur = cur.right + + return True + + +# Time: O(n) +# Space: O(h) +class Solution2: # @param root, a tree node # @return a boolean def isValidBST(self, root): @@ -30,9 +62,10 @@ def isValidBSTRecu(self, root, low, high): return low < root.val and root.val < high \ and self.isValidBSTRecu(root.left, low, root.val) \ and self.isValidBSTRecu(root.right, root.val, high) + if __name__ == "__main__": root = TreeNode(2) root.left = TreeNode(1) root.right = TreeNode(3) - print Solution().isValidBST(root) \ No newline at end of file + print Solution().isValidBST(root) diff --git a/Python/validate-ip-address.py b/Python/validate-ip-address.py new file mode 100644 index 000000000..50be7762d --- /dev/null +++ b/Python/validate-ip-address.py @@ -0,0 +1,70 @@ +# Time: O(1) +# Space: O(1) + +# In this problem, your job to write a function to check whether a input string +# is a valid IPv4 address or IPv6 address or neither. +# +# IPv4 addresses are canonically represented in dot-decimal notation, +# which consists of four decimal numbers, each ranging from 0 to 255, separated by dots ("."), e.g.,172.16.254.1; +# +# Besides, you need to keep in mind that leading zeros in the IPv4 is illegal. +# For example, the address 172.16.254.01 is illegal. +# +# IPv6 addresses are represented as eight groups of four hexadecimal digits, +# each group representing 16 bits. The groups are separated by colons (":"). +# For example, the address 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a legal one. +# Also, we could omit some leading zeros among four hexadecimal digits and +# some low-case characters in the address to upper-case ones, +# so 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address(Omit leading zeros and using upper cases). +# +# However, we don't replace a consecutive group of zero value with a single empty group +# using two consecutive colons (::) to pursue simplicity. +# For example, 2001:0db8:85a3::8A2E:0370:7334 is an invalid IPv6 address. +# +# Besides, you need to keep in mind that extra leading zeros in the IPv6 is also illegal. +# For example, the address 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is also illegal. +# +# Note: You could assume there is no extra space in the test cases and +# there may some special characters in the input string. +# +# Example 1: +# Input: "172.16.254.1" +# +# Output: "IPv4" +# +# Explanation: This is a valid IPv4 address, return "IPv4". +# Example 2: +# Input: "2001:0db8:85a3:0:0:8A2E:0370:7334" +# +# Output: "IPv6" +# +# Explanation: This is a valid IPv6 address, return "IPv6". +# Example 3: +# Input: "256.256.256.256" +# +# Output: "Neither" +# +# Explanation: This is neither a IPv4 address nor a IPv6 address. + +class Solution(object): + def validIPAddress(self, IP): + """ + :type IP: str + :rtype: str + """ + blocks = IP.split('.') + if len(blocks) == 4: + for i in xrange(len(blocks)): + if not blocks[i].isdigit() or not 0 <= int(blocks[i]) < 256 or \ + (blocks[i][0] == '0' and len(blocks[i]) > 1): + return "Neither" + return "IPv4" + + blocks = IP.split(':') + if len(blocks) == 8: + for i in xrange(len(blocks)): + if not (1 <= len(blocks[i]) <= 4) or \ + not all(c in string.hexdigits for c in blocks[i]): + return "Neither" + return "IPv6" + return "Neither" diff --git a/Python/verify-preorder-sequence-in-binary-search-tree.py b/Python/verify-preorder-sequence-in-binary-search-tree.py new file mode 100644 index 000000000..8da8deeb2 --- /dev/null +++ b/Python/verify-preorder-sequence-in-binary-search-tree.py @@ -0,0 +1,34 @@ +# Time: O(n) +# Space: O(1) + +class Solution: + # @param {integer[]} preorder + # @return {boolean} + def verifyPreorder(self, preorder): + low, i = float("-inf"), -1 + for p in preorder: + if p < low: + return False + while i >= 0 and p > preorder[i]: + low = preorder[i] + i -= 1 + i += 1 + preorder[i] = p + return True + +# Time: O(n) +# Space: O(h) +class Solution2: + # @param {integer[]} preorder + # @return {boolean} + def verifyPreorder(self, preorder): + low = float("-inf") + path = [] + for p in preorder: + if p < low: + return False + while path and p > path[-1]: + low = path[-1] + path.pop() + path.append(p) + return True diff --git a/Python/verify-preorder-serialization-of-a-binary-tree.py b/Python/verify-preorder-serialization-of-a-binary-tree.py new file mode 100644 index 000000000..ee7d23f75 --- /dev/null +++ b/Python/verify-preorder-serialization-of-a-binary-tree.py @@ -0,0 +1,66 @@ +# Time: O(n) +# Space: O(1) + +# One way to serialize a binary tree is to use pre-oder traversal. +# When we encounter a non-null node, we record the node's value. +# If it is a null node, we record using a sentinel value such as #. +# +# _9_ +# / \ +# 3 2 +# / \ / \ +# 4 1 # 6 +# / \ / \ / \ +# # # # # # # +# For example, the above binary tree can be serialized to the string +# "9,3,4,#,#,1,#,#,2,#,6,#,#", where # represents a null node. +# +# Given a string of comma separated values, verify whether it is a +# correct preorder traversal serialization of a binary tree. +# Find an algorithm without reconstructing the tree. +# +# Each comma separated value in the string must be either an integer +# or a character '#' representing null pointer. +# +# You may assume that the input format is always valid, for example +# it could never contain two consecutive commas such as "1,,3". +# +# Example 1: +# "9,3,4,#,#,1,#,#,2,#,6,#,#" +# Return true +# +# Example 2: +# "1,#" +# Return false +# +# Example 3: +# "9,#,#,1" +# Return false + +class Solution(object): + def isValidSerialization(self, preorder): + """ + :type preorder: str + :rtype: bool + """ + def split_iter(s, tok): + start = 0 + for i in xrange(len(s)): + if s[i] == tok: + yield s[start:i] + start = i + 1 + yield s[start:] + + if not preorder: + return False + + depth, cnt = 0, preorder.count(',') + 1 + for tok in split_iter(preorder, ','): + cnt -= 1 + if tok == "#": + depth -= 1; + if depth < 0: + break + else: + depth += 1 + return cnt == 0 and depth < 0 diff --git a/Python/walls-and-gates.py b/Python/walls-and-gates.py new file mode 100644 index 000000000..c3113ffd2 --- /dev/null +++ b/Python/walls-and-gates.py @@ -0,0 +1,21 @@ +# Time: O(m * n) +# Space: O(g) + +from collections import deque + +class Solution(object): + def wallsAndGates(self, rooms): + """ + :type rooms: List[List[int]] + :rtype: void Do not return anything, modify rooms in-place instead. + """ + INF = 2147483647 + q = deque([(i, j) for i, row in enumerate(rooms) for j, r in enumerate(row) if not r]) + while q: + (i, j) = q.popleft() + for I, J in (i+1, j), (i-1, j), (i, j+1), (i, j-1): + if 0 <= I < len(rooms) and 0 <= J < len(rooms[0]) and \ + rooms[I][J] == INF: + rooms[I][J] = rooms[i][j] + 1 + q.append((I, J)) + diff --git a/Python/water-and-jug-problem.py b/Python/water-and-jug-problem.py new file mode 100644 index 000000000..b6dcfe954 --- /dev/null +++ b/Python/water-and-jug-problem.py @@ -0,0 +1,42 @@ +# Time: O(logn), n is the max of (x, y) +# Space: O(1) + +# You are given two jugs with capacities x and y litres. +# There is an infinite amount of water supply available. +# You need to determine whether it is possible to +# measure exactly z litres using these two jugs. +# +# Operations allowed: +# +# Fill any of the jugs completely. +# Empty any of the jugs. +# Pour water from one jug into another till +# the other jug is completely full or +# the first jug itself is empty. +# Example 1: +# +# Input: x = 2, y = 6, z = 4 +# Output: True +# Example 2: +# +# Input: x = 2, y = 6, z = 5 +# Output: False + +# Bézout's identity (also called Bézout's lemma) +class Solution(object): + def canMeasureWater(self, x, y, z): + """ + :type x: int + :type y: int + :type z: int + :rtype: bool + """ + def gcd(a, b): + while b: + a, b = b, a%b + return a + + # The problem is to solve: + # - check z <= x + y + # - check if there is any (a, b) integers s.t. ax + by = z + return z == 0 or ((z <= x + y) and (z % gcd(x, y) == 0)) diff --git a/Python/wiggle-sort-ii.py b/Python/wiggle-sort-ii.py new file mode 100644 index 000000000..15b625f07 --- /dev/null +++ b/Python/wiggle-sort-ii.py @@ -0,0 +1,79 @@ +# Time: O(nlogn) +# Space: O(n) + +# Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3].... +# +# Example: +# (1) Given nums = [1, 5, 1, 1, 6, 4], one possible answer is [1, 4, 1, 5, 1, 6]. +# (2) Given nums = [1, 3, 2, 2, 3, 1], one possible answer is [2, 3, 1, 3, 1, 2]. +# +# Note: +# You may assume all input has valid answer. +# +# Follow Up: +# Can you do it in O(n) time and/or in-place with O(1) extra space? + +# Sorting and reoder solution. (92ms) +class Solution(object): + def wiggleSort(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + nums.sort() + med = (len(nums) - 1) / 2 + nums[::2], nums[1::2] = nums[med::-1], nums[:med:-1] + +# Time: O(n) ~ O(n^2) +# Space: O(1) +# Tri Partition (aka Dutch National Flag Problem) with virtual index solution. (TLE) +from random import randint +class Solution2(object): + def wiggleSort(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + def findKthLargest(nums, k): + left, right = 0, len(nums) - 1 + while left <= right: + pivot_idx = randint(left, right) + new_pivot_idx = partitionAroundPivot(left, right, pivot_idx, nums) + if new_pivot_idx == k - 1: + return nums[new_pivot_idx] + elif new_pivot_idx > k - 1: + right = new_pivot_idx - 1 + else: # new_pivot_idx < k - 1. + left = new_pivot_idx + 1 + + def partitionAroundPivot(left, right, pivot_idx, nums): + pivot_value = nums[pivot_idx] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i] > pivot_value: + nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i] + new_pivot_idx += 1 + nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right] + return new_pivot_idx + + def reversedTriPartitionWithVI(nums, val): + def idx(i, N): + return (1 + 2 * (i)) % N + + N = len(nums) / 2 * 2 + 1 + i, j, n = 0, 0, len(nums) - 1 + while j <= n: + if nums[idx(j, N)] > val: + nums[idx(i, N)], nums[idx(j, N)] = nums[idx(j, N)], nums[idx(i, N)] + i += 1 + j += 1 + elif nums[idx(j, N)] < val: + nums[idx(j, N)], nums[idx(n, N)] = nums[idx(n, N)], nums[idx(j, N)] + n -= 1 + else: + j += 1 + + mid = (len(nums) - 1) / 2 + findKthLargest(nums, mid + 1) + reversedTriPartitionWithVI(nums, nums[mid]) diff --git a/Python/wiggle-sort.py b/Python/wiggle-sort.py new file mode 100644 index 000000000..fd3b0283f --- /dev/null +++ b/Python/wiggle-sort.py @@ -0,0 +1,14 @@ +# Time: O(n) +# Space: O(1) + +class Solution(object): + def wiggleSort(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + for i in xrange(1, len(nums)): + if ((i % 2) and nums[i - 1] > nums[i]) or \ + (not (i % 2) and nums[i - 1] < nums[i]): + # Swap unordered elements. + nums[i - 1], nums[i] = nums[i], nums[i - 1] diff --git a/Python/wiggle-subsequence.py b/Python/wiggle-subsequence.py new file mode 100644 index 000000000..3336a9338 --- /dev/null +++ b/Python/wiggle-subsequence.py @@ -0,0 +1,58 @@ +# Time: O(n) +# Space: O(1) + +# A sequence of numbers is called a wiggle sequence +# if the differences between successive numbers strictly +# alternate between positive and negative. +# The first difference (if one exists) may be either positive +# or negative. A sequence with fewer than two elements +# is trivially a wiggle sequence. +# +# For example, [1,7,4,9,2,5] is a wiggle sequence because +# the differences (6,-3,5,-7,3) are alternately positive +# and negative. In contrast, [1,4,7,2,5] and [1,7,4,5,5] are +# not wiggle sequences, the first because its first two differences +# are positive and the second because its last difference is zero. +# +# Given a sequence of integers, return the length of +# the longest subsequence that is a wiggle sequence. +# A subsequence is obtained by deleting some number of elements +# (eventually, also zero) from the original sequence, leaving +# the remaining elements in their original order. +# +# Examples: +# Input: [1,7,4,9,2,5] +# Output: 6 +# The entire sequence is a wiggle sequence. +# +# Input: [1,17,5,10,13,15,10,5,16,8] +# Output: 7 +# There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8]. +# +# Input: [1,2,3,4,5,6,7,8,9] +# Output: 2 +# +# Follow up: +# Can you do it in O(n) time? + + +class Solution(object): + def wiggleMaxLength(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if len(nums) < 2: + return len(nums) + + length, up = 1, None + + for i in xrange(1, len(nums)): + if nums[i - 1] < nums[i] and (up is None or up is False): + length += 1 + up = True + elif nums[i - 1] > nums[i] and (up is None or up is True): + length += 1 + up = False + + return length diff --git a/Python/wildcard-matching.py b/Python/wildcard-matching.py index ebd9f1c49..7965368aa 100644 --- a/Python/wildcard-matching.py +++ b/Python/wildcard-matching.py @@ -48,7 +48,9 @@ def isMatch(self, s, p): return p_ptr == len(p) -# dp +# dp with rolling window +# Time: O(m * n) +# Space: O(m + n) class Solution2: # @return a boolean def isMatch(self, s, p): @@ -92,15 +94,15 @@ def isMatch(self, s, p): return result[len(s)][len(p)] -# recursive, slowest +# recursive, slowest, TLE class Solution4: # @return a boolean def isMatch(self, s, p): - if len(p) == 0: - return len(s) == 0 + if not p or not s: + return not s and not p if p[0] != '*': - if len(s) == 0 or (p[0] == s[0] or p[0] == '?'): + if p[0] == s[0] or p[0] == '?': return self.isMatch(s[1:], p[1:]) else: return False @@ -120,4 +122,4 @@ def isMatch(self, s, p): print Solution().isMatch("aa", "a*") print Solution().isMatch("aa", "?*") print Solution().isMatch("ab", "?*") - print Solution().isMatch("aab", "c*a*b") \ No newline at end of file + print Solution().isMatch("aab", "c*a*b") diff --git a/Python/word-abbreviation.py b/Python/word-abbreviation.py new file mode 100644 index 000000000..ef666f0a3 --- /dev/null +++ b/Python/word-abbreviation.py @@ -0,0 +1,35 @@ +# Time: O(n * l) ~ O(n^2 * l^2) +# Space: O(n * l) + +class Solution(object): + def wordsAbbreviation(self, dict): + """ + :type dict: List[str] + :rtype: List[str] + """ + def isUnique(prefix, words): + return sum(word.startswith(prefix) for word in words) == 1 + + def toAbbr(prefix, word): + abbr = prefix + str(len(word) - 1 - len(prefix)) + word[-1] + return abbr if len(abbr) < len(word) else word + + abbr_to_word = collections.defaultdict(set) + word_to_abbr = {} + + for word in dict: + prefix = word[:1] + abbr_to_word[toAbbr(prefix, word)].add(word) + + for abbr, conflicts in abbr_to_word.iteritems(): + if len(conflicts) > 1: + for word in conflicts: + for i in xrange(2, len(word)): + prefix = word[:i] + if isUnique(prefix, conflicts): + word_to_abbr[word] = toAbbr(prefix, word) + break + else: + word_to_abbr[conflicts.pop()] = abbr + + return [word_to_abbr[word] for word in dict] diff --git a/Python/word-break-ii.py b/Python/word-break-ii.py index f0908b2d0..7dcb65c6d 100644 --- a/Python/word-break-ii.py +++ b/Python/word-break-ii.py @@ -1,5 +1,6 @@ -# Time: O(2^n) -# Space: O(n) +# Time: O(n * l^2 + n * r), l is the max length of the words, +# r is the number of the results. +# Space: O(n^2) # # Given a string s and a dictionary of words dict, # add spaces in s to construct a sentence where each word is a valid dictionary word. @@ -13,36 +14,43 @@ # A solution is ["cats and dog", "cat sand dog"]. # -class Solution: - # @param s, a string - # @param dict, a set of string - # @return a list of strings - def wordBreak(self, s, dict): +class Solution(object): + def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: Set[str] + :rtype: List[str] + """ n = len(s) - possible = [False for _ in xrange(n)] + + max_len = 0 + for string in wordDict: + max_len = max(max_len, len(string)) + + can_break = [False for _ in xrange(n + 1)] valid = [[False] * n for _ in xrange(n)] - for i in xrange(n): - if s[:i+1] in dict: - possible[i] = True - valid[0][i] = True - for j in xrange(i): - if possible[j] and s[j+1:i+1] in dict: - valid[j+1][i] = True - possible[i] = True + can_break[0] = True + for i in xrange(1, n + 1): + for l in xrange(1, min(i, max_len) + 1): + if can_break[i-l] and s[i-l:i] in wordDict: + valid[i-l][i-1] = True + can_break[i] = True + result = [] - if possible[n-1]: - self.genPath(s, valid, 0, [], result) + if can_break[-1]: + self.wordBreakHelper(s, valid, 0, [], result) return result - def genPath(self, s, valid, start, path, result): + def wordBreakHelper(self, s, valid, start, path, result): if start == len(s): result.append(" ".join(path)) return for i in xrange(start, len(s)): if valid[start][i]: path += [s[start:i+1]] - self.genPath(s, valid, i + 1, path, result) + self.wordBreakHelper(s, valid, i + 1, path, result) path.pop() + if __name__ == "__main__": - print Solution().wordBreak("catsanddog", ["cat", "cats", "and", "sand", "dog"]) \ No newline at end of file + print Solution().wordBreak("catsanddog", ["cat", "cats", "and", "sand", "dog"]) diff --git a/Python/word-break.py b/Python/word-break.py index bd39ed955..e64e5631e 100644 --- a/Python/word-break.py +++ b/Python/word-break.py @@ -1,6 +1,6 @@ -# Time: O(n^2) +# Time: O(n * l^2) # Space: O(n) -# + # Given a string s and a dictionary of words dict, # determine if s can be segmented into a space-separated sequence of one or more dictionary words. # @@ -9,24 +9,30 @@ # dict = ["leet", "code"]. # # Return true because "leetcode" can be segmented as "leet code". -# -class Solution: - # @param s, a string - # @param dict, a set of string - # @return a boolean - def wordBreak(self, s, dict): +class Solution(object): + def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: Set[str] + :rtype: bool + """ n = len(s) - possible = [False for _ in xrange(n)] - for i in xrange(n): - if s[:i+1] in dict: - possible[i] = True - for j in xrange(i): - if possible[j] and s[j+1:i+1] in dict: - possible[i] = True + + max_len = 0 + for string in wordDict: + max_len = max(max_len, len(string)) + + can_break = [False for _ in xrange(n + 1)] + can_break[0] = True + for i in xrange(1, n + 1): + for l in xrange(1, min(i, max_len) + 1): + if can_break[i-l] and s[i-l:i] in wordDict: + can_break[i] = True break - - return possible[n-1] + + return can_break[-1] + if __name__ == "__main__": - print Solution().wordBreak("leetcode", ["leet", "code"]) \ No newline at end of file + print Solution().wordBreak("leetcode", ["leet", "code"]) diff --git a/Python/word-ladder-ii.py b/Python/word-ladder-ii.py index 501fd94fa..b7ffb1180 100644 --- a/Python/word-ladder-ii.py +++ b/Python/word-ladder-ii.py @@ -1,5 +1,5 @@ -# Time: O((25n)^n) -# Space: O((25n)^n) +# Time: O(n * d), n is length of string, d is size of dictionary +# Space: O(d) # # Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that: # @@ -37,7 +37,7 @@ def findLadders(self, start, end, dict): for word in cur: visited.add(word) - next = set([]) + next = set() for word in cur: for i in xrange(len(word)): for j in 'abcdefghijklmnopqrstuvwxyz': @@ -55,7 +55,7 @@ def findLadders(self, start, end, dict): return result def backtrack(self, result, trace, path, word): - if len(trace[word]) == 0: + if not trace[word]: result.append([word] + path) else: for prev in trace[word]: diff --git a/Python/word-ladder.py b/Python/word-ladder.py index 8ed2f6c97..3a97d25a8 100644 --- a/Python/word-ladder.py +++ b/Python/word-ladder.py @@ -1,5 +1,5 @@ -# Time: O((25n)^n) -# Space: O((25n)^n) +# Time: O(n * d), n is length of string, d is size of dictionary +# Space: O(d) # # Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that: # @@ -21,30 +21,34 @@ # # BFS -class Solution: - # @param start, a string - # @param end, a string - # @param dict, a set of string - # @return an integer - def ladderLength(self, start, end, dict): - distance, cur, visited = 0, [start], set([start]) - dict.add(end) - +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + distance, cur, visited, lookup = 0, [beginWord], set([beginWord]), set(wordList) + while cur: - next = [] + next_queue = [] + for word in cur: - if word == end: + if word == endWord: return distance + 1 for i in xrange(len(word)): for j in 'abcdefghijklmnopqrstuvwxyz': candidate = word[:i] + j + word[i + 1:] - if candidate not in visited and candidate in dict: - next.append(candidate) + if candidate not in visited and candidate in lookup: + next_queue.append(candidate) visited.add(candidate) distance += 1 - cur = next - + cur = next_queue + return 0 - + + if __name__ == "__main__": - print Solution().ladderLength("hit", "cog", set(["hot","dot","dog","lot","log"])) + print Solution().ladderLength("hit", "cog", set(["hot", "dot", "dog", "lot", "log"])) + print Solution().ladderLength("hit", "cog", set(["hot", "dot", "dog", "lot", "log", "cog"])) diff --git a/Python/word-pattern-ii.py b/Python/word-pattern-ii.py new file mode 100644 index 000000000..2d12cd67c --- /dev/null +++ b/Python/word-pattern-ii.py @@ -0,0 +1,39 @@ +# Time: O(n * C(n - 1, c - 1)), n is length of str, c is unique count of pattern, +# there are H(n - c, c - 1) = C(n - 1, c - 1) possible splits of string, +# and each one costs O(n) to check if it matches the word pattern. +# Space: O(n + c) + +class Solution(object): + def wordPatternMatch(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + w2p, p2w = {}, {} + return self.match(pattern, str, 0, 0, w2p, p2w) + + + def match(self, pattern, str, i, j, w2p, p2w): + is_match = False + if i == len(pattern) and j == len(str): + is_match = True + elif i < len(pattern) and j < len(str): + p = pattern[i] + if p in p2w: + w = p2w[p] + if w == str[j:j+len(w)]: # Match pattern. + is_match = self.match(pattern, str, i + 1, j + len(w), w2p, p2w) + # Else return false. + else: + for k in xrange(j, len(str)): # Try any possible word + w = str[j:k+1] + if w not in w2p: + # Build mapping. Space: O(n + c) + w2p[w], p2w[p] = p, w; + is_match = self.match(pattern, str, i + 1, k + 1, w2p, p2w) + w2p.pop(w), p2w.pop(p); + if is_match: + break + return is_match + diff --git a/Python/word-pattern.py b/Python/word-pattern.py new file mode 100644 index 000000000..7bace4ebd --- /dev/null +++ b/Python/word-pattern.py @@ -0,0 +1,82 @@ +# Time: O(n) +# Space: O(c), c is unique count of pattern + +# Given a pattern and a string str, find if str follows the same pattern. +# +# Examples: +# 1. pattern = "abba", str = "dog cat cat dog" should return true. +# 2. pattern = "abba", str = "dog cat cat fish" should return false. +# 3. pattern = "aaaa", str = "dog cat cat dog" should return false. +# 4. pattern = "abba", str = "dog dog dog dog" should return false. +# +# Notes: +# 1. Both pattern and str contains only lowercase alphabetical letters. +# 2. Both pattern and str do not have leading or trailing spaces. +# 3. Each word in str is separated by a single space. +# 4. Each letter in pattern must map to a word with length that is at least 1. + +from itertools import izip # Generator version of zip. + +class Solution(object): + def wordPattern(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + if len(pattern) != self.wordCount(str): + return False + + w2p, p2w = {}, {} + for p, w in izip(pattern, self.wordGenerator(str)): + if w not in w2p and p not in p2w: + # Build mapping. Space: O(c) + w2p[w] = p + p2w[p] = w + elif w not in w2p or w2p[w] != p: + # Contradict mapping. + return False + return True + + def wordCount(self, str): + cnt = 1 if str else 0 + for c in str: + if c == ' ': + cnt += 1 + return cnt + + # Generate a word at a time without saving all the words. + def wordGenerator(self, str): + w = "" + for c in str: + if c == ' ': + yield w + w = "" + else: + w += c + yield w + + +# Time: O(n) +# Space: O(n) +class Solution2(object): + def wordPattern(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + words = str.split() # Space: O(n) + if len(pattern) != len(words): + return False + + w2p, p2w = {}, {} + for p, w in izip(pattern, words): + if w not in w2p and p not in p2w: + # Build mapping. Space: O(c) + w2p[w] = p + p2w[p] = w + elif w not in w2p or w2p[w] != p: + # Contradict mapping. + return False + return True diff --git a/Python/word-search-ii.py b/Python/word-search-ii.py new file mode 100644 index 000000000..4c6acdaac --- /dev/null +++ b/Python/word-search-ii.py @@ -0,0 +1,77 @@ +# Time: O(m * n * l) +# Space: O(l) +# +# Given a 2D board and a list of words from the dictionary, find all words in the board. +# +# Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells +# are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word. +# +# For example, +# Given words = ["oath","pea","eat","rain"] and board = +# +# [ +# ['o','a','a','n'], +# ['e','t','a','e'], +# ['i','h','k','r'], +# ['i','f','l','v'] +# ] +# Return ["eat","oath"]. +# Note: +# You may assume that all inputs are consist of lowercase letters a-z. +# + +class TrieNode(object): + # Initialize your data structure here. + def __init__(self): + self.is_string = False + self.leaves = {} + + # Inserts a word into the trie. + def insert(self, word): + cur = self + for c in word: + if not c in cur.leaves: + cur.leaves[c] = TrieNode() + cur = cur.leaves[c] + cur.is_string = True + + +class Solution(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + visited = [[False for j in xrange(len(board[0]))] for i in xrange(len(board))] + result = {} + trie = TrieNode() + for word in words: + trie.insert(word) + + for i in xrange(len(board)): + for j in xrange(len(board[0])): + if self.findWordsRecu(board, trie, 0, i, j, visited, [], result): + return True + + return result.keys() + + def findWordsRecu(self, board, trie, cur, i, j, visited, cur_word, result): + if not trie or i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or visited[i][j]: + return + + if board[i][j] not in trie.leaves: + return + + cur_word.append(board[i][j]) + next_node = trie.leaves[board[i][j]] + if next_node.is_string: + result["".join(cur_word)] = True + + visited[i][j] = True + self.findWordsRecu(board, next_node, cur + 1, i + 1, j, visited, cur_word, result) + self.findWordsRecu(board, next_node, cur + 1, i - 1, j, visited, cur_word, result) + self.findWordsRecu(board, next_node, cur + 1, i, j + 1, visited, cur_word, result) + self.findWordsRecu(board, next_node, cur + 1, i, j - 1, visited, cur_word, result) + visited[i][j] = False + cur_word.pop() diff --git a/Python/word-search.py b/Python/word-search.py index 434f5dbda..3166d0b00 100644 --- a/Python/word-search.py +++ b/Python/word-search.py @@ -1,5 +1,5 @@ -# Time: O(m * n * 3^p) -# Space: O(m * n + p) +# Time: O(m * n * l) +# Space: O(l) # # Given a 2D board and a word, find if the word exists in the grid. # diff --git a/Python/word-squares.py b/Python/word-squares.py new file mode 100644 index 000000000..59d69b9e6 --- /dev/null +++ b/Python/word-squares.py @@ -0,0 +1,51 @@ +# Time: O(n^2 * n!) +# Space: O(n^2) + +class TrieNode(object): + def __init__(self): + self.indices = [] + self.children = [None] * 26 + + def insert(self, words, i): + cur = self + for c in words[i]: + if not cur.children[ord(c)-ord('a')]: + cur.children[ord(c)-ord('a')] = TrieNode() + cur = cur.children[ord(c)-ord('a')] + cur.indices.append(i) + + +class Solution(object): + def wordSquares(self, words): + """ + :type words: List[str] + :rtype: List[List[str]] + """ + result = [] + + trie = TrieNode() + for i in xrange(len(words)): + trie.insert(words, i) + + curr = [] + for s in words: + curr.append(s) + self.wordSquaresHelper(words, trie, curr, result) + curr.pop() + + return result + + def wordSquaresHelper(self, words, trie, curr, result): + if len(curr) >= len(words[0]): + return result.append(list(curr)) + + node = trie + for s in curr: + node = node.children[ord(s[len(curr)]) - ord('a')] + if not node: + return + + for i in node.indices: + curr.append(words[i]) + self.wordSquaresHelper(words, trie, curr, result) + curr.pop() diff --git a/Python/zigzag-conversion.py b/Python/zigzag-conversion.py index ebe4be0da..f5381a1b5 100644 --- a/Python/zigzag-conversion.py +++ b/Python/zigzag-conversion.py @@ -14,20 +14,22 @@ # convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR". # -class Solution: - # @return a string - def convert(self, s, nRows): - step, zigzag = 2 * nRows - 2, "" - if s == None or len(s) == 0 or nRows <= 0: - return "" - if nRows == 1: +class Solution(object): + def convert(self, s, numRows): + """ + :type s: str + :type numRows: int + :rtype: str + """ + if numRows == 1: return s - for i in xrange(nRows): + step, zigzag = 2 * numRows - 2, "" + for i in xrange(numRows): for j in xrange(i, len(s), step): zigzag += s[j] - if i > 0 and i < nRows - 1 and j + step - 2 * i < len(s): + if 0 < i < numRows - 1 and j + step - 2 * i < len(s): zigzag += s[j + step - 2 * i] return zigzag if __name__ == "__main__": - print Solution().convert("PAYPALISHIRING", 3) \ No newline at end of file + print Solution().convert("PAYPALISHIRING", 3) diff --git a/Python/zigzag-iterator.py b/Python/zigzag-iterator.py new file mode 100644 index 000000000..9936e2d52 --- /dev/null +++ b/Python/zigzag-iterator.py @@ -0,0 +1,31 @@ +# Time: O(n) +# Space: O(k) + +class ZigzagIterator(object): + + def __init__(self, v1, v2): + """ + Initialize your q structure here. + :type v1: List[int] + :type v2: List[int] + """ + self.q = collections.deque([(len(v), iter(v)) for v in (v1, v2) if v]) + + def next(self): + """ + :rtype: int + """ + len, iter = self.q.popleft() + if len > 1: + self.q.append((len-1, iter)) + return next(iter) + + def hasNext(self): + """ + :rtype: bool + """ + return bool(self.q) + +# Your ZigzagIterator object will be instantiated and called as such: +# i, v = ZigzagIterator(v1, v2), [] +# while i.hasNext(): v.append(i.next()) diff --git a/Python/zuma-game.py b/Python/zuma-game.py new file mode 100644 index 000000000..1af644c93 --- /dev/null +++ b/Python/zuma-game.py @@ -0,0 +1,104 @@ +# Time: O(b * b! * h!) +# Space: O(b * b! * h!) + +# Think about Zuma Game. You have a row of balls on the table, +# colored red(R), yellow(Y), blue(B), green(G), and white(W). +# You also have several balls in your hand. +# +# Each time, you may choose a ball in your hand, and insert it into the row +# (including the leftmost place and rightmost place). +# Then, if there is a group of 3 or more balls in the same color touching, +# remove these balls. Keep doing this until no more balls can be removed. +# +# Find the minimal balls you have to insert to remove all the balls on the table. +# If you cannot remove all the balls, output -1. +# +# Examples: +# +# Input: "WRRBBW", "RB" +# Output: -1 +# Explanation: WRRBBW -> WRR[R]BBW -> WBBW -> WBB[B]W -> WW +# +# Input: "WWRRBBWW", "WRBRW" +# Output: 2 +# Explanation: WWRRBBWW -> WWRR[R]BBWW -> WWBBWW -> WWBB[B]WW -> WWWW -> empty +# +# Input:"G", "GGGGG" +# Output: 2 +# Explanation: G -> G[G] -> GG[G] -> empty +# +# Input: "RBYYBBRRB", "YRBGB" +# Output: 3 +# Explanation: RBYYBBRRB -> RBYY[Y]BBRRB -> RBBBRRB -> RRRB -> B -> B[B] -> BB[B] -> empty +# +# Note: +# You may assume that the initial row of balls on the table won’t have any 3 or +# more consecutive balls with the same color. +# The number of balls on the table won't exceed 20, and the string represents these balls +# is called "board" in the input. +# The number of balls in your hand won't exceed 5, and the string represents these balls +# is called "hand" in the input. +# Both input strings will be non-empty and only contain characters 'R','Y','B','G','W'. + +class Solution(object): + def findMinStep(self, board, hand): + """ + :type board: str + :type hand: str + :rtype: int + """ + def shrink(s): # Time: O(n), Space: O(n) + stack = [] + start = 0 + for i in xrange(len(s)+1): + if i == len(s) or s[i] != s[start]: + if stack and stack[-1][0] == s[start]: + stack[-1][1] += i - start + if stack[-1][1] >= 3: + stack.pop() + elif s and i - start < 3: + stack += [s[start], i - start], + start = i + result = [] + for p in stack: + result += [p[0]] * p[1] + return result + + def find(board, c, j): + for i in xrange(j, len(board)): + if board[i] == c: + return i + return -1 + + def findMinStepHelper(board, hand, lookup): + if not board: return 0 + if not hand: return float("inf") + if tuple(hand) in lookup[tuple(board)]: return lookup[tuple(board)][tuple(hand)] + + result = float("inf") + for i in xrange(len(hand)): + j = 0 + while j < len(board): + k = find(board, hand[i], j) + if k == -1: + break + + if k < len(board) - 1 and board[k] == board[k+1]: + next_board = shrink(board[0:k] + board[k+2:]) + next_hand = hand[0:i] + hand[i+1:] + result = min(result, findMinStepHelper(next_board, next_hand, lookup) + 1) + k += 1 + elif i > 0 and hand[i] == hand[i-1]: + next_board = shrink(board[0:k] + board[k+1:]) + next_hand = hand[0:i-1] + hand[i+1:] + result = min(result, findMinStepHelper(next_board, next_hand, lookup) + 2) + j = k+1 + + lookup[tuple(board)][tuple(hand)] = result + return result + + lookup = collections.defaultdict(dict) + board, hand = list(board), list(hand) + hand.sort() + result = findMinStepHelper(board, hand, lookup) + return -1 if result == float("inf") else result diff --git a/README.md b/README.md index c7c3ea16e..7c4199197 100644 --- a/README.md +++ b/README.md @@ -1,734 +1,761 @@ -LeetCode -======== +# [LeetCode](https://leetcode.com/problemset/algorithms/) ![Language](https://img.shields.io/badge/language-Python%20%2F%20C++%2011-orange.svg) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.md) [![SayThanks](https://img.shields.io/badge/say-thanks-ff69b4.svg)](https://saythanks.io/to/kamyu104) -Up to date (2015-01-13), there are total `180` problems on [LeetCode Online Judge](https://oj.leetcode.com/). -The number of problems is increasing recently. -Here is the classification of all `180` problems. +The number of LeetCode questions is increasing every week. +For more questions and solutions, you can see my [LintCode](https://github.com/kamyu104/LintCode) repository. I'll keep updating for full summary and better solutions. Stay tuned for updates. +(Notes: "📖" means you need to subscribe to [LeetCode premium membership](https://leetcode.com/subscribe/) for the access to premium questions.) ---- -Algorithm -==== +## Algorithms * [Bit Manipulation](https://github.com/kamyu104/LeetCode#bit-manipulation) * [Array](https://github.com/kamyu104/LeetCode#array) * [String](https://github.com/kamyu104/LeetCode#string) * [Linked List](https://github.com/kamyu104/LeetCode#linked-list) * [Stack](https://github.com/kamyu104/LeetCode#stack) +* [Queue](https://github.com/kamyu104/LeetCode#queue) * [Heap](https://github.com/kamyu104/LeetCode#heap) * [Tree](https://github.com/kamyu104/LeetCode#tree) * [Hash Table](https://github.com/kamyu104/LeetCode#hash-table) -* [Data Structure](https://github.com/kamyu104/LeetCode#data-structure) * [Math](https://github.com/kamyu104/LeetCode#math) -* [Two Pointer](https://github.com/kamyu104/LeetCode#two-pointer) +* [Two Pointers](https://github.com/kamyu104/LeetCode#two-pointers) * [Sort](https://github.com/kamyu104/LeetCode#sort) -* [Brute Force Search](https://github.com/kamyu104/LeetCode#brute-force-search) -* [Divide and Conquer](https://github.com/kamyu104/LeetCode#divide-and-conquer) +* [Recursion](https://github.com/kamyu104/LeetCode#recursion) * [Binary Search](https://github.com/kamyu104/LeetCode#binary-search) +* [Binary Search Tree](https://github.com/kamyu104/LeetCode#binary-search-tree) * [Breadth-First Search](https://github.com/kamyu104/LeetCode#breadth-first-search) * [Depth-First Search](https://github.com/kamyu104/LeetCode#depth-first-search) -* [Dynamic Programming](https://github.com/kamyu104/LeetCode#dynamic-programming) * [Backtracking](https://github.com/kamyu104/LeetCode#backtracking) +* [Dynamic Programming](https://github.com/kamyu104/LeetCode#dynamic-programming) * [Greedy](https://github.com/kamyu104/LeetCode#greedy) +* [Geometry](https://github.com/kamyu104/LeetCode#geometry) +* [Design](https://github.com/kamyu104/LeetCode#design) -Database -=== +## Database * [SQL](https://github.com/kamyu104/LeetCode#sql) ---- - -##Bit Manipulation -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Single Number] | [single-number.py] | _O(n)_ | _O(1)_ | Medium | -[Single Number II] | [single-number-ii.py] | _O(n)_ | _O(1)_ | Medium | - -[Single Number]: https://oj.leetcode.com/problems/single-number/ -[single-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/single-number.py -[Single Number II]: https://oj.leetcode.com/problems/single-number-ii/ -[single-number-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/single-number-ii.py - ---- - -##Array - -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[3 Sum] | [3sum.py] | _O(n^2)_ | _O(1)_ | Medium | -[3 Sum Closest] | [3sum-closest.py]| _O(n^2)_ | _O(1)_ | Medium | -[Best Time to Buy and Sell Stock]| [best-time-to-buy-and-sell-stock.py] | _O(n)_ | _O(1)_ | Medium | -[First Missing Positive]| [first-missing-positive.py] | _O(n)_ | _O(1)_ | Hard | Tricky -[Longest Consecutive Sequence]| [longest-consecutive-sequence.py] | _O(n)_ | _O(n)_ | Hard | Tricky -[Majority Element] | [majority-element.py] | _O(n)_ | _O(1)_ | Easy | -[Missing Ranges]| [missing-ranges.py] | _O(n)_ | _O(1)_ | Medium | -[Next Permutation]| [next-permutation.py] | _O(n)_ | _O(1)_ | Medium | Tricky -[Pascal's Triangle]| [pascals-triangle.py] | _O(n^2)_ | _O(n)_ | Easy | -[Pascal's Triangle II]| [pascals-triangle-ii.py] | _O(n^2)_ | _O(n)_ | Easy | -[Plus One] | [plus-one.py] | _O(n)_ | _O(1)_ | Easy | -[Read N Characters Given Read4] | [read-n-characters-given-read4.py] | _O(n)_ | _O(1)_ | Easy | -[Read N Characters Given Read4 II - Call multiple times] | [read-n-characters-given-read4-ii-call-multiple-times.py] | _O(n)_ | _O(1)_ | Hard | -[Remove Duplicates from Sorted Array]| [remove-duplicates-from-sorted-array.py] | _O(n)_ | _O(1)_ | Easy | -[Remove Duplicates from Sorted Array II]| [remove-duplicates-from-sorted-array-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Remove Element] | [remove-element.py] | _O(n)_ | _O(1)_ | Easy | -[Rotate Image] | [rotate-image.py] | _O(n^2)_ | _O(1)_ | Medium | -[Set Matrix Zeroes] | [set-matrix-zeroes.py] | _O(m * n)_ | _O(1)_ | Medium | -[Spiral Matrix] | [spiral-matrix.py] | _O(m * n)_ | _O(1)_ | Medium | -[Spiral Matrix II] | [spiral-matrix-ii.py] | _O(m * n)_ | _O(1)_ | Medium | - - -[3 Sum]: https://oj.leetcode.com/problems/3sum/ -[3sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/3sum.py -[3 Sum Closest]: https://oj.leetcode.com/problems/3sum-closest/ -[3sum-closest.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/3sum-closest.py -[Best Time to Buy and Sell Stock]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock/ -[best-time-to-buy-and-sell-stock.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock.py -[First Missing Positive]:https://oj.leetcode.com/problems/first-missing-positive/ -[first-missing-positive.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/first-missing-positive.py -[Longest Consecutive Sequence]:https://oj.leetcode.com/problems/longest-consecutive-sequence/ -[longest-consecutive-sequence.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-consecutive-sequence.py -[Majority Element]: https://oj.leetcode.com/problems/majority-element/ -[majority-element.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/majority-element.py -[Missing Ranges]:https://oj.leetcode.com/problems/missing-ranges/ -[missing-ranges.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/missing-ranges.py -[Next Permutation]:https://oj.leetcode.com/problems/next-permutation/ -[next-permutation.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/next-permutation.py -[Pascal's Triangle]:https://oj.leetcode.com/problems/pascals-triangle/ -[pascals-triangle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/pascals-triangle.py -[Pascal's Triangle II]:https://oj.leetcode.com/problems/pascals-triangle-ii/ -[pascals-triangle-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/pascals-triangle-ii.py -[Plus One]:https://oj.leetcode.com/problems/plus-one/ -[plus-one.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/plus-one.py -[Read N Characters Given Read4]:https://oj.leetcode.com/problems/read-n-characters-given-read4/ -[read-n-characters-given-read4.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/read-n-characters-given-read4.py -[Read N Characters Given Read4 II - Call multiple times]:https://oj.leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/ -[read-n-characters-given-read4-ii-call-multiple-times.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/read-n-characters-given-read4-ii-call-multiple-times.py -[Remove Duplicates from Sorted Array]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-array/ -[remove-duplicates-from-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-array.py -[Remove Duplicates from Sorted Array II]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-array-ii/ -[remove-duplicates-from-sorted-array-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-array-ii.py -[Remove Element]:https://oj.leetcode.com/problems/remove-element/ -[remove-element.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-element.py -[Rotate Image]:https://oj.leetcode.com/problems/rotate-image/ -[rotate-image.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/rotate-image.py -[Set Matrix Zeroes]:https://oj.leetcode.com/problems/set-matrix-zeroes/ -[set-matrix-zeroes.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/set-matrix-zeroes.py -[Spiral Matrix]:https://oj.leetcode.com/problems/spiral-matrix/ -[spiral-matrix.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/spiral-matrix.py -[Spiral Matrix II]:https://oj.leetcode.com/problems/spiral-matrix-ii/ -[spiral-matrix-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/spiral-matrix-ii.py - - ---- - -##String -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Add Binary] | [add-binary.py] | _O(n)_ | _O(1)_ | Easy | -[Anagrams] | [anagrams.py] | _O(n)_ | _O(n)_ | Medium | -[Compare Version Numbers] | [compare-version-numbers.py] | _O(n)_ | _O(1)_ | Easy | -[Count and Say] | [count-and-say.py]| _O(n^2)_ | _O(n)_ | Easy | -[Implement strStr()] | [implement-strstr.py] | _O(n + m)_ | _O(m)_ | Easy | `KMP Algorithm` -[Length of Last Word] | [length-of-last-word.py] | _O(n)_ | _O(1)_ | Easy | -[Longest Common Prefix] | [longest-common-prefix.py] | _O(n1 + n2 + ...)_ | _O(1)_ | Easy | -[Longest Palindromic Substring] | [longest-palindromic-substring.py] | _O(n)_ | _O(n)_ | Medium | `Manacher's Algorithm` -[Multiply Strings] | [multiply-strings.py] | _O(m * n)_ | _O(m + n)_ | Medium | -[One Edit Distance] | [one-edit-distance.py] | _O(m + n)_ | _O(1)_ | Medium | -[Reverse Words in a String] | [reverse-words-in-a-string.py] | _O(n)_ | _O(n)_ | Medium | -[String to Integer (atoi)] | [string-to-integer-atoi.py] | _O(n)_ | _O(1)_ | Easy | -[Text Justification] | [text-justification.py] | _O(n)_ | _O(1)_ | Hard | -[Valid Palindrome] | [valid-palindrome.py] | _O(n)_ | _O(1)_ | Easy | -[ZigZag Conversion] | [zigzag-conversion.py] | _O(n)_ | _O(1)_ | Easy | - -[Add Binary]:https://oj.leetcode.com/problems/add-binary/ -[add-binary.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/add-binary.py -[Anagrams]:https://oj.leetcode.com/problems/anagrams/ -[anagrams.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/anagrams.py -[Count and Say]:https://oj.leetcode.com/problems/count-and-say/ -[count-and-say.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/count-and-say.py -[Compare Version Numbers]:https://oj.leetcode.com/problems/compare-version-numbers/ -[compare-version-numbers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/compare-version-numbers.py -[Implement strStr()]:https://oj.leetcode.com/problems/implement-strstr/ -[implement-strstr.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/implement-strstr.py -[Length of Last Word]:https://oj.leetcode.com/problems/length-of-last-word/ -[length-of-last-word.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/length-of-last-word.py -[Longest Common Prefix]:https://oj.leetcode.com/problems/longest-common-prefix/ -[longest-common-prefix.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-common-prefix.py -[Longest Palindromic Substring]:https://oj.leetcode.com/problems/longest-palindromic-substring/ -[longest-palindromic-substring.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-palindromic-substring.py -[Multiply Strings]:https://oj.leetcode.com/problems/multiply-strings/ -[multiply-strings.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/multiply-strings.py - -[One Edit Distance]:https://oj.leetcode.com/problems/one-edit-distance/ -[one-edit-distance.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/one-edit-distance.py -[Reverse Words in a String]:https://oj.leetcode.com/problems/reverse-words-in-a-string/ -[reverse-words-in-a-string.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-words-in-a-string.py -[String to Integer (atoi)]:https://oj.leetcode.com/problems/string-to-integer-atoi/ -[string-to-integer-atoi.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/string-to-integer-atoi.py -[Text Justification]:https://oj.leetcode.com/problems/text-justification/ -[text-justification.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/text-justification.py -[Valid Palindrome]:https://oj.leetcode.com/problems/valid-palindrome/ -[valid-palindrome.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-palindrome.py -[ZigZag Conversion]:https://oj.leetcode.com/problems/zigzag-conversion/ -[zigzag-conversion.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/zigzag-conversion.py - ---- - -##Linked List -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Add Two Numbers] | [add-two-numbers.py] | _O(n)_ | _O(1)_ | Medium | -[Copy List with Random Pointer] | [copy-list-with-random-pointer.py] | _O(n)_ | _O(1)_ | Hard | -[Intersection of Two Linked Lists]| [intersection-of-two-linked-lists.py] | _O(m + n)_ | _O(1)_ | Easy | -[Remove Duplicates from Sorted List]| [remove-duplicates-from-sorted-list.py] | _O(n)_ | _O(1)_ | Easy | -[Remove Duplicates from Sorted List II]| [remove-duplicates-from-sorted-list-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Reverse Linked List II]| [reverse-linked-list-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Reverse Nodes in k-Group]| [reverse-nodes-in-k-group.py] | _O(n)_ | _O(1)_ | Hard | -[Rotate List]| [rotate-list.py] | _O(n)_ | _O(1)_ | Medium | -[Swap Nodes in Pairs]| [swap-nodes-in-pairs.py] | _O(n)_ | _O(1)_ | Medium | - -[Add Two Numbers]:https://oj.leetcode.com/problems/add-two-numbers/ -[add-two-numbers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/add-two-numbers.py -[Copy List with Random Pointer]:https://oj.leetcode.com/problems/copy-list-with-random-pointer/ -[copy-list-with-random-pointer.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/copy-list-with-random-pointer.py -[Intersection of Two Linked Lists]:https://oj.leetcode.com/problems/intersection-of-two-linked-lists/ -[intersection-of-two-linked-lists.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/intersection-of-two-linked-lists.py -[Remove Duplicates from Sorted List]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-list/ -[remove-duplicates-from-sorted-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-list.py -[Remove Duplicates from Sorted List II]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ -[remove-duplicates-from-sorted-list-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-list-ii.py -[Reverse Linked List II]:https://oj.leetcode.com/problems/reverse-linked-list-ii/ -[reverse-linked-list-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-linked-list-ii.py -[Reverse Nodes in k-Group]:https://oj.leetcode.com/problems/reverse-nodes-in-k-group/ -[reverse-nodes-in-k-group.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-nodes-in-k-group.py -[Rotate List]:https://oj.leetcode.com/problems/rotate-list/ -[rotate-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/rotate-list.py -[Swap Nodes in Pairs]:https://oj.leetcode.com/problems/swap-nodes-in-pairs/ -[swap-nodes-in-pairs.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/swap-nodes-in-pairs.py - ---- - -##Stack -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Binary Search Tree Iterator] | [binary-search-tree-iterator.py] | _O(1)_| _O(logn)_| Medium -[Evaluate Reverse Polish Notation]| [evaluate-reverse-polish-notation.py]| _O(n)_| _O(n)_| Medium | -[Longest Valid Parentheses]| [longest-valid-parentheses.py] | _O(n)_ | _O(1)_ | Hard | -[Min Stack] | [min-stack.py] | _O(n)_ | _O(1)_ | Easy | -[Simplify Path]| [simplify-path.py] | _O(n)_ | _O(n)_ | Medium | -[Symmetric Tree]| [symmetric-tree.py] | _O(n)_ | _O(logn)_ | Easy | -[Valid Parentheses]| [valid-parentheses.py] | _O(n)_ | _O(n)_ | Easy | - -[Binary Search Tree Iterator]:https://oj.leetcode.com/problems/binary-search-tree-iterator/ -[binary-search-tree-iterator.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-search-tree-iterator.py -[Evaluate Reverse Polish Notation]:https://oj.leetcode.com/problems/evaluate-reverse-polish-notation/ -[evaluate-reverse-polish-notation.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/evaluate-reverse-polish-notation.py -[Longest Valid Parentheses]:https://oj.leetcode.com/problems/longest-valid-parentheses/ -[longest-valid-parentheses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-valid-parentheses.py -[Min Stack]:https://oj.leetcode.com/problems/min-stack/ -[min-stack.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/min-stack.py -[Simplify Path]:https://oj.leetcode.com/problems/simplify-path/ -[simplify-path.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/simplify-path.py -[Symmetric Tree]:https://oj.leetcode.com/problems/symmetric-tree/ -[symmetric-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/symmetric-tree.py -[Valid Parentheses]:https://oj.leetcode.com/problems/valid-parentheses/ -[valid-parentheses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-parentheses.py - ---- - -##Heap -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Merge k Sorted Lists] | [merge-k-sorted-lists.py] | _O(nlogk)_| _O(1)_| Hard | - -[Merge k Sorted Lists]:https://oj.leetcode.com/problems/merge-k-sorted-lists/ -[merge-k-sorted-lists.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-k-sorted-lists.py - ---- - -##Tree -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Binary Tree Preorder Traversal] | [binary-tree-preorder-traversal.py] | _O(n)_| _O(1)_| Medium | `Morris Traversal` -[Binary Tree Inorder Traversal] | [binary-tree-inorder-traversal.py] | _O(n)_| _O(1)_| Medium | `Morris Traversal` -[Binary Tree Postorder Traversal]| [binary-tree-postorder-traversal.py] | _O(n)_| _O(1)_| Hard | `Morris Traversal` -[Recover Binary Search Tree]| [recover-binary-search-tree.py] | _O(n)_| _O(1)_| Hard | `Morris Traversal` - -[Binary Tree Preorder Traversal]:https://oj.leetcode.com/problems/binary-tree-preorder-traversal/ -[binary-tree-preorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-preorder-traversal.py -[Binary Tree Inorder Traversal]:https://oj.leetcode.com/problems/binary-tree-inorder-traversal/ -[binary-tree-inorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-inorder-traversal.py -[Binary Tree Postorder Traversal]:https://oj.leetcode.com/problems/binary-tree-postorder-traversal/ -[binary-tree-postorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-postorder-traversal.py -[Recover Binary Search Tree]:https://oj.leetcode.com/problems/recover-binary-search-tree/ -[recover-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/recover-binary-search-tree.py - ---- - -##Hash Table -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[4 Sum] |[4sum.py] | _O(n^2)_ ~ _O(n^4)_ | _O(n^2)_ | Medium | -[Longest Substring with At Most Two Distinct Characters]| [longest-substring-with-at-most-two-distinct-characters.py] | _O(n^2)_ | _O(1)_ | Hard | -[Longest Substring Without Repeating Characters] | [longest-substring-without-repeating-characters.py] | _O(n)_ | _O(1)_ | Medium | -[Max Points on a Line] | [max-points-on-a-line.py] | _O(n^2)_ | _O(n)_ | Hard | -[Minimum Window Substring] | [minimum-window-substring.py] | _O(n^2)_ | _O(n)_ | Hard | -[Substring with Concatenation of All Words] | [substring-with-concatenation-of-all-words.py] | _O(m * n * k)_ | _O(n * k)_ | Hard | -[Two Sum] | [two-sum.py] | _O(n)_ | _O(n)_ | Medium | -[Two Sum III - Data structure design] | [two-sum-iii-data-structure-design.py] | _O(n)_ | _O(n)_ | Easy | -[Valid Sudoku] | [valid-sudoku.py] | _O(n)_ | _O(n)_ | Easy | - -[4 Sum]: https://oj.leetcode.com/problems/4sum/ -[4sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/4sum.py -[Longest Substring with At Most Two Distinct Characters]:https://oj.leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/ -[longest-substring-with-at-most-two-distinct-characters.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-substring-with-at-most-two-distinct-characters.py -[Longest Substring Without Repeating Characters]:https://oj.leetcode.com/problems/longest-substring-without-repeating-characters/ -[longest-substring-without-repeating-characters.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-substring-without-repeating-characters.py -[Max Points on a Line]:https://oj.leetcode.com/problems/max-points-on-a-line/ -[max-points-on-a-line.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/max-points-on-a-line.py -[Minimum Window Substring]:https://oj.leetcode.com/problems/minimum-window-substring/ -[minimum-window-substring.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/minimum-window-substring.py -[Substring with Concatenation of All Words]:https://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/ -[substring-with-concatenation-of-all-words.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/substring-with-concatenation-of-all-words.py -[Two Sum]:https://oj.leetcode.com/problems/two-sum/ -[two-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/two-sum.py -[Two Sum III - Data structure design]:https://oj.leetcode.com/problems/two-sum-iii-data-structure-design/ -[two-sum-iii-data-structure-design.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/two-sum-iii-data-structure-design.py -[Valid Sudoku]:https://oj.leetcode.com/problems/valid-sudoku/ -[valid-sudoku.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-sudoku.py - ---- - -##Data Structure -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[LRU Cache] | [lru-cache.py] | _O(1)_ | _O(n)_ | Hard | - - -[LRU Cache]:https://oj.leetcode.com/problems/lru-cache/ -[lru-cache.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/lru-cache.py - ---- - -##Math -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Divide Two Integers] | [divide-two-integers.py] | _O(logn)_ | _O(1)_ | Medium | -[Excel Sheet Column Title] | [excel-sheet-column-title.py] | _O(logn)_ | _O(1)_ | Easy | -[Excel Sheet Column Number] | [excel-sheet-column-number.py] | _O(n)_ | _O(1)_ | Easy | -[Factorial Trailing Zeroes] | [factorial-trailing-zeroes.py] | _O(logn)_ | _O(1)_ | Easy | -[Fraction to Recurring Decimal] | [fraction-to-recurring-decimal.py] | _O(logn)_ | _O(1)_ | Medium | -[Gray Code] | [gray-code.py] | _O(2^n)_ | _O(1)_ | Medium | -[Integer to Roman] | [integer-to-roman.py] | _O(n)_ | _O(1)_ | Medium | -[Palindrome Number] | [palindrome-number.py] | _O(1)_ | _O(1)_ | Easy | -[Permutation Sequence] | [permutation-sequence.py] | _O(n)_ | _O(1)_ | Medium | `Cantor Ordering` -[Reverse Integer] | [reverse-integer.py] | _O(logn)_ | _O(1)_ | Easy | -[Roman to Integer] | [roman-to-integer.py] | _O(n)_ | _O(1)_ | Easy | -[Valid Number] | [valid-number.py] | _O(n)_ | _O(1)_ | Hard | `Automata` - -[Divide Two Integers]:https://oj.leetcode.com/problems/divide-two-integers/ -[divide-two-integers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/divide-two-integers.py -[Excel Sheet Column Title]:https://oj.leetcode.com/problems/excel-sheet-column-title/ -[excel-sheet-column-title.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/excel-sheet-column-title.py -[Excel Sheet Column Number]:https://oj.leetcode.com/problems/excel-sheet-column-number/ -[excel-sheet-column-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/excel-sheet-column-number.py -[Factorial Trailing Zeroes]:https://oj.leetcode.com/problems/factorial-trailing-zeroes/ -[factorial-trailing-zeroes.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/factorial-trailing-zeroes.py -[Fraction to Recurring Decimal]:https://oj.leetcode.com/problems/fraction-to-recurring-decimal/ -[fraction-to-recurring-decimal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/fraction-to-recurring-decimal.py -[Gray Code]:https://oj.leetcode.com/problems/gray-code/ -[gray-code.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/gray-code.py -[Integer to Roman]:https://oj.leetcode.com/problems/integer-to-roman/ -[integer-to-roman.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/integer-to-roman.py -[Palindrome Number]:https://oj.leetcode.com/problems/palindrome-number/ -[palindrome-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/palindrome-number.py -[Permutation Sequence]:https://oj.leetcode.com/problems/permutation-sequence/ -[permutation-sequence.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/permutation-sequence.py -[Reverse Integer]:https://oj.leetcode.com/problems/reverse-integer/ -[reverse-integer.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-integer.py -[Roman to Integer]:https://oj.leetcode.com/problems/roman-to-integer/ -[roman-to-integer.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/roman-to-integer.py -[Valid Number]:https://oj.leetcode.com/problems/valid-number/ -[valid-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-number.py - - ---- - -##Sort -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Insert Interval]| [insert-interval.py] | _O(n)_ | _O(1)_ | Hard | -[Insertion Sort List]|[insertion-sort-list.py] | _O(n^2)_ | _O(1)_ | Medium | -[Largest Number] | [largest-number.py] | _O(n^2)_ | _O(n)_ | Medium | -[Maximum Gap] | [maximum-gap.py]| _O(n)_ | _O(n)_ | Hard | Tricky -[Merge Intervals]| [merge-intervals.py] | _O(n^2)_ | _O(1)_ | Hard | -[Merge Sorted Array]| [merge-sorted-array.py] | _O(n)_ | _O(1)_ | Easy | -[Merge Two Sorted Lists]| [merge-two-sorted-lists.py] | _O(n)_ | _O(1)_ | Easy | -[Sort Colors] | [sort-colors.py] | _O(n)_ | _O(1)_ | Medium | -[Sort List] | [sort-list.py] | _O(nlogn)_ | _O(1)_ | Medium | - -[Insert Interval]:https://oj.leetcode.com/problems/insert-interval/ -[insert-interval.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/insert-interval.py -[Insertion Sort List]:https://oj.leetcode.com/problems/insertion-sort-list/ -[insertion-sort-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/insertion-sort-list.py -[Largest Number]:https://oj.leetcode.com/problems/largest-number/ -[largest-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/largest-number.py -[Maximum Gap]:https://oj.leetcode.com/problems/maximum-gap/ -[maximum-gap.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-gap.py -[Merge Intervals]:https://oj.leetcode.com/problems/merge-intervals/ -[merge-intervals.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-intervals.py -[Merge Sorted Array]:https://oj.leetcode.com/problems/merge-sorted-array/ -[merge-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-sorted-array.py -[Merge Two Sorted Lists]:https://oj.leetcode.com/problems/merge-two-sorted-lists/ -[merge-two-sorted-lists.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-two-sorted-lists.py -[Sort Colors]:https://oj.leetcode.com/problems/sort-colors/ -[sort-colors.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sort-colors.py -[Sort List]:https://oj.leetcode.com/problems/sort-list/ -[sort-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sort-list.py - ---- - -##Two Pointer -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Linked List Cycle]| [linked-list-cycle.py] | _O(n)_ | _O(1)_ | Medium | -[Linked List Cycle II]| [linked-list-cycle-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Partition List]| [partition-list.py] | _O(n)_ | _O(1)_ | Medium | -[Remove Nth Node From End of List]| [remove-nth-node-from-end-of-list.py] | _O(n)_ | _O(1)_ | Easy | -[Reorder List]| [reorder-list.py] | _O(n)_ | _O(1)_ | Medium | -[Two Sum II - Input array is sorted] | [two-sum-ii-input-array-is-sorted.py] | _O(n)_ | _O(1)_ | Medium | - -[Linked List Cycle]:https://oj.leetcode.com/problems/linked-list-cycle/ -[linked-list-cycle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/linked-list-cycle.py -[Linked List Cycle II]:https://oj.leetcode.com/problems/linked-list-cycle-ii/ -[linked-list-cycle-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/linked-list-cycle-ii.py -[Partition List]:https://oj.leetcode.com/problems/partition-list/ -[partition-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/partition-list.py -[Remove Nth Node From End of List]:https://oj.leetcode.com/problems/remove-nth-node-from-end-of-list/ -[remove-nth-node-from-end-of-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-nth-node-from-end-of-list.py -[Reorder List]:https://oj.leetcode.com/problems/reorder-list/ -[reorder-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reorder-list.py -[Two Sum II - Input array is sorted]:https://oj.leetcode.com/problems/two-sum-ii-input-array-is-sorted/ -[two-sum-ii-input-array-is-sorted.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/two-sum-ii-input-array-is-sorted.py - ---- - -##Brute Force Search -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Letter Combinations of a Phone Number]| [letter-combinations-of-a-phone-number.py] | _O(4^n)_ | _O(1)_ | Medium | -[Permutations]| [permutations.py] | _O(n!)_ | _O(n)_ | Medium | -[Permutations II]| [permutations-ii.py] | _O(n!)_ | _O(n)_ | Hard | -[Subsets] | [subsets.py] | _O(2^n)_ | _O(1)_ | Medium | -[Subsets II] | [subsets-ii.py] | _O(2^n)_ | _O(1)_ | Medium | - -[Letter Combinations of a Phone Number]:https://oj.leetcode.com/problems/letter-combinations-of-a-phone-number/ -[letter-combinations-of-a-phone-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/letter-combinations-of-a-phone-number.py -[Permutations]:https://oj.leetcode.com/problems/permutations/ -[permutations.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/permutations.py -[Permutations II]:https://oj.leetcode.com/problems/permutations-ii/ -[permutations-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/permutations-ii.py -[Subsets]:https://oj.leetcode.com/problems/subsets/ -[subsets.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/subsets.py -[Subsets II]:https://oj.leetcode.com/problems/subsets-ii/ -[subsets-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/subsets-ii.py - ---- - -##Divide and Conquer -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Balanced Binary Tree] | [balanced-binary-tree.py] | _O(n)_| _O(logn)_| Easy | -[Binary Tree Maximum Path Sum]| [binary-tree-maximum-path-sum.py] | _O(n)_| _O(logn)_| Hard | -[Binary Tree Upside Down] | [binary-tree-upside-down.py] | _O(n)_ | _O(1)_ | Medium | -[Construct Binary Tree from Inorder and Postorder Traversal] | [construct-binary-tree-from-inorder-and-postorder-traversal.py] | _O(n)_ | _O(n)_ | Medium | -[Construct Binary Tree from Preorder and Inorder Traversal] | [construct-binary-tree-from-preorder-and-inorder-traversal.py] | _O(n)_ | _O(n)_ | Medium -[Convert Sorted Array to Binary Search Tree] | [convert-sorted-array-to-binary-search-tree.py] | _O(n)_ | _O(logn)_ | Medium | -[Convert Sorted List to Binary Search Tree] | [convert-sorted-list-to-binary-search-tree.py] | _O(n)_ | _O(logn)_ | Medium | -[Flatten Binary Tree to Linked List]|[flatten-binary-tree-to-linked-list.py]| _O(n)_ | _O(logn)_ | Medium | -[Maximum Depth of Binary Tree]|[maximum-depth-of-binary-tree.py]| _O(n)_ | _O(logn)_ | Easy | -[Minimum Depth of Binary Tree]|[minimum-depth-of-binary-tree.py]| _O(n)_ | _O(logn)_ | Easy | -[Populating Next Right Pointers in Each Node]|[populating-next-right-pointers-in-each-node.py]| _O(n)_ | _O(logn)_ | Medium | -[Same Tree] |[same-tree.py] | _O(n)_ | _O(logn)_ | Easy | -[Sum Root to Leaf Numbers] | [sum-root-to-leaf-numbers.py] | _O(n)_ | _O(logn)_ | Medium | -[Unique Binary Search Trees II] | [unique-binary-search-trees-ii.py] | _O(4^n / n^(3/2)_ | _O(4^n / n^(3/2)_ | Medium | -[Validate Binary Search Tree]|[validate-binary-search-tree.py]| _O(n)_ | _O(logn)_ | Medium | - -[Balanced Binary Tree]:https://oj.leetcode.com/problems/balanced-binary-tree/ -[balanced-binary-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/balanced-binary-tree.py -[Binary Tree Maximum Path Sum]:https://oj.leetcode.com/problems/binary-tree-maximum-path-sum/ -[binary-tree-maximum-path-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-maximum-path-sum.py -[Binary Tree Upside Down]:https://oj.leetcode.com/problems/binary-tree-upside-down/ -[binary-tree-upside-down.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-upside-down.py -[Construct Binary Tree from Inorder and Postorder Traversal]:https://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/ -[construct-binary-tree-from-inorder-and-postorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/construct-binary-tree-from-inorder-and-postorder-traversal.py -[Construct Binary Tree from Preorder and Inorder Traversal]:https://oj.leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ -[construct-binary-tree-from-preorder-and-inorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/construct-binary-tree-from-preorder-and-inorder-traversal.py -[Convert Sorted Array to Binary Search Tree]:https://oj.leetcode.com/problems/convert-sorted-array-to-binary-search-tree/ -[convert-sorted-array-to-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/convert-sorted-array-to-binary-search-tree.py -[Convert Sorted List to Binary Search Tree]:https://oj.leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ -[convert-sorted-list-to-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/convert-sorted-list-to-binary-search-tree.py -[Flatten Binary Tree to Linked List]:https://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/ -[flatten-binary-tree-to-linked-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/flatten-binary-tree-to-linked-list.py -[Maximum Depth of Binary Tree]:https://oj.leetcode.com/problems/maximum-depth-of-binary-tree/ -[maximum-depth-of-binary-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-depth-of-binary-tree.py -[Minimum Depth of Binary Tree]:https://oj.leetcode.com/problems/minimum-depth-of-binary-tree/ -[minimum-depth-of-binary-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/minimum-depth-of-binary-tree.py -[Populating Next Right Pointers in Each Node]:https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node/ -[populating-next-right-pointers-in-each-node.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/populating-next-right-pointers-in-each-node.py -[Same Tree]:https://oj.leetcode.com/problems/same-tree/ -[same-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/same-tree.py -[Sum Root to Leaf Numbers]:https://oj.leetcode.com/problems/sum-root-to-leaf-numbers/ -[sum-root-to-leaf-numbers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sum-root-to-leaf-numbers.py -[Unique Binary Search Trees II]:https://oj.leetcode.com/problems/unique-binary-search-trees-ii/ -[unique-binary-search-trees-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-binary-search-trees-ii.py -[Validate Binary Search Tree]:https://oj.leetcode.com/problems/validate-binary-search-tree.py/ -[validate-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/validate-binary-search-tree.py - - ---- - -##Binary Search - -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Find Minimum in Rotated Sorted Array] | [find-minimum-in-rotated-sorted-array.py] | _O(logn)_ | _O(1)_ | Medium | -[Find Minimum in Rotated Sorted Array II] | [find-minimum-in-rotated-sorted-array-ii.py] | _O(logn)_ ~ _O(n)_ | _O(1)_ | Hard | -[Find Peak Element] | [find-peak-element.py] | _O(logn)_ | _O(1)_ | Medium | -[Median of Two Sorted Arrays] | [median-of-two-sorted-arrays.py] | _O(log(m + n)_ | _O(log(m + n)_ | Hard | -[Pow(x, n)] | [powx-n.py] | _O(logn)_ | _O(logn)_ | Medium | -[Search a 2D Matrix] | [search-a-2d-matrix.py] | _O(log m + logn)_ | _O(1)_ | Medium | -[Search for a Range] | [search-for-a-range.py] | _O(logn)_ | _O(1)_ | Medium | -[Search in Rotated Sorted Array] | [search-in-rotated-sorted-array.py] | _O(logn)_ | _O(1)_ | Hard | -[Search in Rotated Sorted Array II] | [search-in-rotated-sorted-array-ii.py] | _O(logn)_ | _O(1)_ | Medium | -[Search Insert Position] | [search-insert-position.py] | _O(logn)_ | _O(1)_ | Medium | -[Sqrt(x)] | [sqrtx.py] | _O(logn)_ | _O(1)_ | Medium | - -[Find Minimum in Rotated Sorted Array]:https://oj.leetcode.com/problems/find-minimum-in-rotated-sorted-array/ -[find-minimum-in-rotated-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/find-minimum-in-rotated-sorted-array.py -[Find Minimum in Rotated Sorted Array II]:https://oj.leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/ -[find-minimum-in-rotated-sorted-array-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/find-minimum-in-rotated-sorted-array-ii.py -[Find Peak Element]:https://oj.leetcode.com/problems/find-peak-element/ -[find-peak-element.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/find-peak-element.py -[Median of Two Sorted Arrays]:https://oj.leetcode.com/problems/median-of-two-sorted-arrays/ -[median-of-two-sorted-arrays.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/median-of-two-sorted-arrays.py -[Pow(x, n)]:https://oj.leetcode.com/problems/powx-n/ -[powx-n.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/powx-n.py -[Search a 2D Matrix]:https://oj.leetcode.com/problems/search-a-2d-matrix/ -[search-a-2d-matrix.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-a-2d-matrix.py -[Search for a Range]:https://oj.leetcode.com/problems/search-for-a-range/ -[search-for-a-range.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-for-a-range.py -[Search in Rotated Sorted Array]:https://oj.leetcode.com/problems/search-in-rotated-sorted-array/ -[search-in-rotated-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-in-rotated-sorted-array.py -[Search in Rotated Sorted Array II]:https://oj.leetcode.com/problems/search-in-rotated-sorted-array-ii/ -[search-in-rotated-sorted-array-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-in-rotated-sorted-array-ii.py -[Search Insert Position]:https://oj.leetcode.com/problems/search-insert-position/ -[search-insert-position.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-insert-position.py -[Sqrt(x)]:https://oj.leetcode.com/problems/sqrtx/ -[sqrtx.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sqrtx.py - ---- - -##Breadth-First Search -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Binary Tree Level Order Traversal]| [binary-tree-level-order-traversal.py] | _O(n)_| _O(n)_| Easy | -[Binary Tree Level Order Traversal II]| [binary-tree-level-order-traversal-ii.py] | _O(n)_| _O(n)_| Easy | -[Binary Tree Zigzag Level Order Traversal]| [binary-tree-zigzag-level-order-traversal.py] | _O(n)_| _O(n)_| Medium | -[Clone Graph]| [clone-graph.py] | _O(n)_ | _O(n)_ | Medium | -[Populating Next Right Pointers in Each Node II]|[populating-next-right-pointers-in-each-node-ii.py]| _O(n)_ | _O(1)_ | Hard | -[Surrounded Regions]|[surrounded-regions.py]| _O(m * n)_ | _O(m + n)_ | Medium | -[Word Ladder] |[word-ladder.py] | _O((25n)^n)_ | _O((25n)^n)_ | Medium | - -[Binary Tree Level Order Traversal]:https://oj.leetcode.com/problems/binary-tree-level-order-traversal/ -[binary-tree-level-order-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-level-order-traversal.py -[Binary Tree Level Order Traversal II]:https://oj.leetcode.com/problems/binary-tree-level-order-traversal-ii/ -[binary-tree-level-order-traversal-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-level-order-traversal-ii.py -[Binary Tree Zigzag Level Order Traversal]:https://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/ -[binary-tree-zigzag-level-order-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-zigzag-level-order-traversal.py -[Clone Graph]:https://oj.leetcode.com/problems/clone-graph/ -[clone-graph.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/clone-graph.py -[Populating Next Right Pointers in Each Node II]:https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ -[populating-next-right-pointers-in-each-node-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/populating-next-right-pointers-in-each-node-ii.py -[Surrounded Regions]:https://oj.leetcode.com/problems/surrounded-regions/ -[surrounded-regions.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/surrounded-regions.py -[Word Ladder]:https://oj.leetcode.com/problems/word-ladder/ -[word-ladder.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-ladder.py - ---- - -##Depth-First Search -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Combination Sum]| [combination-sum.py] | _O(n^m)_ | _O(m)_ | Medium | -[Combination Sum II]| [combination-sum-ii.py]| _O(n! / m!(n-m)!)_| _O(m)_ | Medium | -[Combinations] | [combinations.py] | _O(n!)_ | _O(n)_ | Medium | -[Generate Parentheses]| [generate-parentheses.py]| _O(4^n / n^(3/2)_ | _O(n)_ | Medium | -[N-Queens] | [n-queens.py] | _O(n!)_ | _O(n)_ | Hard | -[N-Queens-II] | [n-queens-ii.py] | _O(n!)_ | _O(n)_ | Hard | -[Palindrome Partitioning] | [palindrome-partitioning.py] | _O(n^2)_ ~ _O(2^n)_ | _O(n^2)_ | Medium | -[Path Sum] | [path-sum.py] | _O(n)_ | _O(logn)_ | Easy | -[Path Sum II] | [path-sum-ii.py] | _O(n)_ | _O(logn)_ | Medium | -[Restore IP Addresses] | [restore-ip-addresses.py] | _O(n^m)_ ~ _O(3^4)_ | _O(n * m)_ ~ _O(3 * 4)_ | Medium | -[Sudoku Solver] | [sudoku-solver.py] | _O((9!)^9)_ | _O(1)_ | Hard | -[Word Search] | [word-search.py] | _O(m * n * 3^p)_ | _O(m * n * p)_ | Medium | - -[Combination Sum]:https://oj.leetcode.com/problems/combination-sum/ -[combination-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/combination-sum.py -[Combination Sum II]:https://oj.leetcode.com/problems/combination-sum-ii/ -[combination-sum-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/combination-sum-ii.py -[Combinations]:https://oj.leetcode.com/problems/combinations/ -[combinations.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/combinations.py -[Generate Parentheses]:https://oj.leetcode.com/problems/generate-parentheses/ -[generate-parentheses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/generate-parentheses.py -[N-Queens]:https://oj.leetcode.com/problems/n-queens/ -[n-queens.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/n-queens.py -[N-Queens-II]:https://oj.leetcode.com/problems/n-queens-ii/ -[n-queens-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/n-queens-ii.py -[Palindrome Partitioning]:https://oj.leetcode.com/problems/palindrome-partitioning/ -[palindrome-partitioning.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/palindrome-partitioning.py -[Path Sum]:https://oj.leetcode.com/problems/path-sum/ -[path-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/path-sum.py -[Path Sum II]:https://oj.leetcode.com/problems/path-sum-ii/ -[path-sum-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/path-sum-ii.py -[Restore IP Addresses]:https://oj.leetcode.com/problems/restore-ip-addresses/ -[restore-ip-addresses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/restore-ip-addresses.py -[Sudoku Solver]:https://oj.leetcode.com/problems/sudoku-solver/ -[sudoku-solver.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sudoku-solver.py -[Word Search]:https://oj.leetcode.com/problems/word-search/ -[word-search.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-search.py - ---- - -##Dynamic Programming -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Best Time to Buy and Sell Stock III]| [best-time-to-buy-and-sell-stock-iii.py] | _O(n)_ | _O(1)_ | Hard | -[Climbing Stairs]| [climbing-stairs.py] | _O(n)_ | _O(1)_ | Easy | -[Decode Ways] | [decode-ways.py]| _O(n)_ | _O(1)_ | Medium | -[Distinct Subsequences]|[distinct-subsequences.py]| _O(n^2)_ | _O(n)_ | Hard | -[Dungeon Game] | [dungeon-game.py]| _O(m * n)_ | _O(m + n)_ | Hard | -[Edit Distance]|[edit-distance.py]| _O(m * n)_ | _O(m + n)_ | Hard | -[Interleaving String]|[interleaving-string.py]| _O(m * n)_ | _O(m + n)_ | Hard | -[Maximal Rectangle]|[maximal-rectangle.py]| _O(n^2)_ | _O(n)_ | Hard | -[Maximum Product Subarray]|[maximum-product-subarray.py]| _O(n)_ | _O(1)_ | Medium | -[Maximum Subarray]|[maximum-subarray.py]| _O(n)_ | _O(1)_ | Medium | -[Minimum Path Sum]|[minimum-path-sum.py]| _O(m * n)_ | _O(m + n)_ | Medium | -[Palindrome Partitioning II] | [palindrome-partitioning-ii.py] | _O(n^2)_ | _O(n^2)_ | Hard | -[Regular Expression Matching] | [regular-expression-matching.py] | _O(m * n)_ | _O(n)_ | Hard | -[Scramble String] | [scramble-string.py] | _O(n^4)_ | _O(n^3)_ | Hard | -[Triangle] | [triangle.py] | _O(m * n)_ | _O(n)_ | Medium | -[Unique Binary Search Trees] | [unique-binary-search-trees.py] | _O(n^2)_ | _O(n)_ | Medium | -[Unique Paths] | [unique-paths.py]| _O(m * n)_ | _O(m + n)_ | Medium | -[Unique Paths II] | [unique-paths-ii.py] | _O(m * n)_ | _O(m + n)_ | Medium | -[Word Break] | [word-break.py] | _O(n^2)_ | _O(n)_ | Medium | -[Word Break II] | [word-break-ii.py] | _O(n^2)_ | _O(n)_ | Hard | - -[Best Time to Buy and Sell Stock III]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ -[best-time-to-buy-and-sell-stock-iii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock-iii.py -[Climbing Stairs]:https://oj.leetcode.com/problems/climbing-stairs/ -[climbing-stairs.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/climbing-stairs.py -[Decode Ways]:https://oj.leetcode.com/problems/decode-ways/ -[decode-ways.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/decode-ways.py -[Distinct Subsequences]:https://oj.leetcode.com/problems/distinct-subsequences/ -[distinct-subsequences.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/distinct-subsequences.py -[Dungeon Game]:https://oj.leetcode.com/problems/dungeon-game/ -[dungeon-game.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/dungeon-game.py -[Edit Distance]:https://oj.leetcode.com/problems/edit-distance/ -[edit-distance.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/edit-distance.py -[Interleaving String]:https://oj.leetcode.com/problems/interleaving-string/ -[interleaving-string.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/interleaving-string.py -[Maximal Rectangle]:https://oj.leetcode.com/problems/maximal-rectangle/ -[maximal-rectangle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximal-rectangle.py -[Maximum Product Subarray]:https://oj.leetcode.com/problems/maximum-product-subarray/ -[maximum-product-subarray.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-product-subarray.py -[Maximum Subarray]:https://oj.leetcode.com/problems/maximum-subarray/ -[maximum-subarray.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-subarray.py -[Minimum Path Sum]:https://oj.leetcode.com/problems/minimum-path-sum/ -[minimum-path-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/minimum-path-sum.py -[Palindrome Partitioning II]:https://oj.leetcode.com/problems/palindrome-partitioning-ii/ -[palindrome-partitioning-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/palindrome-partitioning-ii.py -[Regular Expression Matching]:https://oj.leetcode.com/problems/regular-expression-matching/ -[regular-expression-matching.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/regular-expression-matching.py -[Scramble String]:https://oj.leetcode.com/problems/scramble-string/ -[scramble-string.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/scramble-string.py -[Triangle]:https://oj.leetcode.com/problems/triangle/ -[triangle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/triangle.py -[Unique Binary Search Trees]:https://oj.leetcode.com/problems/unique-binary-search-trees/ -[unique-binary-search-trees.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-binary-search-trees.py -[Unique Paths]:https://oj.leetcode.com/problems/unique-paths/ -[unique-paths.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-paths.py -[Unique Paths II]:https://oj.leetcode.com/problems/unique-paths-ii/ -[unique-paths-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-paths-ii.py -[Word Break]:https://oj.leetcode.com/problems/word-break/ -[word-break.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-break.py -[Word Break II]:https://oj.leetcode.com/problems/word-break-ii/ -[word-break-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-break-ii.py - ---- - -##Backtracking -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Word Ladder II] |[word-ladder-ii.py] | _O((25n)^n)_ | _O((25n)^n)_ | Hard | - -[Word Ladder II]:https://oj.leetcode.com/problems/word-ladder-ii/ -[word-ladder-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-ladder-ii.py - ---- - -##Greedy -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Best Time to Buy and Sell Stock II]| [best-time-to-buy-and-sell-stock-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Candy]| [candy.py] | _O(n)_ | _O(n)_ | Hard | -[Container With Most Water]| [container-with-most-water.py] | _O(n)_ | _O(1)_ | Medium | -[Gas Station]| [gas-station.py] | _O(n)_ | _O(1)_ | Medium | -[Jump Game] | [jump-game.py] | _O(n)_ | _O(1)_ | Medium | -[Jump Game II] | [jump-game-ii.py] | _O(n^2)_ | _O(1)_ | Hard | -[Largest Rectangle in Histogram] | [largest-rectangle-in-histogram.py] | _O(n)_ | _O(n)_ | Hard | Tricky -[Trapping Rain Water] | [trapping-rain-water.py] | _O(n)_ | _O(1)_ | Hard | Tricky -[Wildcard Matching] | [wildcard-matching.py] | _O(m + n)_ | _O(1)_ | Hard | Tricky - -[Best Time to Buy and Sell Stock II]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ -[best-time-to-buy-and-sell-stock-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock-ii.py -[Candy]:https://oj.leetcode.com/problems/candy/ -[candy.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/candy.py -[Container With Most Water]:https://oj.leetcode.com/problems/container-with-most-water/ -[container-with-most-water.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/container-with-most-water.py -[Gas Station]:https://oj.leetcode.com/problems/gas-station/ -[gas-station.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/gas-station.py -[Jump Game]:https://oj.leetcode.com/problems/jump-game/ -[jump-game.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/jump-game.py -[Jump Game II]:https://oj.leetcode.com/problems/jump-game-ii/ -[jump-game-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/jump-game-ii.py -[Largest Rectangle in Histogram]:https://oj.leetcode.com/problems/largest-rectangle-in-histogram/ -[largest-rectangle-in-histogram.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/largest-rectangle-in-histogram.py -[Trapping Rain Water]:https://oj.leetcode.com/problems/trapping-rain-water/ -[trapping-rain-water.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/trapping-rain-water.py -[Wildcard Matching]:https://oj.leetcode.com/problems/wildcard-matching/ -[wildcard-matching.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/wildcard-matching.py - ---- - -##SQL -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Combine Two Tables] | [combine-two-tables.sql] | _O(m + n)_ | _O(m + n)_ | Easy | -[Consecutive Numbers] | [consecutive-numbers.sql] | _O(n)_ | _O(n)_ | Medium | -[Nth Highest Salary] | [nth-highest-salary.sql] | _O(n^2)_ | _O(n)_ | Medium | -[Rank Scores] | [rank-scores.sql] | _O(n^2)_ | _O(n)_ | Medium | -[Second Highest Salary] | [second-highest-salary.sql] | _O(n)_ | _O(1)_ | Easy | - -[Combine Two Tables]:https://oj.leetcode.com/problems/combine-two-tables/ -[combine-two-tables.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/combine-two-tables.sql -[Consecutive Numbers]:https://oj.leetcode.com/problems/consecutive-numbers/ -[consecutive-numbers.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/consecutive-numbers.sql -[Nth Highest Salary]:https://oj.leetcode.com/problems/nth-highest-salary/ -[nth-highest-salary.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/nth-highest-salary.sql -[Rank Scores]:https://oj.leetcode.com/problems/rank-scores/ -[rank-scores.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/rank-scores.sql -[Second Highest Salary]:https://oj.leetcode.com/problems/second-highest-salary/ -[second-highest-salary.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/second-highest-salary.sql +## Shell + +* [Shell Script](https://github.com/kamyu104/LeetCode#shell-script) + +## Bit Manipulation +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +136 | [Single Number](https://leetcode.com/problems/single-number/) | [C++](./C++/single-number.cpp) [Python](./Python/single-number.py) | _O(n)_ | _O(1)_ | Easy ||| +137 | [Single Number II](https://leetcode.com/problems/single-number-ii/) | [C++](./C++/single-number-ii.cpp) [Python](./Python/single-number-ii.py) | _O(n)_ | _O(1)_ | Medium ||| +190 | [Reverse Bits](https://leetcode.com/problems/reverse-bits/) | [C++](./C++/reverse-bits.cpp) [Python](./Python/reverse-bits.py) | _O(1)_ | _O(1)_ | Easy ||| +191 |[Number of 1 Bits](https://leetcode.com/problems/number-of-1-bits/) | [C++](./C++/number-of-1-bits.cpp) [Python](./Python/number-of-1-bits.py) | _O(1)_ | _O(1)_ | Easy ||| +201 | [Bitwise AND of Numbers Range](https://leetcode.com/problems/bitwise-and-of-numbers-range/) | [C++](./C++/bitwise-and-of-numbers-range.cpp) [Python](./Python/bitwise-and-of-numbers-range.py) | _O(1)_ | _O(1)_ | Medium || +231 | [Power of Two](https://leetcode.com/problems/power-of-two/) | [C++](./C++/power-of-two.cpp) [Python](./Python/power-of-two.py) | _O(1)_ | _O(1)_ | Easy | LintCode | +260 | [Single Number III](https://leetcode.com/problems/single-number-iii/) | [C++](./C++/single-number-iii.cpp) [Python](./Python/single-number-iii.py) | _O(n)_ | _O(1)_ | Medium || +268| [Missing Number](https://leetcode.com/problems/missing-number/) | [C++](./C++/missing-number.cpp) [Python](./Python/missing-number.py) | _O(n)_ | _O(1)_ | Medium | LintCode || +318| [Maximum Product of Word Lengths](https://leetcode.com/problems/maximum-product-of-word-lengths/) | [C++](./C++/maximum-product-of-word-lengths.cpp) [Python](./Python/maximum-product-of-word-lengths.py) | _O(n)_ ~ _O(n^2)_ | _O(n)_ | Medium || Bit Manipulation, Counting Sort, Pruning| +342 | [Power of Four](https://leetcode.com/problems/power-of-four/) | [C++](./C++/power-of-four.cpp) [Python](./Python/power-of-four.py) | _O(1)_ | _O(1)_ | Easy | | +371 | [Sum of Two Integers](https://leetcode.com/problems/sum-of-two-integers/) | [C++](./C++/sum-of-two-integers.cpp) [Python](./Python/sum-of-two-integers.py) | _O(1)_ | _O(1)_ | Easy | LintCode | +389 | [Find the Difference](https://leetcode.com/problems/find-the-difference/) | [C++](./C++/find-the-difference.cpp) [Python](./Python/find-the-difference.py) | _O(n)_ | _O(1)_ | Easy | | +393 | [UTF-8 Validation](https://leetcode.com/problems/utf-8-validation/) | [C++](./C++/utf-8-validation.cpp) [Python](./Python/utf-8-validation.py) | _O(n)_ | _O(1)_ | Medium | | +401 | [Binary Watch](https://leetcode.com/problems/binary-watch/) | [C++](./C++/binary-watch.cpp) [Python](./Python/binary-watch.py) | _O(1)_ | _O(1)_ | Easy | | +411 | [Minimum Unique Word Abbreviation](https://leetcode.com/problems/minimum-unique-word-abbreviation/) | [C++](./C++/minimum-unique-word-abbreviation.cpp) [Python](./Python/minimum-unique-word-abbreviation.py) | _O(2^n)_ | _O(n)_ | Hard | 📖 | +421 | [Maximum XOR of Two Numbers in an Array](https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/) | [C++](./C++/maximum-xor-of-two-numbers-in-an-array.cpp) [Python](./Python/maximum-xor-of-two-numbers-in-an-array.py) | _O(n)_ | _O(1)_ | Medium || +461 | [Hamming Distance](https://leetcode.com/problems/hamming-distance/) | [C++](./C++/hamming-distance.cpp) [Python](./Python/hamming-distance.py) | _O(1)_ | _O(1)_ | Easy || +462 | [Minimum Moves to Equal Array Elements II](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/) | [C++](./C++/minimum-moves-to-equal-array-elements-ii.cpp) [Python](./Python/minimum-moves-to-equal-array-elements-ii.py) | _O(n)_ on average | _O(1)_ | Medium || +477 | [Total Hamming Distance](https://leetcode.com/problems/total-hamming-distance/) | [C++](./C++/total-hamming-distance.cpp) [Python](./Python/total-hamming-distance.py) | _O(n)_ | _O(1)_ | Medium || +645 | [Set Mismatch](https://leetcode.com/problems/set-mismatch/) | [C++](./C++/set-mismatch.cpp) [Python](./Python/set-mismatch.py) | _O(n)_ | _O(1)_ | Easy || +693 | [Binary Number with Alternating Bits](https://leetcode.com/problems/binary-number-with-alternating-bits/) | [C++](./C++/binary-number-with-alternating-bits.cpp) [Python](./Python/binary-number-with-alternating-bits.py) | _O(1)_ | _O(1)_ | Easy || + +## Array +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +15 | [3 Sum](https://leetcode.com/problems/3sum/) | [C++](./C++/3sum.cpp) [Python](./Python/3sum.py) | _O(n^2)_ | _O(1)_ | Medium || Two Pointers +16 | [3 Sum Closest](https://leetcode.com/problems/3sum-closest/) | [C++](./C++/3sum-closest.cpp) [Python](./Python/3sum-closest.py) | _O(n^2)_ | _O(1)_ | Medium || Two Pointers +18| [4 Sum](https://leetcode.com/problems/4sum/) | [C++](./C++/4sum.cpp) [Python](./Python/4sum.py) | _O(n^3)_ | _O(1)_ | Medium || Two Pointers +26 | [Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)| [C++](./C++/remove-duplicates-from-sorted-array.cpp) [Python](./Python/remove-duplicates-from-sorted-array.py) | _O(n)_ | _O(1)_ | Easy || Two Pointers +27 | [Remove Element](https://leetcode.com/problems/remove-element/) | [C++](./C++/remove-element.cpp) [Python](./Python/remove-element.py) | _O(n)_ | _O(1)_ | Easy || +31 | [Next Permutation](https://leetcode.com/problems/next-permutation/)| [C++](./C++/next-permutation.cpp) [Python](./Python/next-permutation.py) | _O(n)_ | _O(1)_ | Medium || Tricky +41 | [First Missing Positive](https://leetcode.com/problems/first-missing-positive/)| [C++](./C++/first-missing-positive.cpp) [Python](./Python/first-missing-positive.py) | _O(n)_ | _O(1)_ | Hard || Tricky +48 | [Rotate Image](https://leetcode.com/problems/rotate-image/) | [C++](./C++/rotate-image.cpp) [Python](./Python/rotate-image.py) | _O(n^2)_ | _O(1)_ | Medium || +54 | [Spiral Matrix](https://leetcode.com/problems/spiral-matrix/) | [C++](./C++/spiral-matrix.cpp) [Python](./Python/spiral-matrix.py) | _O(m * n)_ | _O(1)_ | Medium || +59 | [Spiral Matrix II](https://leetcode.com/problems/spiral-matrix-ii/) | [C++](./C++/spiral-matrix-ii.cpp) [Python](./Python/spiral-matrix-ii.py) | _O(n^2)_ | _O(1)_ | Medium || +66 | [Plus One](https://leetcode.com/problems/plus-one/) | [C++](./C++/plus-one.cpp) [Python](./Python/plus-one.py) | _O(n)_ | _O(1)_ | Easy || +73 | [Set Matrix Zeroes](https://leetcode.com/problems/set-matrix-zeroes/) | [C++](./C++/set-matrix-zeroes.cpp) [Python](./Python/set-matrix-zeroes.py) | _O(m * n)_ | _O(1)_ | Medium || +80 | [Remove Duplicates from Sorted Array II](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/)| [C++](./C++/remove-duplicates-from-sorted-array-ii.cpp) [Python](./Python/remove-duplicates-from-sorted-array-ii.py) | _O(n)_ | _O(1)_ | Medium || Two Pointers +118 | [Pascal's Triangle](https://leetcode.com/problems/pascals-triangle/)| [C++](./C++/pascals-triangle.cpp) [Python](./Python/pascals-triangle.py) | _O(n^2)_ | _O(1)_ | Easy || +119 | [Pascal's Triangle II](https://leetcode.com/problems/pascals-triangle-ii/)| [C++](./C++/pascals-triangle-ii.cpp) [Python](./Python/pascals-triangle-ii.py) | _O(n^2)_ | _O(1)_ | Easy || +121 | [Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)| [C++](./C++/best-time-to-buy-and-sell-stock.cpp) [Python](./Python/best-time-to-buy-and-sell-stock.py) | _O(n)_ | _O(1)_ | Easy || +128 | [Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/)| [C++](./C++/longest-consecutive-sequence.cpp) [Python](./Python/longest-consecutive-sequence.py) | _O(n)_ | _O(n)_ | Hard || Tricky +157 | [Read N Characters Given Read4](https://leetcode.com/problems/read-n-characters-given-read4/) | [C++](./C++/read-n-characters-given-read4.cpp) [Python](./Python/read-n-characters-given-read4.py) | _O(n)_ | _O(1)_ | Easy |📖| +158 | [Read N Characters Given Read4 II - Call multiple times](https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/) | [C++](./C++/read-n-characters-given-read4-ii-call-multiple-times.cpp) [Python](./Python/read-n-characters-given-read4-ii-call-multiple-times.py) | _O(n)_ | _O(1)_ | Hard |📖| +163 | [Missing Ranges](https://leetcode.com/problems/missing-ranges/)| [C++](./C++/missing-ranges.cpp) [Python](./Python/missing-ranges.py) | _O(n)_ | _O(1)_ | Medium | 📖 | +169 | [Majority Element](https://leetcode.com/problems/majority-element/) | [C++](./C++/majority-element.cpp) [Python](./Python/majority-element.py) | _O(n)_ | _O(1)_ | Easy | +189 | [Rotate Array](https://leetcode.com/problems/rotate-array/) | [C++](./C++/rotate-array.cpp) [Python](./Python/rotate-array.py) | _O(n)_ | _O(1)_ | Easy || +209 | [Minimum Size Subarray Sum](https://leetcode.com/problems/minimum-size-subarray-sum/) | [C++](./C++/minimum-size-subarray-sum.cpp) [Python](./Python/minimum-size-subarray-sum.py) | _O(n)_ | _O(1)_ | Medium | | Binary Search +215 | [Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) | [C++](./C++/kth-largest-element-in-an-array.cpp) [Python](./Python/kth-largest-element-in-an-array.py)| _O(n)_ ~ _O(n^2)_ | _O(1)_ | Medium | EPI| +228 | [Summary Ranges](https://leetcode.com/problems/summary-ranges/) | [C++](./C++/summary-ranges.cpp) [Python](./Python/summary-ranges.py)| _O(n)_ | _O(1)_ | Medium | | +229 | [Majority Element II](https://leetcode.com/problems/majority-element-ii/) | [C++](./C++/majority-element-ii.cpp) [Python](./Python/majority-element-ii.py) | _O(n)_ | _O(1)_ | Medium | | +238 | [Product of Array Except Self](https://leetcode.com/problems/product-of-array-except-self/) | [C++](./C++/product-of-array-except-self.cpp) [Python](./Python/product-of-array-except-self.py) | _O(n)_ | _O(1)_ | Medium | LintCode | +240 | [Search a 2D Matrix II](https://leetcode.com/problems/search-a-2d-matrix-ii/) | [C++](./C++/search-a-2d-matrix-ii.cpp) [Python](./Python/search-a-2d-matrix-ii.py) | _O(m + n)_ | _O(1)_ | Medium | EPI, LintCode | +243| [Shortest Word Distance](https://leetcode.com/problems/shortest-word-distance/) | [C++](./C++/shortest-word-distance.cpp) [Python](./Python/shortest-word-distance.py) | _O(n)_ | _O(1)_ | Easy |📖|| +245| [Shortest Word Distance III](https://leetcode.com/problems/shortest-word-distance-iii/) | [C++](./C++/shortest-word-distance-iii.cpp) [Python](./Python/shortest-word-distance-iii.py) | _O(n)_ | _O(1)_ | Medium |📖|| +251| [Flatten 2D Vector](https://leetcode.com/problems/flatten-2d-vector/) | [C++](./C++/flatten-2d-vector.cpp) [Python](./Python/flatten-2d-vector.py) | _O(1)_ | _O(1)_ | Medium |📖|| +277| [Find the Celebrity](https://leetcode.com/problems/find-the-celebrity/) | [C++](./C++/find-the-celebrity.cpp) [Python](./Python/find-the-celebrity.py) | _O(n)_ | _O(1)_ | Medium |📖, EPI || +289| [Game of Life](https://leetcode.com/problems/game-of-life/) | [C++](./C++/game-of-life.cpp) [Python](./Python/game-of-life.py) | _O(m * n)_ | _O(1)_ | Medium ||| +293| [Flip Game](https://leetcode.com/problems/flip-game/) | [C++](./C++/flip-game.cpp) [Python](./Python/flip-game.py) | _O(n * (c+1))_ | _O(1)_ | Easy |📖|| +296| [Best Meeting Point](https://leetcode.com/problems/best-meeting-point/) | [C++](./C++/best-meeting-point.cpp) [Python](./Python/best-meeting-point.py) | _O(m * n)_ | _O(m + n)_ | Hard |📖|| +311| [Sparse Matrix Multiplication](https://leetcode.com/problems/sparse-matrix-multiplication/) | [C++](./C++/sparse-matrix-multiplication.cpp) [Python](./Python/sparse-matrix-multiplication.py) | _O(m * n * l)_ | _O(m * l)_ | Medium |📖|| +334| [Increasing Triplet Subsequence](https://leetcode.com/problems/increasing-triplet-subsequence/) | [C++](./C++/increasing-triplet-subsequence.cpp) [Python](./Python/increasing-triplet-subsequence.py) | _O(n)_ | _O(1)_ | Medium ||| +370| [Range Addition](https://leetcode.com/problems/range-addition/) | [C++](./C++/range-addition.cpp) [Python](./Python/range-addition.py) | _O(k + n)_ | _O(1)_ | Medium |📖|| +384| [Shuffle an Array](https://leetcode.com/problems/shuffle-an-array/) | [C++](./C++/shuffle-an-array.cpp) [Python](./Python/shuffle-an-array.py) | _O(n)_ | _O(n)_ | Medium | EPI || +396| [Rotate Function](https://leetcode.com/problems/rotate-function/) | [C++](./C++/rotate-function.cpp) [Python](./Python/rotate-function.py) | _O(n)_ | _O(1)_ | Easy ||| +412| [Fizz Buzz](https://leetcode.com/problems/fizz-buzz/) | [C++](./C++/fizz-buzz.cpp) [Python](./Python/fizz-buzz.py) | _O(n)_ | _O(1)_ | Easy ||| +414| [Third Maximum Number](https://leetcode.com/problems/third-maximum-number/) | [C++](./C++/third-maximum-number.cpp) [Python](./Python/third-maximum-number.py) | _O(n)_ | _O(1)_ | Easy ||| +419| [Battleships in a Board](https://leetcode.com/problems/battleships-in-a-board/) | [C++](./C++/battleships-in-a-board.cpp) [Python](./Python/battleships-in-a-board.py) | _O(m * n)_ | _O(1)_ | Medium ||| +422| [Valid Word Square](https://leetcode.com/problems/valid-word-square/) | [C++](./C++/valid-word-square.cpp) [Python](./Python/valid-word-square.py) | _O(m * n)_ | _O(1)_ | Easy |📖|| +442| [Find All Duplicates in an Array](https://leetcode.com/problems/find-all-duplicates-in-an-array/) | [C++](./C++/find-all-duplicates-in-an-array.cpp) [Python](./Python/find-all-duplicates-in-an-array.py) | _O(n)_ | _O(1)_ | Medium ||| +448| [Find All Numbers Disappeared in an Array](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/) | [C++](./C++/find-all-numbers-disappeared-in-an-array.cpp) [Python](./Python/find-all-numbers-disappeared-in-an-array.py) | _O(n)_ | _O(1)_ | Easy ||| +565 | [Array Nesting](https://leetcode.com/problems/array-nesting/) | [C++](./C++/array-nesting.cpp) [Python](./Python/array-nesting.py) | _O(n)_ | _O(1)_ | Medium ||| +566 | [Reshape the Matrix](https://leetcode.com/problems/reshape-the-matrix/) | [C++](./C++/reshape-the-matrix.cpp) [Python](./Python/reshape-the-matrix.py) | _O(m * n)_ | _O(m * n)_ | Easy ||| +581 | [Shortest Unsorted Continuous Subarray](https://leetcode.com/problems/shortest-unsorted-continuous-subarray/) | [C++](./C++/shortest-unsorted-continuous-subarray.cpp) [Python](./Python/shortest-unsorted-continuous-subarray.py) | _O(n)_ | _O(1)_ | Easy ||| +605 | [Can Place Flowers](https://leetcode.com/problems/can-place-flowers/) | [C++](./C++/can-place-flowers.cpp) [Python](./Python/can-place-flowers.py) | _O(n)_ | _O(1)_ | Easy ||| +624 | [Maximum Distance in Arrays](https://leetcode.com/problems/maximum-distance-in-arrays/) | [C++](./C++/maximum-distance-in-arrays.cpp) [Python](./Python/maximum-distance-in-arrays.py) | _O(n)_ | _O(1)_ | Easy | 📖 | +643 | [Maximum Average Subarray I](https://leetcode.com/problems/maximum-average-subarray-i/) | [C++](./C++/maximum-average-subarray-i.cpp) [Python](./Python/maximum-average-subarray-i.py) | _O(n)_ | _O(1)_ | Easy || Math +644 | [Maximum Average Subarray II](https://leetcode.com/problems/maximum-average-subarray-ii/) | [C++](./C++/maximum-average-subarray-ii.cpp) [Python](./Python/maximum-average-subarray-ii.py) | _O(n)_ | _O(n)_ | Hard | 📖 | Math +661| [Image Smoother](https://leetcode.com/problems/image-smoother/) | [C++](./C++/image-smoother.cpp) [Python](./Python/image-smoother.py) | _O(m * n)_ | _O(1)_ | Easy ||| +665| [Non-decreasing Array](https://leetcode.com/problems/non-decreasing-array/) | [C++](./C++/non-decreasing-array.cpp) [Python](./Python/non-decreasing-array.py) | _O(n)_ | _O(1)_ | Easy ||| +667| [Beautiful Arrangement II](https://leetcode.com/problems/beautiful-arrangement-ii/) | [C++](./C++/beautiful-arrangement-ii.cpp) [Python](./Python/beautiful-arrangement-ii.py) | _O(n)_ | _O(1)_ | Medium ||| +670| [Maximum Swap](https://leetcode.com/problems/maximum-swap/) | [C++](./C++/maximum-swap.cpp) [Python](./Python/maximum-swap.py) | _O(logn)_ | _O(logn)_ | Medium ||| +674 | [Longest Continuous Increasing Subsequence](https://leetcode.com/problems/longest-continuous-increasing-subsequence/) | [C++](./C++/longest-continuous-increasing-subsequence.cpp) [Python](./Python/longest-continuous-increasing-subsequence.py) | _O(n)_ | _O(1)_ | Easy || +683 | [K Empty Slots](https://leetcode.com/problems/k-empty-slots/) | [C++](./C++/k-empty-slots.cpp) [Python](./Python/k-empty-slots.py) | _O(n)_ | _O(n)_ | Hard || +697| [Degree of an Array](https://leetcode.com/problems/degree-of-an-array/) | [C++](./C++/degree-of-an-array.cpp) [Python](./Python/degree-of-an-array.py) | _O(n)_ | _O(n)_ | Easy || +713 | [Subarray Product Less Than K](https://leetcode.com/problems/subarray-product-less-than-k/) | [C++](./C++/subarray-product-less-than-k.cpp) [Python](./Python/subarray-product-less-than-k.py) | _O(n)_ | _O(1)_ | Medium || +717 | [1-bit and 2-bit Characters](https://leetcode.com/problems/1-bit-and-2-bit-characters/) | [C++](./C++/1-bit-and-2-bit-characters.cpp) [Python](./Python/1-bit-and-2-bit-characters.py) | _O(n)_ | _O(1)_ | Easy || Greedy +723 | [Candy Crush](https://leetcode.com/problems/candy-crush/) | [C++](./C++/candy-crush.cpp) [Python](./Python/candy-crush.py) | _O((R * C)^2)_ | _O(1)_ | Medium || +724 | [Find Pivot Index](https://leetcode.com/problems/find-pivot-index/) | [C++](./C++/find-pivot-index.cpp) [Python](./Python/find-pivot-index.py) | _O(n)_ | _O(1)_ | Easy || +729 | [My Calendar I](https://leetcode.com/problems/my-calendar-i/) | [C++](./C++/my-calendar-i.cpp) [Python](./Python/my-calendar-i.py) | _O(nlogn)_ | _O(n)_ | Medium || +731 | [My Calendar II](https://leetcode.com/problems/my-calendar-ii/) | [C++](./C++/my-calendar-ii.cpp) [Python](./Python/my-calendar-ii.py) | _O(n^2)_ | _O(n)_ | Medium || +732 | [My Calendar III](https://leetcode.com/problems/my-calendar-iii/) | [C++](./C++/my-calendar-iii.cpp) [Python](./Python/my-calendar-iii.py) | _O(n^2)_ | _O(n)_ | Hard || + + +## String +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +5| [Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/) | [C++](./C++/longest-palindromic-substring.cpp) [Python](./Python/longest-palindromic-substring.py) | _O(n)_ | _O(n)_ | Medium || `Manacher's Algorithm` +6| [ZigZag Conversion](https://leetcode.com/problems/zigzag-conversion/) | [C++](./C++/zigzag-conversion.cpp) [Python](./Python/zigzag-conversion.py) | _O(n)_ | _O(1)_ | Easy || +8| [String to Integer (atoi)](https://leetcode.com/problems/string-to-integer-atoi/) | [C++](./C++/string-to-integer-atoi.cpp) [Python](./Python/string-to-integer-atoi.py) | _O(n)_ | _O(1)_ | Easy || +14| [Longest Common Prefix](https://leetcode.com/problems/longest-common-prefix/) | [C++](./C++/longest-common-prefix.cpp) [Python](./Python/longest-common-prefix.py) | _O(n * k)_ | _O(1)_ | Easy || +28| [Implement strStr()](https://leetcode.com/problems/implement-strstr/) | [C++](./C++/implement-strstr.cpp) [Python](./Python/implement-strstr.py) | _O(n + k)_ | _O(k)_ | Easy || `KMP Algorithm` +38| [Count and Say](https://leetcode.com/problems/count-and-say/) | [C++](./C++/count-and-say.cpp) [Python](./Python/count-and-say.py)| _O(n * 2^n)_ | _O(2^n)_ | Easy || +43| [Multiply Strings](https://leetcode.com/problems/multiply-strings/) | [C++](./C++/multiply-strings.cpp) [Python](./Python/multiply-strings.py) | _O(m * n)_ | _O(m + n)_ | Medium || +58| [Length of Last Word](https://leetcode.com/problems/length-of-last-word/) | [C++](./C++/length-of-last-word.cpp) [Python](./Python/length-of-last-word.py) | _O(n)_ | _O(1)_ | Easy || +67| [Add Binary](https://leetcode.com/problems/add-binary/) | [C++](./C++/add-binary.cpp) [Python](./Python/add-binary.py) | _O(n)_ | _O(1)_ | Easy || +68| [Text Justification](https://leetcode.com/problems/text-justification/) | [C++](./C++/text-justification.cpp) [Python](./Python/text-justification.py) | _O(n)_ | _O(1)_ | Hard || +125| [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) | [C++](./C++/valid-palindrome.cpp) [Python](./Python/valid-palindrome.py) | _O(n)_ | _O(1)_ | Easy || +151| [Reverse Words in a String](https://leetcode.com/problems/reverse-words-in-a-string/) | [C++](./C++/reverse-words-in-a-string.cpp) [Python](./Python/reverse-words-in-a-string.py) | _O(n)_ | _O(1)_ | Medium || +161| [One Edit Distance](https://leetcode.com/problems/one-edit-distance/) | [C++](./C++/one-edit-distance.cpp) [Python](./Python/one-edit-distance.py) | _O(m + n)_ | _O(1)_ | Medium |📖 | +165| [Compare Version Numbers](https://leetcode.com/problems/compare-version-numbers/) | [C++](./C++/compare-version-numbers.cpp) [Python](./Python/compare-version-numbers.py) | _O(n)_ | _O(1)_ | Easy || +186| [Reverse Words in a String II](https://leetcode.com/problems/reverse-words-in-a-string-ii/) |[C++](./C++/reverse-words-in-a-string-ii.cpp) [Python](./Python/reverse-words-in-a-string-ii.py) | _O(n)_ | _O(1)_ | Medium | 📖 | +214| [Shortest Palindrome](https://leetcode.com/problems/shortest-palindrome/) | [C++](./C++/shortest-palindrome.cpp) [Python](./Python/shortest-palindrome.py) | _O(n)_ | _O(n)_ | Hard || `KMP Algorithm` `Manacher's Algorithm` +242| [Valid Anagram](https://leetcode.com/problems/valid-anagram/)| [C++](./C++/valid-anagram.cpp) [Python](./Python/valid-anagram.py) | _O(n)_ | _O(1)_ | Easy | LintCode | +271| [Encode and Decode Strings](https://leetcode.com/problems/encode-and-decode-strings/) | [C++](./C++/encode-and-decode-strings.cpp) [Python](./Python/encode-and-decode-strings.py) | _O(n)_ | _O(1)_ | Medium | 📖 | +273| [Integer to English Words](https://leetcode.com/problems/integer-to-english-words/) | [C++](./C++/integer-to-english-words.cpp) [Python](./Python/integer-to-english-words.py) | _O(logn)_ | _O(1)_ | Hard | | +306| [Addictive Number](https://leetcode.com/problems/additive-number/) | [C++](./C++/additive-number.cpp) [Python](./Python/additive-number.py) | _O(n^3)_ | _O(n)_ | Medium | | +383| [Ransom Note](https://leetcode.com/problems/ransom-note/) | [C++](./C++/ransom-note.cpp) [Python](./Python/ransom-note.py) | _O(n)_ | _O(1)_ | Easy | EPI | +405| [Convert a Number to Hexadecimal](https://leetcode.com/problems/convert-a-number-to-hexadecimal/) | [C++](./C++/convert-a-number-to-hexadecimal.cpp) [Python](./Python/convert-a-number-to-hexadecimal.py) | _O(n)_ | _O(1)_ | Easy | | +408| [Valid Word Abbreviation](https://leetcode.com/problems/valid-word-abbreviation/) | [C++](./C++/valid-word-abbreviation.cpp) [Python](./Python/valid-word-abbreviation.py) | _O(n)_ | _O(1)_ | Easy | 📖 | +415| [Add Strings](https://leetcode.com/problems/add-strings/) | [C++](./C++/add-strings.cpp) [Python](./Python/add-strings.py) | _O(n)_ | _O(1)_ | Easy | | +420| [Strong Password Checker](https://leetcode.com/problems/strong-password-checker/) | [C++](./C++/strong-password-checker.cpp) [Python](./Python/strong-password-checker.py) | _O(n)_ | _O(1)_ | Hard | | +434| [Number of Segments in a String](https://leetcode.com/problems/number-of-segments-in-a-string/) | [C++](./C++/number-of-segments-in-a-string.cpp) [Python](./Python/number-of-segments-in-a-string.py) | _O(n)_ | _O(1)_ | Easy | | +443| [String Compression](https://leetcode.com/problems/string-compression/) | [C++](./C++/string-compression.cpp) [Python](./Python/string-compression.py) | _O(n)_ | _O(1)_ | Easy | | +459| [Repeated Substring Pattern](https://leetcode.com/problems/repeated-substring-pattern/) | [C++](./C++/repeated-substring-pattern.cpp) [Python](./Python/repeated-substring-pattern.py) | _O(n)_ | _O(n)_ | Easy || `KMP Algorithm` | +468| [Validate IP Address](https://leetcode.com/problems/validate-ip-address/) | [C++](./C++/validate-ip-address.cpp) [Python](./Python/validate-ip-address.py) | _O(1)_ | _O(1)_ | Medium | | +551 | [Student Attendance Record I](https://leetcode.com/problems/student-attendance-record-i/) | [C++](./C++/student-attendance-record-i.cpp) [Python](./Python/student-attendance-record-i.py) | _O(n)_ | _O(1)_ | Easy ||| +556| [Next Greater Element III](https://leetcode.com/problems/next-greater-element-iii/) |[C++](./C++/next-greater-element-iii.cpp) [Python](./Python/next-greater-element-iii.py) | _O(1)_ | _O(1)_ | Medium | | +557| [Reverse Words in a String III](https://leetcode.com/problems/reverse-words-in-a-string-iii/) |[C++](./C++/reverse-words-in-a-string-iii.cpp) [Python](./Python/reverse-words-in-a-string-iii.py) | _O(n)_ | _O(1)_ | Easy | | +564| [Find the Closest Palindrome](https://leetcode.com/problems/find-the-closest-palindrome/) |[C++](./C++/find-the-closest-palindrome.cpp) [Python](./Python/find-the-closest-palindrome.py) | _O(l)_ | _O(l)_ | Hard | | +591| [Tag Validator](https://leetcode.com/problems/tag-validator/) |[C++](./C++/tag-validator.cpp) [Python](./Python/tag-validator.py) | _O(n)_ | _O(n)_ | Hard | | +616| [Add Bold Tag in String](https://leetcode.com/problems/add-bold-tag-in-string/) | [C++](./C++/add-bold-tag-in-string.cpp) [Python](./Python/add-bold-tag-in-string.py) | _O(s * d * l)_ | _O(s)_ | Medium | 📖 | +647| [Palindromic Substrings](https://leetcode.com/problems/palindromic-substrings/) | [C++](./C++/palindromic-substrings.cpp) [Python](./Python/palindromic-substrings.py) | _O(n)_ | _O(n)_ | Medium || `Manacher's Algorithm` +648| [Replace Words](https://leetcode.com/problems/replace-words/) | [C++](./C++/replace-words.cpp) [Python](./Python/replace-words.py) | _O(n)_ | _O(t)_ | Medium || Trie | +657| [Judge Route Circle](https://leetcode.com/problems/judge-route-circle/) |[C++](./C++/judge-route-circle.cpp) [Python](./Python/judge-route-circle.py) | _O(n)_ | _O(1)_ | Easy | | +678| [Valid Parenthesis String](https://leetcode.com/problems/valid-parenthesis-string/) |[C++](./C++/valid-parenthesis-string.cpp) [Python](./Python/valid-parenthesis-string.py) | _O(n)_ | _O(1)_ | Medium | | +680| [Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) | [C++](./C++/valid-palindrome-ii.cpp) [Python](./Python/valid-palindrome-ii.py) | _O(n)_ | _O(1)_ | Easy || +681| [Next Closest Time](https://leetcode.com/problems/next-closest-time/) | [C++](./C++/next-closest-time.cpp) [Python](./Python/next-closest-time.py) | _O(1)_ | _O(1)_ | Medium || +686 | [Repeated String Match](https://leetcode.com/problems/repeated-string-match/) | [C++](./C++/repeated-string-match.cpp) [Python](./Python/repeated-string-match.py) | _O(n + m)_ | _O(1)_ | Easy || `Rabin-Karp Algorithm` | +696| [Count Binary Substrings](https://leetcode.com/problems/count-binary-substrings/) | [C++](./C++/count-binary-substrings.cpp) [Python](./Python/count-binary-substrings.py) | _O(n)_ | _O(1)_ | Easy|| +720| [Longest Word in Dictionary](https://leetcode.com/problems/longest-word-in-dictionary/) | [C++](./C++/longest-word-in-dictionary.cpp) [Python](./Python/longest-word-in-dictionary.py) | _O(n)_ | _O(t)_ | Easy || Trie | +722| [Remove Comments](https://leetcode.com/problems/remove-comments/) | [C++](./C++/remove-comments.cpp) [Python](./Python/remove-comments.py) | _O(n)_ | _O(k)_ | Medium ||| + +## Linked List +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +2| [Add Two Numbers](https://leetcode.com/problems/add-two-numbers/) | [C++](./C++/add-two-numbers.cpp) [Python](./Python/add-two-numbers.py) | _O(n)_ | _O(1)_ | Medium || +21| [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/)| [C++](./C++/merge-two-sorted-lists.cpp) [Python](./Python/merge-two-sorted-lists.py) | _O(n)_ | _O(1)_ | Easy || +23| [Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) | [C++](./C++/merge-k-sorted-lists.cpp) [Python](./Python/merge-k-sorted-lists.py) | _O(nlogk)_| _O(1)_| Hard | | Heap, Divide and Conquer +24| [Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/)| [C++](./C++/swap-nodes-in-pairs.cpp) [Python](./Python/swap-nodes-in-pairs.py) | _O(n)_ | _O(1)_ | Easy || +25| [Reverse Nodes in k-Group](https://leetcode.com/problems/reverse-nodes-in-k-group/)| [C++](./C++/reverse-nodes-in-k-group.cpp) [Python](./Python/reverse-nodes-in-k-group.py) | _O(n)_ | _O(1)_ | Hard || +61| [Rotate List](https://leetcode.com/problems/rotate-list/)| [C++](./C++/rotate-list.cpp) [Python](./Python/rotate-list.py) | _O(n)_ | _O(1)_ | Medium || +82| [Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/)| [C++](./C++/remove-duplicates-from-sorted-list-ii.cpp) [Python](./Python/remove-duplicates-from-sorted-list-ii.py) | _O(n)_ | _O(1)_ | Medium || +83| [Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list/)| [C++](./C++/remove-duplicates-from-sorted-list.cpp) [Python](./Python/remove-duplicates-from-sorted-list.py) | _O(n)_ | _O(1)_ | Easy || +92| [Reverse Linked List II](https://leetcode.com/problems/reverse-linked-list-ii/)| [C++](./C++/reverse-linked-list-ii.cpp) [Python](./Python/reverse-linked-list-ii.py) | _O(n)_ | _O(1)_ | Medium || +138| [Copy List with Random Pointer](https://leetcode.com/problems/copy-list-with-random-pointer/) | [C++](./C++/copy-list-with-random-pointer.cpp) [Python](./Python/copy-list-with-random-pointer.py) | _O(n)_ | _O(1)_ | Hard || +160| [Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists/)| [C++](./C++/intersection-of-two-linked-lists.cpp) [Python](./Python/intersection-of-two-linked-lists.py) | _O(m + n)_ | _O(1)_ | Easy || +203| [Remove Linked List Elements](https://leetcode.com/problems/remove-linked-list-elements/)| [C++](./C++/remove-linked-list-elements.cpp) [Python](./Python/remove-linked-list-elements.py) | _O(n)_ | _O(1)_ | Easy || +206| [Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/)| [C++](./C++/reverse-linked-list.cpp) [Python](./Python/reverse-linked-list.py) | _O(n)_ | _O(1)_ | Easy || +234| [Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list/)| [C++](./C++/palindrome-linked-list.cpp) [Python](./Python/palindrome-linked-list.py) | _O(n)_ | _O(1)_ | Easy || +237| [Delete Node in a Linked List](https://leetcode.com/problems/delete-node-in-a-linked-list/)| [C++](./C++/delete-node-in-a-linked-list.cpp) [Python](./Python/delete-node-in-a-linked-list.py) | _O(1)_ | _O(1)_ | Easy | LintCode | +328| [Odd Even Linked List](https://leetcode.com/problems/odd-even-linked-list/)| [C++](./C++/odd-even-linked-list.cpp) [Python](./Python/odd-even-linked-list.py) | _O(n)_ | _O(1)_ | Medium | | +369| [Plus One Linked List](https://leetcode.com/problems/plus-one-linked-list/)| [C++](./C++/plus-one-linked-list.cpp) [Python](./Python/plus-one-linked-list.py) | _O(n)_ | _O(1)_ | Medium | 📖 | Two Pointers | +445| [Add Two Numbers II](https://leetcode.com/problems/add-two-numbers-ii/)| [C++](./C++/add-two-numbers-ii.cpp) [Python](./Python/add-two-numbers-ii.py) | _O(m + n)_ | _O(m + n)_ | Medium ||| +725 | [Split Linked List in Parts](https://leetcode.com/problems/split-linked-list-in-parts/) | [C++](./C++/split-linked-list-in-parts.cpp) [Python](./Python/split-linked-list-in-parts.py) | _O(n + k)_ | _O(1)_ | Medium || + +## Stack +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +20| [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/)| [C++](./C++/valid-parentheses.cpp) [Python](./Python/valid-parentheses.py) | _O(n)_ | _O(n)_ | Easy || +32| [Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/)| [C++](./C++/longest-valid-parentheses.cpp) [Python](./Python/longest-valid-parentheses.py) | _O(n)_ | _O(1)_ | Hard || +71| [Simplify Path](https://leetcode.com/problems/simplify-path/)| [C++](./C++/simplify-path.cpp) [Python](./Python/simplify-path.py) | _O(n)_ | _O(n)_ | Medium || +84| [Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) | [C++](./C++/largest-rectangle-in-histogram.cpp) [Python](./Python/largest-rectangle-in-histogram.py) | _O(n)_ | _O(n)_ | Hard || Ascending Stack, DP +85| [Maximal Rectangle](https://leetcode.com/problems/maximal-rectangle/)| [C++](./C++/maximal-rectangle.cpp) [Python](./Python/maximal-rectangle.py)| _O(m * n)_ | _O(n)_ | Hard | EPI | Ascending Stack +101| [Symmetric Tree](https://leetcode.com/problems/symmetric-tree/)| [C++](./C++/symmetric-tree.cpp) [Python](./Python/symmetric-tree.py) | _O(n)_ | _O(h)_ | Easy || +150| [Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/)| [C++](./C++/evaluate-reverse-polish-notation.cpp) [Python](./Python/evaluate-reverse-polish-notation.py)| _O(n)_| _O(n)_| Medium || +155| [Min Stack](https://leetcode.com/problems/min-stack/) | [C++](./C++/min-stack.cpp) [Python](./Python/min-stack.py) | _O(n)_ | _O(1)_ | Easy || +173| [Binary Search Tree Iterator](https://leetcode.com/problems/binary-search-tree-iterator/) | [C++](./C++/binary-search-tree-iterator.cpp) [Python](./Python/binary-search-tree-iterator.py) | _O(1)_| _O(h)_| Medium || +224| [Basic Calculator](https://leetcode.com/problems/basic-calculator/) | [C++](./C++/basic-calculator.cpp) [Python](./Python/basic-calculator.py) | _O(n)_| _O(n)_| Hard || +227| [Basic Calculator II](https://leetcode.com/problems/basic-calculator-ii/) | [C++](./C++/basic-calculator-ii.cpp) [Python](./Python/basic-calculator-ii.py) | _O(n)_| _O(n)_| Medium || +232| [Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks/) | [C++](./C++/implement-queue-using-stacks.cpp) [Python](./Python/implement-queue-using-stacks.py) | _O(1), amortized_| _O(n)_| Easy | EPI, LintCode | +255| [Verify Preorder Sequence in Binary Search Tree](https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/) | [C++](./C++/verify-preorder-sequence-in-binary-search-tree.cpp) [Python](./Python/verify-preorder-sequence-in-binary-search-tree.py) | _O(n)_| _O(1)_| Medium |📖|| +272| [Closest Binary Search Tree Value II](https://leetcode.com/problems/closest-binary-search-tree-value-ii/) | [C++](./C++/closest-binary-search-tree-value-ii.cpp) [Python](./Python/closest-binary-search-tree-value-ii.py) | _O(h + k)_| _O(h)_| Hard |📖|| +331| [Verify Preorder Serialization of a Binary Tree](https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/) | [C++](./C++/verify-preorder-serialization-of-a-binary-tree.cpp) [Python](./Python/verify-preorder-serialization-of-a-binary-tree.py) | _O(n)_| _O(1)_| Medium ||| +341| [Flatten Nested List Iterator](https://leetcode.com/problems/flatten-nested-list-iterator/)| [C++](./C++/flatten-nested-list-iterator.cpp) [Python](./Python/flatten-nested-list-iterator.py) | _O(n)_ | _O(h)_ | Medium |📖| Iterator | +385| [Mini Parser](https://leetcode.com/problems/mini-parser/)| [C++](./C++/mini-parser.cpp) [Python](./Python/mini-parser.py) | _O(n)_ | _O(h)_ | Medium ||| +394| [Decode String](https://leetcode.com/problems/decode-string/)| [C++](./C++/decode-string.cpp) [Python](./Python/decode-string.py) | _O(n)_ | _O(h)_ | Medium ||| +439| [Ternary Expression Parser](https://leetcode.com/problems/ternary-expression-parser/) | [C++](./C++/ternary-expression-parser.cpp) [Python](./Python/ternary-expression-parser.py) | _O(n)_ | _O(1)_ | Medium |📖| +456| [132 Pattern](https://leetcode.com/problems/132-pattern/) | [C++](./C++/132-pattern.cpp) [Python](./Python/132-pattern.py) | _O(n)_ | _O(n)_ | Medium || +636| [Exclusive Time of Functions](https://leetcode.com/problems/exclusive-time-of-functions/) | [C++](./C++/exclusive-time-of-functions.cpp) [Python](./Python/exclusive-time-of-functions.py) | _O(n)_ | _O(n)_ | Medium || +682| [Baseball Game](https://leetcode.com/problems/baseball-game/) | [C++](./C++/baseball-game.cpp) [Python](./Python/baseball-game.py) | _O(n)_ | _O(n)_ | Easy || +726| [Number of Atoms](https://leetcode.com/problems/number-of-atoms/) | [C++](./C++/number-of-atoms.cpp) [Python](./Python/number-of-atoms.py) | _O(n)_ | _O(n)_ | Hard || +735| [Asteroid Collision](https://leetcode.com/problems/asteroid-collision/) | [C++](./C++/asteroid-collision.cpp) [Python](./Python/asteroid-collision.py) | _O(n)_ | _O(n)_ | Medium || +736| [Parse Lisp Expression](https://leetcode.com/problems/parse-lisp-expression/) | [C++](./C++/parse-lisp-expression.cpp) [Python](./Python/parse-lisp-expression.py) | _O(n^2)_ | _O(n^2)_ | Hard || +739| [Daily Temperatures](https://leetcode.com/problems/daily-temperatures/) | [C++](./C++/daily-temperatures.cpp) [Python](./Python/daily-temperatures.py) | _O(n)_ | _O(n)_ | Medium || + +## Queue +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +239| [Sliding Window Maximum](https://leetcode.com/problems/sliding-window-maximum/)| [C++](./C++/sliding-window-maximum.cpp) [Python](./Python/sliding-window-maximum.py) | _O(n)_ | _O(k)_ | Hard | EPI, LintCode | +281| [Zigzag Iterator](https://leetcode.com/problems/zigzag-iterator/)| [C++](./C++/zigzag-iterator.cpp) [Python](./Python/zigzag-iterator.py) | _O(n)_ | _O(k)_ | Medium |📖|| +346| [Moving Average from Data Stream](https://leetcode.com/problems/moving-average-from-data-stream/)| [C++](./C++/moving-average-from-data-stream.cpp) [Python](./Python/moving-average-from-data-stream.py) | _O(1)_ | _O(w)_ | Easy |📖|| + +## Heap +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +264| [Ugly Number II](https://leetcode.com/problems/ugly-number-ii/) | [C++](./C++/ugly-number-ii.cpp) [Python](./Python/ugly-number-ii.py) | _O(n)_ | _O(1)_ | Medium | CTCI, LintCode | BST, Heap | +295| [Find Median from Data Stream](https://leetcode.com/problems/find-median-from-data-stream/) | [C++](./C++/find-median-from-data-stream.cpp) [Python](./Python/find-median-from-data-stream.py) | _O(nlogn)_ | _O(n)_ | Hard | EPI, LintCode | BST, Heap | +313| [Super Ugly Number](https://leetcode.com/problems/super-ugly-number/) | [C++](./C++/super-ugly-number.cpp) [Python](./Python/super-ugly-number.py) | _O(n * k)_ | _O(n + k)_ | Medium || BST, Heap | +358| [Rearrange String k Distance Apart](https://leetcode.com/problems/rearrange-string-k-distance-apart/)| [C++](./C++/rearrange-string-k-distance-apart.cpp) [Python](./Python/rearrange-string-k-distance-apart.py) | _O(n)_ | _O(n)_ | Hard |📖| Greedy, Heap | +373 | [Find K Pairs with Smallest Sums](https://leetcode.com/problems/find-k-pairs-with-smallest-sums/) | [C++](./C++/find-k-pairs-with-smallest-sums.cpp) [Python](./Python/find-k-pairs-with-smallest-sums.py) | _O(k * log(min(n, m, k)))_ | _O(min(n, m, k))_ | Medium ||| +378 | [Kth Smallest Element in a Sorted Matrix](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/) | [C++](./C++/kth-smallest-element-in-a-sorted-matrix.cpp) [Python](./Python/kth-smallest-element-in-a-sorted-matrix.py) | _O(k * log(min(n, m, k)))_ | _O(min(n, m, k))_ | Medium | LintCode || +407 | [Trapping Rain Water II](https://leetcode.com/problems/trapping-rain-water-ii/) | [C++](./C++/trapping-rain-water-ii.cpp) [Python](./Python/trapping-rain-water-ii.py) | _O(m * n * (logm + logn))_ | _O(m * n)_ | Hard | LintCode || +632 | [Smallest Range](https://leetcode.com/problems/smallest-range/) | [C++](./C++/smallest-range.cpp) [Python](./Python/smallest-range.py) | _O(nlogk)_ | _O(k)_ | Hard ||| + +## Tree +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +94 | [Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) | [C++](./C++/binary-tree-inorder-traversal.cpp) [Python](./Python/binary-tree-inorder-traversal.py) | _O(n)_| _O(1)_| Medium || `Morris Traversal` | +99 | [Recover Binary Search Tree](https://leetcode.com/problems/recover-binary-search-tree/) | [C++](./C++/recover-binary-search-tree.cpp) [Python](./Python/recover-binary-search-tree.py) | _O(n)_| _O(1)_| Hard || `Morris Traversal` +144 | [Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/) | [C++](./C++/binary-tree-preorder-traversal.cpp) [Python](./Python/binary-tree-preorder-traversal.py) | _O(n)_| _O(1)_| Medium || `Morris Traversal` +145 | [Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/) | [C++](./C++/binary-tree-postorder-traversal.cpp) [Python](./Python/binary-tree-postorder-traversal.py) | _O(n)_| _O(1)_| Hard || `Morris Traversal` +208 | [Implement Trie (Prefix Tree)](https://leetcode.com/problems/implement-trie-prefix-tree/) | [C++](./C++/implement-trie-prefix-tree.cpp) [Python](./Python/implement-trie-prefix-tree.py) | _O(n)_ | _O(1)_ | Medium || Trie +211 | [Add and Search Word - Data structure design](https://leetcode.com/problems/add-and-search-word-data-structure-design/) | [C++](./C++/add-and-search-word-data-structure-design.cpp) [Python](./Python/add-and-search-word-data-structure-design.py) | _O(min(n, h))_ | _O(min(n, h))_ | Medium || Trie, DFS +226| [Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) | [C++](./C++/invert-binary-tree.cpp) [Python](./Python/invert-binary-tree.py) | _O(n)_ | _O(h)_, _O(w)_ | Easy || +297 | [Serialize and Deserialize Binary Tree](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/) | [C++](./C++/serialize-and-deserialize-binary-tree.cpp) [Python](./Python/serialize-and-deserialize-binary-tree.py) | _O(n)_ | _O(h)_ | Hard | LintCode | DFS +307 | [Range Sum Query - Mutable](https://leetcode.com/problems/range-sum-query-mutable/) | [C++](./C++/range-sum-query-mutable.cpp) [Python](./Python/range-sum-query-mutable.py) | ctor: _O(n)_, update: _O(logn)_, query: _O(logn)_ | _O(n)_ | Medium | LintCode | DFS, Segment Tree, BIT +308 | [Range Sum Query 2D - Mutable](https://leetcode.com/problems/range-sum-query-2d-mutable/) | [C++](./C++/range-sum-query-2d-mutable.cpp) [Python](./Python/range-sum-query-2d-mutable.py) | ctor: _O(m * n)_, update: _O(logm + logn)_, query: _O(logm + logn)_ | _O(m * n)_ | Hard | 📖 | DFS, Segment Tree, BIT +315|[Count of Smaller Numbers After Self](https://leetcode.com/problems/count-of-smaller-numbers-after-self/)| [C++](./C++/count-of-smaller-numbers-after-self.cpp) [Python](./Python/count-of-smaller-numbers-after-self.py)| _O(nlogn)_ | _O(n)_ | Hard | LintCode | BST, BIT, Divide and Conquer | +548 | [Split Array with Equal Sum](https://leetcode.com/problems/split-array-with-equal-sum/) | [C++](./C++/split-array-with-equal-sum.cpp) [Python](./Python/split-array-with-equal-sum.py) | _O(n^2)_ | _O(n)_ | Medium |📖| +563 |[Binary Tree Tilt](https://leetcode.com/problems/binary-tree-tilt/)| [C++](./C++/binary-tree-tilt.cpp) [Python](./Python/binary-tree-tilt.py)| _O(n)_ | _O(n)_ | Easy | | | +572 |[Subtree of Another Tree](https://leetcode.com/problems/construct-string-from-binary-tree/)| [C++](./C++/subtree-of-another-tree.cpp) [Python](./Python/subtree-of-another-tree.py)| _O(m * n)_ | _O(h)_ | Easy | | | +606 |[Construct String from Binary Tree](https://leetcode.com/problems/construct-string-from-binary-tree/)| [C++](./C++/construct-string-from-binary-tree.cpp) [Python](./Python/construct-string-from-binary-tree.py)| _O(n)_ | _O(h)_ | Easy | | | +617 |[Merge Two Binary Trees](https://leetcode.com/problems/merge-two-binary-trees/)| [C++](./C++/merge-two-binary-trees.cpp) [Python](./Python/merge-two-binary-trees.py)| _O(n)_ | _O(h)_ | Easy | | | +623 |[Add One Row to Tree](https://leetcode.com/problems/add-one-row-to-tree/)| [C++](./C++/add-one-row-to-tree.cpp) [Python](./Python/add-one-row-to-tree.py)| _O(n)_ | _O(h)_ | Medium | | | +637 |[Average of Levels in Binary Tree](https://leetcode.com/problems/average-of-levels-in-binary-tree/)| [C++](./C++/average-of-levels-in-binary-tree.cpp) [Python](./Python/average-of-levels-in-binary-tree.py)| _O(n)_ | _O(h)_ | Easy | | | +652 |[Find Duplicate Subtrees](https://leetcode.com/problems/find-duplicate-subtrees/)| [C++](./C++/find-duplicate-subtrees.cpp) [Python](./Python/find-duplicate-subtrees.py)| _O(n)_ | _O(n)_ | Medium | | DFS, Hash | +653 |[Two Sum IV - Input is a BST](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/)| [C++](./C++/two-sum-iv-input-is-a-bst.cpp) [Python](./Python/two-sum-iv-input-is-a-bst.py)| _O(n)_ | _O(h)_ | Easy | | Two Pointers | +654 |[Maximum Binary Tree](https://leetcode.com/problems/maximum-binary-tree/)| [C++](./C++/maximum-binary-tree.cpp) [Python](./Python/maximum-binary-tree.py)| _O(n)_ | _O(n)_ | Medium | LintCode | Descending Stack | +655 | [Print Binary Tree](https://leetcode.com/problems/print-binary-tree/) | [C++](./C++/print-binary-tree.cpp) [Python](./Python/print-binary-tree.py) | _O(n)_ | _O(h)_ | Medium | | +662 | [Maximum Width of Binary Tree](https://leetcode.com/problems/maximum-width-of-binary-tree/) | [C++](./C++/maximum-width-of-binary-tree.cpp) [Python](./Python/maximum-width-of-binary-tree.py) | _O(n)_ | _O(h)_ | Medium | | DFS +663 | [Equal Tree Partition](https://leetcode.com/problems/strange-printer/) | [C++](./C++/equal-tree-partition.cpp) [Python](./Python/equal-tree-partition.py) | _O(n)_ | _O(n)_ | Medium | 📖 | Hash +677 | [Map Sum Pairs](https://leetcode.com/problems/map-sum-pairs/) | [C++](./C++/map-sum-pairs.cpp) [Python](./Python/map-sum-pairs.py) | _O(n)_ | _O(t)_ | Medium || Trie +684 | [Redundant Connection](https://leetcode.com/problems/redundant-connection/) | [C++](./C++/redundant-connection.cpp) [Python](./Python/redundant-connection.py) | _O(n)_ | _O(n)_ | Medium || Union Find +685 | [Redundant Connection II](https://leetcode.com/problems/redundant-connection-ii/) | [C++](./C++/redundant-connection-ii.cpp) [Python](./Python/redundant-connection-ii.py) | _O(n)_ | _O(n)_ | Hard || Union Find +687 | [Longest Univalue Path](https://leetcode.com/problems/longest-univalue-path/) | [C++](./C++/longest-univalue-path.cpp) [Python](./Python/longest-univalue-path.py) | _O(n)_ | _O(h)_ | Easy || +699 | [Falling Squares](https://leetcode.com/problems/falling-squares/) | [C++](./C++/falling-squares.cpp) [Python](./Python/falling-squares.py) | _O(nlogn)_ | _O(n)_ | Hard || Segment Tree | + +## Hash Table +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +1| [Two Sum](https://leetcode.com/problems/two-sum/) | [C++](./C++/two-sum.cpp) [Python](./Python/two-sum.py) | _O(n)_ | _O(n)_ | Easy || +3| [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) | [C++](./C++/longest-substring-without-repeating-characters.cpp) [Python](./Python/longest-substring-without-repeating-characters.py) | _O(n)_ | _O(1)_ | Medium || +30| [Substring with Concatenation of All Words](https://leetcode.com/problems/substring-with-concatenation-of-all-words/) | [C++](./C++/substring-with-concatenation-of-all-words.cpp) [Python](./Python/substring-with-concatenation-of-all-words.py) | _O((m + n) * k)_ | _O(n * k)_ | Hard || +36| [Valid Sudoku](https://leetcode.com/problems/valid-sudoku/) | [C++](./C++/valid-sudoku.cpp) [Python](./Python/valid-sudoku.py) | _O(9^2)_ | _O(9)_ | Easy || +49| [Group Anagrams](https://leetcode.com/problems/anagrams/) | [C++](./C++/anagrams.cpp) [Python](./Python/anagrams.py) | _O(n * glogg)_ | _O(n)_ | Medium || +76| [Minimum Window Substring](https://leetcode.com/problems/minimum-window-substring/) | [C++](./C++/minimum-window-substring.cpp) [Python](./Python/minimum-window-substring.py) | _O(n)_ | _O(k)_ | Hard || +149| [Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) | [C++](./C++/max-points-on-a-line.cpp) [Python](./Python/max-points-on-a-line.py) | _O(n^2)_ | _O(n)_ | Hard || +159| [Longest Substring with At Most Two Distinct Characters](https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/)| [C++](./C++/longest-substring-with-at-most-two-distinct-characters.cpp) [Python](./Python/longest-substring-with-at-most-two-distinct-characters.py) | _O(n)_ | _O(1)_ | Hard |📖| +170| [Two Sum III - Data structure design](https://leetcode.com/problems/two-sum-iii-data-structure-design/) | [C++](./C++/two-sum-iii-data-structure-design.cpp) [Python](./Python/two-sum-iii-data-structure-design.py) | _O(n)_ | _O(n)_ | Easy | 📖 | +187| [Repeated DNA Sequences](https://leetcode.com/problems/repeated-dna-sequences/) | [Python](./Python/repeated-dna-sequences.py) | _O(n)_ | _O(n)_ | Medium || +202| [Happy Number](https://leetcode.com/problems/happy-number/) | [C++](./C++/happy-number.cpp) [Python](./Python/happy-number.py) | _O(k)_ | _O(k)_ | Easy || +204| [Count Primes](https://leetcode.com/problems/count-primes/) | [C++](./C++/count-primes.cpp) [Python](./Python/count-primes.py) | _O(n)_ | _O(n)_ | Easy || +205| [Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) | [C++](./C++/isomorphic-strings.cpp) [Python](./Python/isomorphic-strings.py) | _O(n)_ | _O(1)_ | Easy || +217| [Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) | [C++](./C++/contains-duplicate.cpp) [Python](./Python/contains-duplicate.py) | _O(n)_ | _O(n)_ | Easy || +219| [Contains Duplicate II](https://leetcode.com/problems/contains-duplicate-ii/) | [C++](./C++/contains-duplicate-ii.cpp) [Python](./Python/contains-duplicate-ii.py) | _O(n)_ | _O(n)_ | Easy || +244| [Shortest Word Distance II](https://leetcode.com/problems/shortest-word-distance-ii/) | [C++](./C++/shortest-word-distance-ii.cpp) [Python](./Python/shortest-word-distance-ii.py) | ctor: _O(n)_, lookup: _O(a + b)_ | _O(n)_ | Medium |📖|| +246| [Strobogrammatic Number](https://leetcode.com/problems/strobogrammatic-number/) | [C++](./C++/strobogrammatic-number.cpp) [Python](./Python/strobogrammatic-number.py) | _O(n)_ | _O(1)_ | Easy |📖|| +249| [Group Shifted Strings](https://leetcode.com/problems/group-shifted-strings/) | [C++](./C++/group-shifted-strings.cpp) [Python](./Python/group-shifted-strings.py) | _O(nlogn)_ | _O(n)_ | Easy |📖|| +266| [Palindrome Permutation](https://leetcode.com/problems/palindrome-permutation/) | [C++](./C++/palindrome-permutation.cpp) [Python](./Python/palindrome-permutation.py) | _O(n)_ | _O(1)_ | Easy |📖|| +288| [Unique Word Abbreviation](https://leetcode.com/problems/unique-word-abbreviation/) | [C++](./C++/unique-word-abbreviation.cpp) [Python](./Python/unique-word-abbreviation.py) | ctor: _O(n)_, lookup: _O(1)_ | _O(k)_ | Easy |📖|| +290| [Word Pattern](https://leetcode.com/problems/word-pattern/) | [C++](./C++/word-pattern.cpp) [Python](./Python/word-pattern.py) | _O(n)_ | _O(c)_ | Easy | variant of [Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) || +299| [Bulls and Cows](https://leetcode.com/problems/bulls-and-cows/) | [C++](./C++/bulls-and-cows.cpp) [Python](./Python/bulls-and-cows.py) | _O(n)_ | _O(1)_ | Easy ||| +305| [Number of Islands II](https://leetcode.com/problems/number-of-islands-ii/) | [C++](./C++/number-of-islands-ii.cpp) [Python](./Python/number-of-islands-ii.py) | _O(k)_ | _O(k)_| Hard | LintCode, 📖 | Union Find +314| [Binary Tree Vertical Order Traversal](https://leetcode.com/problems/binary-tree-vertical-order-traversal/) | [C++](./C++/binary-tree-vertical-order-traversal.cpp) [Python](./Python/binary-tree-vertical-order-traversal.py) | _O(n)_ | _O(n)_| Medium | 📖 | BFS +323| [Number of Connected Components in an Undirected Graph](https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/) | [C++](./C++/number-of-connected-components-in-an-undirected-graph.cpp) [Python](./Python/number-of-connected-components-in-an-undirected-graph.py) | _O(n)_ | _O(n)_| Medium | 📖 | Union Find +325| [Maximum Size Subarray Sum Equals k](https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/) | [C++](./C++/maximum-size-subarray-sum-equals-k.cpp) [Python](./Python/maximum-size-subarray-sum-equals-k.py) | _O(n)_ | _O(n)_| Medium | 📖 | +336| [Palindrome Pairs](https://leetcode.com/problems/palindrome-pairs/) | [C++](./C++/palindrome-pairs.cpp) [Python](./Python/palindrome-pairs.py) | _O(n * k^2)_ | _O(n * k)_ | Hard | | | +340| [Longest Substring with At Most K Distinct Characters](https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/)| [C++](./C++/longest-substring-with-at-most-k-distinct-characters.cpp) [Python](./Python/longest-substring-with-at-most-k-distinct-characters.py) | _O(n)_ | _O(1)_ | Hard |📖| +356| [Line Reflection](https://leetcode.com/problems/line-reflection/) | [C++](./C++/line-reflection.cpp) [Python](./Python/line-reflection.py) | _O(n)_| _O(n)_| Medium |📖| Hash, Two Pointers | +387| [First Unique Character in a String](https://leetcode.com/problems/first-unique-character-in-a-string/) | [C++](./C++/first-unique-character-in-a-string.cpp) [Python](./Python/first-unique-character-in-a-string.py) | _O(n)_| _O(n)_| Easy ||| +388| [Longest Absolute File Path](https://leetcode.com/problems/longest-absolute-file-path/) | [C++](./C++/longest-absolute-file-path.cpp) [Python](./Python/longest-absolute-file-path.py) | _O(n)_| _O(d)_| Medium || Stack | +409| [Longest Palindrome](https://leetcode.com/problems/longest-palindrome/) | [C++](./C++/longest-palindrome.cpp) [Python](./Python/longest-palindrome.py) | _O(n)_| _O(1)_| Easy ||| +424| [Longest Repeating Character Replacement](https://leetcode.com/problems/longest-repeating-character-replacement/) | [C++](./C++/longest-repeating-character-replacement.cpp) [Python](./Python/longest-repeating-character-replacement.py) | _O(n)_| _O(1)_| Medium ||| +438| [Find All Anagrams in a String](https://leetcode.com/problems/find-all-anagrams-in-a-string/) | [C++](./C++/find-all-anagrams-in-a-string.cpp) [Python](./Python/find-all-anagrams-in-a-string.py) | _O(n)_ | _O(1)_ | Easy || +447| [Number of Boomerangs](https://leetcode.com/problems/number-of-boomerangs/) | [C++](./C++/number-of-boomerangs.cpp) [Python](./Python/number-of-boomerangs.py) | _O(n^2)_ | _O(n)_ | Easy || +454| [4Sum II](https://leetcode.com/problems/4sum-ii/) | [C++](./C++/4sum-ii.cpp) [Python](./Python/4sum-ii.py) | _O(n^2)_ | _O(n^2)_ | Medium || +473| [Matchsticks to Square](https://leetcode.com/problems/matchsticks-to-square/) | [C++](./C++/matchsticks-to-square.cpp) [Python](./Python/matchsticks-to-square.py) | _O(n * s * 2^n)_ | _O(n * (2^n + s))_ | Medium || +554| [Brick Wall](https://leetcode.com/problems/brick-wall/) |[C++](./C++/brick-wall.cpp) [Python](./Python/brick-wall.py) | _O(n)_ | _O(m)_ | Medium | | +560| [Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/) |[C++](./C++/subarray-sum-equals-k.cpp) [Python](./Python/subarray-sum-equals-k.py) | _O(n)_ | _O(n)_ | Medium | | +561| [Array Partition I](https://leetcode.com/problems/array-partition-i/) |[C++](./C++/array-partition-i.cpp) [Python](./Python/array-partition-i.py) | _O(r)_ | _O(r)_ | Easy | | +575| [Distribute Candies](https://leetcode.com/problems/distribute-candies/) |[C++](./C++/distribute-candies.cpp) [Python](./Python/distribute-candies.py) | _O(n)_ | _O(n)_ | Easy | | +594| [Longest Harmonious Subsequence](https://leetcode.com/problems/longest-harmonious-subsequence/) |[C++](./C++/longest-harmonious-subsequence.cpp) [Python](./Python/longest-harmonious-subsequence.py) | _O(n)_ | _O(n)_ | Easy | | +599| [Minimum Index Sum of Two Lists](https://leetcode.com/problems/minimum-index-sum-of-two-lists/) |[C++](./C++/minimum-index-sum-of-two-lists.cpp) [Python](./Python/minimum-index-sum-of-two-lists.py) | _O((m + n) * l)_ | _O(m * l)_ | Easy | | +609| [Find Duplicate File in System](https://leetcode.com/problems/find-duplicate-file-in-system/) |[C++](./C++/find-duplicate-file-in-system.cpp) [Python](./Python/find-duplicate-file-in-system.py) | _O(n * l)_ | _O(n * l)_ | Medium | | +721| [Accounts Merge](https://leetcode.com/problems/accounts-merge/) | [C++](./C++/accounts-merge.cpp) [Python](./Python/accounts-merge.py) | _O(nlogn)_ | _O(n)_| Medium || Union Find +734| [Sentence Similarity](https://leetcode.com/problems/sentence-similarity/) | [C++](./C++/sentence-similarity.cpp) [Python](./Python/sentence-similarity.py) | _O(n + p)_ | _O(p)_| Easy || +737| [Sentence Similarity II](https://leetcode.com/problems/sentence-similarity-ii/) | [C++](./C++/sentence-similarity-ii.cpp) [Python](./Python/sentence-similarity-ii.py) | _O(n + p)_ | _O(p)_| Medium || Union Find +748 | [Shortest Completing Word](https://leetcode.com/problems/shortest-completing-word/) | [C++](./C++/shortest-completing-word.cpp) [Python](./Python/shortest-completing-word.py) | _O(n)_ | _O(1)_ | Easy || + +## Math +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +7| [Reverse Integer](https://leetcode.com/problems/reverse-integer/) | [C++](./C++/reverse-integer.cpp) [Python](./Python/reverse-integer.py) | _O(1)_ | _O(1)_ | Easy || +9| [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | [C++](./C++/palindrome-number.cpp) [Python](./Python/palindrome-number.py) | _O(1)_ | _O(1)_ | Easy || +12| [Integer to Roman](https://leetcode.com/problems/integer-to-roman/) | [C++](./C++/integer-to-roman.cpp) [Python](./Python/integer-to-roman.py) | _O(n)_ | _O(1)_ | Medium || +13| [Roman to Integer](https://leetcode.com/problems/roman-to-integer/) | [C++](./C++/roman-to-integer.cpp) [Python](./Python/roman-to-integer.py) | _O(n)_ | _O(1)_ | Easy || +29| [Divide Two Integers](https://leetcode.com/problems/divide-two-integers/) | [C++](./C++/divide-two-integers.cpp) [Python](./Python/divide-two-integers.py) | _O(1)_ | _O(1)_ | Medium || +50| [Pow(x, n)](https://leetcode.com/problems/powx-n/) | [C++](./C++/powx-n.cpp) [Python](./Python/powx-n.py) | _O(1)_ | _O(1)_ | Medium || +60| [Permutation Sequence](https://leetcode.com/problems/permutation-sequence/) | [C++](./C++/permutation-sequence.cpp) [Python](./Python/permutation-sequence.py) | _O(n^2)_ | _O(n)_ | Medium || `Cantor Ordering` +65| [Valid Number](https://leetcode.com/problems/valid-number/) | [C++](./C++/valid-number.cpp) [Python](./Python/valid-number.py) | _O(n)_ | _O(1)_ | Hard || `Automata` +89| [Gray Code](https://leetcode.com/problems/gray-code/) | [C++](./C++/gray-code.cpp) [Python](./Python/gray-code.py) | _O(2^n)_ | _O(1)_ | Medium || +166| [Fraction to Recurring Decimal](https://leetcode.com/problems/fraction-to-recurring-decimal/) | [C++](./C++/fraction-to-recurring-decimal.cpp) [Python](./Python/fraction-to-recurring-decimal.py) | _O(logn)_ | _O(1)_ | Medium || +168| [Excel Sheet Column Title](https://leetcode.com/problems/excel-sheet-column-title/) | [C++](./C++/excel-sheet-column-title.cpp) [Python](./Python/excel-sheet-column-title.py) | _O(logn)_ | _O(1)_ | Easy || +171| [Excel Sheet Column Number](https://leetcode.com/problems/excel-sheet-column-number/) | [C++](./C++/excel-sheet-column-number.cpp) [Python](./Python/excel-sheet-column-number.py) | _O(n)_ | _O(1)_ | Easy || +172| [Factorial Trailing Zeroes](https://leetcode.com/problems/factorial-trailing-zeroes/) | [C++](./C++/factorial-trailing-zeroes.cpp) [Python](./Python/factorial-trailing-zeroes.py) | _O(1)_ | _O(1)_ | Easy || +223| [Rectangle Area](https://leetcode.com/problems/rectangle-area/) | [C++](./C++/rectangle-area.cpp) [Python](./Python/rectangle-area.py) | _O(1)_ | _O(1)_ | Easy || +233| [Number of Digit One](https://leetcode.com/problems/number-of-digit-one/) | [C++](./C++/number-of-digit-one.cpp) [Python](./Python/number-of-digit-one.py) | _O(1)_ | _O(1)_ | Hard | CTCI, LintCode| +248| [Strobogrammatic Number III](https://leetcode.com/problems/strobogrammatic-number-iii/) | [C++](./C++/strobogrammatic-number-iii.cpp) [Python](./Python/strobogrammatic-number-iii.py) | _O(5^(n/2))_ | _O(n)_ | Hard |📖|| +258| [Add Digits](https://leetcode.com/problems/add-digits/) | [C++](./C++/add-digits.cpp) [Python](./Python/add-digits.py) | _O(1)_ | _O(1)_ | Easy ||| +263| [Ugly Number](https://leetcode.com/problems/ugly-number/) | [C++](./C++/ugly-number.cpp) [Python](./Python/ugly-number.py) | _O(1)_ | _O(1)_ | Easy ||| +292| [Nim Game](https://leetcode.com/problems/nim-game/) | [C++](./C++/nim-game.cpp) [Python](./Python/nim-game.py) | _O(1)_ | _O(1)_ | Easy | LintCode || +319 | [Bulb Switcher](https://leetcode.com/problems/bulb-switcher/) | [C++](./C++/bulb-switcher.cpp) [Python](./Python/bulb-switcher.py) | _O(1)_ | _O(1)_ | Medium ||| +326 | [Power of Three](https://leetcode.com/problems/power-of-three/) | [C++](./C++/power-of-three.cpp) [Python](./Python/power-of-three.py) | _O(1)_ | _O(1)_ | Easy ||| +335 | [Self Crossing](https://leetcode.com/problems/self-crossing/) | [C++](./C++/self-crossing.cpp) [Python](./Python/self-crossing.py) | _O(n)_ | _O(1)_ | Hard ||| +338 | [Counting Bits](https://leetcode.com/problems/counting-bits/) | [C++](./C++/counting-bits.cpp) [Python](./Python/counting-bits.py) | _O(n)_ | _O(n)_ | Medium ||| +343 | [Integer Break](https://leetcode.com/problems/integer-break/) | [C++](./C++/integer-break.cpp) [Python](./Python/integer-break.py) | _O(logn)_ | _O(1)_ | Medium || Tricky, DP | +365 | [Water and Jug Problem](https://leetcode.com/problems/water-and-jug-problem/) | [C++](./C++/water-and-jug-problem.cpp) [Python](./Python/water-and-jug-problem.py) | _O(logn)_ | _O(1)_ | Medium || `Bézout's identity` | +372 | [Super Pow](https://leetcode.com/problems/super-pow/) | [C++](./C++/super-pow.cpp) [Python](./Python/super-pow.py) | _O(n)_ | _O(1)_ | Medium ||| +382 | [Linked List Random Node](https://leetcode.com/problems/linked-list-random-node/) | [C++](./C++/linked-list-random-node.cpp) [Python](./Python/linked-list-random-node.py) | _O(n)_ | _O(1)_ | Medium || `Reservoir Sampling` | +386 | [Lexicographical Numbers](https://leetcode.com/problems/lexicographical-numbers/) | [C++](./C++/lexicographical-numbers.cpp) [Python](./Python/lexicographical-numbers.py) | _O(n)_ | _O(1)_ | Medium ||| +390 | [Elimination Game](https://leetcode.com/problems/elimination-game/) | [C++](./C++/elimination-game.cpp) [Python](./Python/elimination-game.py) | _O(logn)_ | _O(1)_ | Medium || +391 | [Perfect Rectangle](https://leetcode.com/problems/perfect-rectangle/) | [C++](./C++/perfect-rectangle.cpp) [Python](./Python/perfect-rectangle.py) | _O(n)_ | _O(n)_ | Hard | | +398 | [Random Pick Index](https://leetcode.com/problems/random-pick-index/) | [C++](./C++/random-pick-index.cpp) [Python](./Python/random-pick-index.py) | _O(n)_ | _O(1)_ | Medium || `Reservoir Sampling` | +400 | [Nth Digit](https://leetcode.com/problems/nth-digit/) | [C++](./C++/nth-digit.cpp) [Python](./Python/nth-digit.py) | _O(logn)_ | _O(1)_ | Easy ||| +413 | [Arithmetic Slices](https://leetcode.com/problems/arithmetic-slices/) | [C++](./C++/arithmetic-slices.cpp) [Python](./Python/arithmetic-slices.py) | _O(n)_ | _O(1)_ | Medium ||| +423 | [Reconstruct Original Digits from English](https://leetcode.com/problems/reconstruct-original-digits-from-english/) | [C++](./C++/reconstruct-original-digits-from-english.cpp) [Python](./Python/reconstruct-original-digits-from-english.py) | _O(n)_ | _O(1)_ | Medium | [GCJ2016 - Round 1B](https://code.google.com/codejam/contest/11254486/dashboard#s=p0)|| +441 | [Arranging Coins](https://leetcode.com/problems/arranging-coins/) | [C++](./C++/arranging-coins.cpp) [Python](./Python/arranging-coins.py) | _O(nlogn)_ | _O(1)_ | Easy || Binary Search| +453 | [Minimum Moves to Equal Array Elements](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/) | [C++](./C++/minimum-number-of-arrows-to-burst-balloons.cpp) [Python](./Python/minimum-number-of-arrows-to-burst-balloons.py) | _O(n)_ | _O(1)_ | Easy ||| +458 | [Poor Pigs](https://leetcode.com/problems/poor-pigs/) | [C++](./C++/poor-pigs.cpp) [Python](./Python/poor-pigs.py) | _O(n)_ | _O(1)_ | Easy ||| +469 | [Convex Polygon](https://leetcode.com/problems/convex-polygon/) | [C++](./C++/convex-polygon.cpp) [Python](./Python/convex-polygon.py) | _O(n)_ | _O(1)_ | Medium |📖|| +553 | [Optimal Division](https://leetcode.com/problems/optimal-division/) | [C++](./C++/optimal-division.cpp) [Python](./Python/optimal-division.py) | _O(n)_ | _O(1)_ | Medium ||| +573 | [Squirrel Simulation](https://leetcode.com/problems/squirrel-simulation/) | [C++](./C++/squirrel-simulation.cpp) [Python](./Python/squirrel-simulation.py) | _O(n)_ | _O(1)_ | Medium |📖|| +592 | [Fraction Addition and Subtraction](https://leetcode.com/problems/fraction-addition-and-subtraction/) | [C++](./C++/fraction-addition-and-subtraction.cpp) [Python](./Python/fraction-addition-and-subtraction.py) | _O(nlogx)_ | _O(n)_ | Medium ||| +593 | [Valid Square](https://leetcode.com/problems/valid-square/) | [C++](./C++/valid-square.cpp) [Python](./Python/valid-square.py) | _O(1)_ | _O(1)_ | Medium ||| +598 | [Range Addition II](https://leetcode.com/problems/range-addition-ii/) | [C++](./C++/range-addition-ii.cpp) [Python](./Python/range-addition-ii.py) | _O(p)_ | _O(1)_ | Easy ||| +625 | [Minimum Factorization](https://leetcode.com/problems/minimum-factorization/) | [C++](./C++/minimum-factorization.cpp) [Python](./Python/minimum-factorization.py) | _O(loga)_ | _O(1)_ | Medium |📖|| +628| [Maximum Product of Three Numbers](https://leetcode.com/problems/maximum-product-of-three-numbers/) | [C++](./C++/maximum-product-of-three-numbers.cpp) [Python](./Python/maximum-product-of-three-numbers.py) | _O(n)_ | _O(1)_ | Easy ||| +633| [Sum of Square Numbers](https://leetcode.com/problems/sum-of-square-numbers/) | [C++](./C++/sum-of-square-numbers.cpp) [Python](./Python/sum-of-square-numbers.py) | _O(sqrt(c) * logc)_ | _O(1)_ | Easy ||| +634| [Find the Derangement of An Array](https://leetcode.com/problems/find-the-derangement-of-an-array/) | [C++](./C++/find-the-derangement-of-an-array.cpp) [Python](./Python/find-the-derangement-of-an-array.py) | _O(n)_ | _O(1)_ | Medium |📖|| +640| [Solve the Equation](https://leetcode.com/problems/solve-the-equation/) | [C++](./C++/solve-the-equation.cpp) [Python](./Python/solve-the-equation.py) | _O(n)_ | _O(n)_ | Medium || | +651 | [4 Keys Keyboard](https://leetcode.com/problems/4-keys-keyboard/) | [C++](./C++/4-keys-keyboard.cpp) [Python](./Python/4-keys-keyboard.py) | _O(1)_ | _O(1)_ | Medium |📖| Math, DP | +660 | [Remove 9](https://leetcode.com/problems/remove-9/) | [C++](./C++/remove-9.cpp) [Python](./Python/remove-9.py) | _O(logn)_ | _O(1)_ | Hard |📖|| +672 | [Bulb Switcher II](https://leetcode.com/problems/bulb-switcher-ii/) | [C++](./C++/bulb-switcher-ii.cpp) [Python](./Python/bulb-switcher-ii.py) | _O(1)_ | _O(1)_ | Medium ||| +728 | [Self Dividing Numbers](https://leetcode.com/problems/self-dividing-numbers/) | [C++](./C++/self-dividing-numbers.cpp) [Python](./Python/self-dividing-numbers.py) | _O(n)_ | _O(1)_ | Medium ||| + +## Sort +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +56| [Merge Intervals](https://leetcode.com/problems/merge-intervals/)| [C++](./C++/merge-intervals.cpp) [Python](./Python/merge-intervals.py) | _O(nlogn)_ | _O(1)_ | Hard || +57| [Insert Interval](https://leetcode.com/problems/insert-interval/)| [C++](./C++/insert-interval.cpp) [Python](./Python/insert-interval.py) | _O(n)_ | _O(1)_ | Hard || +75| [Sort Colors](https://leetcode.com/problems/sort-colors/) | [C++](./C++/sort-colors.cpp) [Python](./Python/sort-colors.py) | _O(n)_ | _O(1)_ | Medium || Tri Partition +88| [Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/)| [C++](./C++/merge-sorted-array.cpp) [Python](./Python/merge-sorted-array.py) | _O(n)_ | _O(1)_ | Easy || +147| [Insertion Sort List](https://leetcode.com/problems/insertion-sort-list/)|[C++](./C++/insertion-sort-list.cpp) [Python](./Python/insertion-sort-list.py) | _O(n^2)_ | _O(1)_ | Medium || +148| [Sort List](https://leetcode.com/problems/sort-list/) | [C++](./C++/sort-list.cpp) [Python](./Python/sort-list.py) | _O(nlogn)_ | _O(logn)_ | Medium || +164| [Maximum Gap](https://leetcode.com/problems/maximum-gap/) | [C++](./C++/maximum-gap.cpp) [Python](./Python/maximum-gap.py)| _O(n)_ | _O(n)_ | Hard || Tricky +179| [Largest Number](https://leetcode.com/problems/largest-number/) | [C++](./C++/largest-number.cpp) [Python](./Python/largest-number.py) | _O(nlogn)_ | _O(1)_ | Medium || +218| [The Skyline Problem](https://leetcode.com/problems/the-skyline-problem/) | [C++](./C++/the-skyline-problem.cpp) [Python](./Python/the-skyline-problem.py) | _O(nlogn)_ | _O(n)_ | Hard || Sort, BST| +252| [Meeting Rooms](https://leetcode.com/problems/meeting-rooms/) | [C++](./C++/meeting-rooms.cpp) [Python](./Python/meeting-rooms.py) | _O(nlogn)_ | _O(n)_ | Easy |📖| | +253| [Meeting Rooms II](https://leetcode.com/problems/meeting-rooms-ii/) | [C++](./C++/meeting-rooms-ii.cpp) [Python](./Python/meeting-rooms-ii.py) | _O(nlogn)_ | _O(n)_ | Medium |📖| | +274| [H-Index](https://leetcode.com/problems/h-index/) | [C++](./C++/h-index.cpp) [Python](./Python/h-index.py) | _O(n)_ | _O(n)_ | Medium || Counting Sort | +280| [Wiggle Sort](https://leetcode.com/problems/wiggle-sort/) | [C++](./C++/wiggle-sort.cpp) [Python](./Python/wiggle-sort.py) | _O(n)_ | _O(1)_ | Medium |📖| | +324| [Wiggle Sort II](https://leetcode.com/problems/wiggle-sort-ii/) | [C++](./C++/wiggle-sort-ii.cpp) [Python](./Python/wiggle-sort-ii.py) | _O(n)_ on average | _O(1)_ | Medium | variant of [Sort Colors](https://leetcode.com/problems/sort-colors/) | Tri Partition | +347| [Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) | [C++](./C++/top-k-frequent-elements.cpp) [Python](./Python/top-k-frequent-elements.py) | _O(n)_ | _O(n)_ | Medium | | Quick Select, Heap, Bucket Sort | +406| [Queue Reconstruction by Height](https://leetcode.com/problems/queue-reconstruction-by-height/) | [C++](./C++/queue-reconstruction-by-height.cpp) [Python](./Python/queue-reconstruction-by-height.py) | _O(n * sqrt(n))_ | _O(n)_ | Medium | | Tricky | +451| [Sort Characters By Frequency](https://leetcode.com/problems/sort-characters-by-frequency/) | [C++](./C++/sort-characters-by-frequency.cpp) [Python](./Python/sort-characters-by-frequency.py) | _O(n)_ | _O(n)_ | Medium | | | +692| [Top K Frequent Words](https://leetcode.com/problems/top-k-frequent-words/) | [C++](./C++/top-k-frequent-words.cpp) [Python](./Python/top-k-frequent-words.py) | _O(n + klogk)_ on average | _O(n)_ | Medium | | Quick Select, Heap, Bucket Sort | + +## Two Pointers +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +19| [Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/)| [C++](./C++/remove-nth-node-from-end-of-list.cpp) [Python](./Python/remove-nth-node-from-end-of-list.py) | _O(n)_ | _O(1)_ | Easy || +86| [Partition List](https://leetcode.com/problems/partition-list/)| [C++](./C++/partition-list.cpp) [Python](./Python/partition-list.py) | _O(n)_ | _O(1)_ | Medium || +141| [Linked List Cycle](https://leetcode.com/problems/linked-list-cycle/)| [C++](./C++/linked-list-cycle.cpp) [Python](./Python/linked-list-cycle.py) | _O(n)_ | _O(1)_ | Easy || +142| [Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/)| [C++](./C++/linked-list-cycle-ii.cpp) [Python](./Python/linked-list-cycle-ii.py) | _O(n)_ | _O(1)_ | Medium || +143| [Reorder List](https://leetcode.com/problems/reorder-list/)| [C++](./C++/reorder-list.cpp) [Python](./Python/reorder-list.py) | _O(n)_ | _O(1)_ | Medium || +167| [Two Sum II - Input array is sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) | [C++](./C++/two-sum-ii-input-array-is-sorted.cpp) [Python](./Python/two-sum-ii-input-array-is-sorted.py) | _O(n)_ | _O(1)_ | Medium | | +259 | [3Sum Smaller](https://leetcode.com/problems/3sum-smaller/) | [C++](./C++/3sum-smaller.cpp) [Python](./Python/3sum-smaller.py) | _O(n^2)_ | _O(1)_ | Medium | 📖, LintCode | +283 | [Move Zeroes](https://leetcode.com/problems/move-zeroes/) | [C++](./C++/move-zeroes.cpp) [Python](./Python/move-zeroes.py) | _O(n)_ | _O(1)_ | Easy | | +287| [Find the Duplicate Number](https://leetcode.com/problems/find-the-duplicate-number/)| [C++](./C++/find-the-duplicate-number.cpp) [Python](./Python/find-the-duplicate-number.py) | _O(n)_ | _O(1)_ | Hard | | Binary Search, Two Pointers | +344| [Reverse String](https://leetcode.com/problems/reverse-string/) | [C++](./C++/reverse-string.cpp) [Python](./Python/reverse-string.py) | _O(n)_ | _O(1)_ | Easy | | +345| [Reverse Vowels of a String](https://leetcode.com/problems/reverse-vowels-of-a-string/) | [C++](./C++/reverse-vowels-of-a-string.cpp) [Python](./Python/reverse-vowels-of-a-string.py) | _O(n)_ | _O(1)_ | Easy | | +349| [Intersection of Two Arrays](https://leetcode.com/problems/intersection-of-two-arrays/) | [C++](./C++/intersection-of-two-arrays.cpp) [Python](./Python/intersection-of-two-arrays.py) | _O(m + n)_ | _O(min(m, n))_ | Easy | EPI | Hash, Binary Search +350| [Intersection of Two Arrays II](https://leetcode.com/problems/intersection-of-two-arrays-ii/) | [C++](./C++/intersection-of-two-arrays-ii.cpp) [Python](./Python/intersection-of-two-arrays-ii.py) | _O(m + n)_ | _O(1)_ | Easy | EPI | Hash, Binary Search +360| [Sort Transformed Array](https://leetcode.com/problems/sort-transformed-array/) | [C++](./C++/sort-transformed-array.cpp) [Python](./Python/sort-transformed-array.py) | _O(n)_ | _O(1)_ | Medium |📖| +457| [Circular Array Loop](https://leetcode.com/problems/circular-array-loop/) | [C++](./C++/circular-array-loop.cpp) [Python](./Python/circular-array-loop.py) | _O(n)_ | _O(1)_ | Medium || +567| [Permutation in String](https://leetcode.com/problems/permutation-in-string/) | [C++](./C++/permutation-in-string.cpp) [Python](./Python/permutation-in-string.py) | _O(n)_ | _O(1)_ | Medium || +611| [Valid Triangle Number](https://leetcode.com/problems/valid-triangle-number/) | [C++](./C++/valid-triangle-number.cpp) [Python](./Python/valid-triangle-number.py) | _O(n^2)_ | _O(1)_ | Medium || + +## Recursion +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +95| [Unique Binary Search Trees II](https://leetcode.com/problems/unique-binary-search-trees-ii/) | [C++](./C++/unique-binary-search-trees-ii.cpp) [Python](./Python/unique-binary-search-trees-ii.py) | _O(4^n / n^(3/2)_ | _O(4^n / n^(3/2)_ | Medium || +98| [Validate Binary Search Tree](https://leetcode.com/problems/validate-binary-search-tree/)|[C++](./C++/validate-binary-search-tree.cpp) [Python](./Python/validate-binary-search-tree.py)| _O(n)_ | _O(1)_ | Medium || +100| [Same Tree](https://leetcode.com/problems/same-tree/) |[C+](./C++/same-tree.cpp) [Python](./Python/same-tree.py) | _O(n)_ | _O(h)_ | Easy || +104| [Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/)| [C++](./C++/maximum-depth-of-binary-tree.cpp) [Python](./Python/maximum-depth-of-binary-tree.py)| _O(n)_ | _O(h)_ | Easy || +105| [Construct Binary Tree from Preorder and Inorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | [C++](./C++/construct-binary-tree-from-preorder-and-inorder-traversal.cpp) [Python](./Python/construct-binary-tree-from-preorder-and-inorder-traversal.py) | _O(n)_ | _O(n)_ | Medium || +106| [Construct Binary Tree from Inorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | [C++](./C++/construct-binary-tree-from-inorder-and-postorder-traversal.cpp) [Python](./Python/construct-binary-tree-from-inorder-and-postorder-traversal.py) | _O(n)_ | _O(n)_ | Medium || +108| [Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/) | [C++](./C++/convert-sorted-array-to-binary-search-tree.cpp) [Python](./Python/convert-sorted-array-to-binary-search-tree.py) | _O(n)_ | _O(logn)_ | Medium || +109| [Convert Sorted List to Binary Search Tree](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/) | [C++](./C++/convert-sorted-list-to-binary-search-tree.cpp) [Python](./Python/convert-sorted-list-to-binary-search-tree.py) | _O(n)_ | _O(logn)_ | Medium || +110| [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) | [Python](./Python/balanced-binary-tree.py) | _O(n)_| _O(h)_ | Easy || +111| [Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/)|[Python](./Python/minimum-depth-of-binary-tree.py)| _O(n)_ | _O(h)_ | Easy || +114| [Flatten Binary Tree to Linked List](https://leetcode.com/problems/flatten-binary-tree-to-linked-list/)|[Python](./Python/flatten-binary-tree-to-linked-list.py)| _O(n)_ | _O(h)_ | Medium || +116| [Populating Next Right Pointers in Each Node](https://leetcode.com/problems/populating-next-right-pointers-in-each-node/)|[Python](./Python/populating-next-right-pointers-in-each-node.py)| _O(n)_ | _O(1)_ | Medium || +124| [Binary Tree Maximum Path Sum](https://leetcode.com/problems/binary-tree-maximum-path-sum/)| [Python](./Python/binary-tree-maximum-path-sum.py) | _O(n)_| _O(h)_| Hard || +129| [Sum Root to Leaf Numbers](https://leetcode.com/problems/sum-root-to-leaf-numbers/) | [Python](./Python/sum-root-to-leaf-numbers.py) | _O(n)_ | _O(h)_ | Medium || +156| [Binary Tree Upside Down](https://leetcode.com/problems/binary-tree-upside-down/) | [Python](./Python/binary-tree-upside-down.py) | _O(n)_ | _O(1)_ | Medium |📖| +241| [Different Ways to Add Parentheses](https://leetcode.com/problems/different-ways-to-add-parentheses/) | [C++](./C++/different-ways-to-add-parentheses.cpp) [Python](./Python/different-ways-to-add-parentheses.py) | _O(n * 4^n / n^(3/2))_ | _O(n * 4^n / n^(3/2))_ | Medium || +298 | [Binary Tree Longest Consecutive Sequence](https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/) | [C++](./C++/binary-tree-longest-consecutive-sequence.cpp) [Python](./Python/binary-tree-longest-consecutive-sequence.py) | _O(n)_ | _O(h)_ | Medium |📖| +327| [Count of Range Sum](https://leetcode.com/problems/count-of-range-sum/) | [C++](./C++/count-of-range-sum.cpp) [Python](./Python/count-of-range-sum.py) | _O(nlogn)_ | _O(n)_ | Hard || +333 | [Largest BST Subtree](https://leetcode.com/problems/largest-bst-subtree/) | [C++](./C++/largest-bst-subtree.cpp) [Python](./Python/largest-bst-subtree.py) | _O(n)_ | _O(h)_ | Medium |📖| +337| [House Robber III](https://leetcode.com/problems/house-robber-iii/) | [C++](./C++/house-robber-iii.cpp) [Python](./Python/house-robber-iii.py) | _O(n)_ | _O(h)_ | Medium || +395| [Longest Substring with At Least K Repeating Characters](https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/) | [C++](./C++/longest-substring-with-at-least-k-repeating-characters.cpp) [Python](./Python/longest-substring-with-at-least-k-repeating-characters.py) | _O(n)_ | _O(1)_ | Medium || +404| [Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves/) | [C++](./C++/sum-of-left-leaves.cpp) [Python](./Python/sum-of-left-leaves.py) | _O(n)_ | _O(h)_ | Easy || +437| [Path Sum III](https://leetcode.com/problems/path-sum-iii/) | [C++](./C++/path-sum-iii.cpp) [Python](./Python/path-sum-iii.py) | _O(n)_ | _O(h)_ | Easy || +549 | [Binary Tree Longest Consecutive Sequence II](https://leetcode.com/problems/binary-tree-longest-consecutive-sequence-ii/) | [C++](./C++/binary-tree-longest-consecutive-sequence-ii.cpp) [Python](./Python/binary-tree-longest-consecutive-sequence-ii.py) | _O(n)_ | _O(h)_ | Medium |📖| +669| [Trim a Binary Search Tree](https://leetcode.com/problems/trim-a-binary-search-tree/) | [C++](./C++/trim-a-binary-search-tree.cpp) [Python](./Python/trim-a-binary-search-tree.py) | _O(n)_ | _O(h)_ | Easy || +671| [Second Minimum Node In a Binary Tree](https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/) | [C++](./C++/second-minimum-node-in-a-binary-tree.cpp) [Python](./Python/second-minimum-node-in-a-binary-tree.py) | _O(n)_ | _O(h)_ | Easy || + +## Binary Search +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +4| [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) | [C++](./C++/median-of-two-sorted-arrays.cpp) [Python](./Python/median-of-two-sorted-arrays.py) | _O(log(min(m, n)))_ | _O(1)_ | Hard || +33| [Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array/) | [C++](./C++/search-in-rotated-sorted-array.cpp) [Python](./Python/search-in-rotated-sorted-array.py) | _O(logn)_ | _O(1)_ | Hard || +34| [Search for a Range](https://leetcode.com/problems/search-for-a-range/) | [C++](./C++/search-for-a-range.cpp) [Python](./Python/search-for-a-range.py) | _O(logn)_ | _O(1)_ | Medium || +35| [Search Insert Position](https://leetcode.com/problems/search-insert-position/) | [C++](./C++/search-insert-position.cpp) [Python](./Python/search-insert-position.py) | _O(logn)_ | _O(1)_ | Medium || +69| [Sqrt(x)](https://leetcode.com/problems/sqrtx/) | [C++](./C++/sqrtx.cpp) [Python](./Python/sqrtx.py) | _O(logn)_ | _O(1)_ | Medium || +74| [Search a 2D Matrix](https://leetcode.com/problems/search-a-2d-matrix/) | [C++](./C++/search-a-2d-matrix.cpp) [Python](./Python/search-a-2d-matrix.py) | _O(logm + logn)_ | _O(1)_ | Medium || +81| [Search in Rotated Sorted Array II](https://leetcode.com/problems/search-in-rotated-sorted-array-ii/) | [C++](./C++/search-in-rotated-sorted-array-ii.cpp) [Python](./Python/search-in-rotated-sorted-array-ii.py) | _O(logn)_ | _O(1)_ | Medium || +153| [Find Minimum in Rotated Sorted Array](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/) | [C++](./C++/find-minimum-in-rotated-sorted-array.cpp) [Python](./Python/find-minimum-in-rotated-sorted-array.py) | _O(logn)_ | _O(1)_ | Medium || +154| [Find Minimum in Rotated Sorted Array II](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/) | [C++](./C++/find-minimum-in-rotated-sorted-array-ii.cpp) [Python](./Python/find-minimum-in-rotated-sorted-array-ii.py) | _O(logn)_ ~ _O(n)_ | _O(1)_ | Hard || +162| [Find Peak Element](https://leetcode.com/problems/find-peak-element/) | [C++](./C++/find-peak-element.cpp) [Python](./Python/find-peak-element.py) | _O(logn)_ | _O(1)_ | Medium || +222| [Count Complete Tree Nodes](https://leetcode.com/problems/count-complete-tree-nodes/) | [C++](./C++/count-complete-tree-nodes.cpp) [Python](./Python/count-complete-tree-nodes.py) | _O((logn)^2)_ | _O(1)_ | Medium || +275| [H-Index II](https://leetcode.com/problems/h-index-ii/) | [C++](./C++/h-index-ii.cpp) [Python](./Python/h-index-ii.py) | _O(logn)_ | _O(1)_ | Medium || Binary Search | +278| [First Bad Version](https://leetcode.com/problems/first-bad-version/) | [C++](./C++/first-bad-version.cpp) [Python](./Python/first-bad-version.py) | _O(logn)_ | _O(1)_ | Easy | LintCode || +300| [Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) | [C++](./C++/longest-increasing-subsequence.cpp) [Python](./Python/longest-increasing-subsequence.py) | _O(nlogn)_ | _O(n)_ | Medium | CTCI, LintCode | Binary Search, DP| +302| [Smallest Rectangle Enclosing Black Pixels](https://leetcode.com/problems/smallest-rectangle-enclosing-black-pixels/)| [C++](./C++/smallest-rectangle-enclosing-black-pixels.cpp) [Python](./Python/smallest-rectangle-enclosing-black-pixels.py) | _O(nlogn)_ | _O(1)_ | Hard | 📖 | +354| [Russian Doll Envelopes](https://leetcode.com/problems/russian-doll-envelopes/) | [C++](./C++/russian-doll-envelopes.cpp) [Python](./Python/russian-doll-envelopes.py) | _O(nlogn)_ | _O(1)_ | Hard ||| +363| [Max Sum of Rectangle No Larger Than K](https://leetcode.com/problems/max-sum-of-sub-matrix-no-larger-than-k/) | [C++](./C++/max-sum-of-sub-matrix-no-larger-than-k.cpp) [Python](./Python/max-sum-of-sub-matrix-no-larger-than-k.py) | _O(min(m, n)^2 * max(m, n) * logn(max(m, n)))_ | _O(max(m, n))_ | Hard ||| +367| [Valid Perfect Square](https://leetcode.com/problems/valid-perfect-square/)| [C++](./C++/valid-perfect-square.cpp) [Python](./Python/valid-perfect-square.py) | _O(logn)_ | _O(1)_ | Medium | | +374| [Guess Number Higher or Lower](https://leetcode.com/problems/guess-number-higher-or-lower/)| [C++](./C++/guess-number-higher-or-lower.cpp) [Python](./Python/guess-number-higher-or-lower.py) | _O(logn)_ | _O(1)_ | Easy | | +410| [Split Array Largest Sum](https://leetcode.com/problems/split-array-largest-sum/)| [C++](./C++/split-array-largest-sum.cpp) [Python](./Python/split-array-largest-sum.py) | _O(nlogs)_ | _O(1)_ | Hard | | +436 | [Find Right Interval](https://leetcode.com/problems/find-right-interval/) | [C++](./C++/find-right-interval.cpp) [Python](./Python/find-right-interval.py) | _O(nlogn)_ | _O(n)_ | Medium | | +475 | [Heaters](https://leetcode.com/problems/heaters/) | [C++](./C++/heaters.cpp) [Python](./Python/heaters.py) | _O((m + n) * logn)_ | _O(1)_ | Easy | | +658 | [Find K Closest Elements](https://leetcode.com/problems/find-k-closest-elements/) | [C++](./C++/find-k-closest-elements.cpp) [Python](./Python/find-k-closest-elements.py) | _O(logn + k)_ | _O(1)_ | Medium | | +668 | [Kth Smallest Number in Multiplication Table](https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/) | [C++](./C++/kth-smallest-number-in-multiplication-table.cpp) [Python](./Python/kth-smallest-number-in-multiplication-table.py) | _O(m * log(m * n))_ | _O(1)_ | Hard | | +719 | [Find K-th Smallest Pair Distance](https://leetcode.com/problems/find-k-th-smallest-pair-distance/) | [C++](./C++/find-k-th-smallest-pair-distance.cpp) [Python](./Python/find-k-th-smallest-pair-distance.py) | _O(nlogn + nlogw)_ | _O(1)_ | Hard | | +744 | [Find Smallest Letter Greater Than Target](https://leetcode.com/problems/find-smallest-letter-greater-than-target/) | [C++](./C++/find-smallest-letter-greater-than-target.cpp) [Python](./Python/find-smallest-letter-greater-than-target.py) | _O(logn)_ | _O(1)_ | Easy | | + +## Binary Search Tree +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +220| [Contains Duplicate III](https://leetcode.com/problems/contains-duplicate-iii/) | [C++](./C++/contains-duplicate-iii.cpp) [Python](./Python/contains-duplicate-iii.py) | _O(nlogk)_ | _O(k)_ | Medium || +230 | [Kth Smallest Element in a BST](https://leetcode.com/problems/kth-smallest-element-in-a-bst/) | [C++](./C++/kth-smallest-element-in-a-bst.cpp) [Python](./Python/kth-smallest-element-in-a-bst.py) | _O(max(h, k))_ | _O(min(h, k))_ | Medium || +235 | [Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) | [C++](./C++/lowest-common-ancestor-of-a-binary-search-tree.cpp) [Python](./Python/lowest-common-ancestor-of-a-binary-search-tree.py) | _O(h)_ | _O(1)_ | Easy | EPI | +270| [Closest Binary Search Tree Value](https://leetcode.com/problems/closest-binary-search-tree-value/)| [C++](./C++/closest-binary-search-tree-value.cpp) [Python](./Python/closest-binary-search-tree-value.py) | _O(h)_ | _O(1)_ | Easy | 📖 | +285| [Inorder Successor in BST](https://leetcode.com/problems/inorder-successor-in-bst/)| [C++](./C++/inorder-successor-in-bst.cpp) [Python](./Python/inorder-successor-in-bst.py) | _O(h)_ | _O(1)_ | Medium | 📖 | +352 | [Data Stream as Disjoint Intervals](https://leetcode.com/problems/data-stream-as-disjoint-intervals/) | [C++](./C++/data-stream-as-disjoint-intervals.cpp) [Python](./Python/data-stream-as-disjoint-intervals.py) | _O(logn)_ | _O(n)_ | Hard | | +449|[Serialize and Deserialize BST](https://leetcode.com/problems/serialize-and-deserialize-bst/)| [C++](./C++/serialize-and-deserialize-bst.cpp) [Python](./Python/serialize-and-deserialize-bst.py)| _O(n)_ | _O(h)_ | Medium | | | +450|[Delete Node in a BST](https://leetcode.com/problems/delete-node-in-a-bst/)| [C++](./C++/delete-node-in-a-bst.cpp) [Python](./Python/delete-node-in-a-bst.py)| _O(h)_ | _O(h)_ | Medium | | | + +## Breadth-First Search +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +102| [Binary Tree Level Order Traversal](https://leetcode.com/problems/binary-tree-level-order-traversal/)| [C++](./C++/binary-tree-level-order-traversal.cpp) [Python](./Python/binary-tree-level-order-traversal.py)| _O(n)_| _O(n)_| Easy || +107| [Binary Tree Level Order Traversal II](https://leetcode.com/problems/binary-tree-level-order-traversal-ii/)| [Python](./Python/binary-tree-level-order-traversal-ii.py) | _O(n)_| _O(n)_| Easy || +103| [Binary Tree Zigzag Level Order Traversal](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/)| [Python](./Python/binary-tree-zigzag-level-order-traversal.py) | _O(n)_| _O(n)_| Medium || +117| [Populating Next Right Pointers in Each Node II](https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/)|[Python](./Python/populating-next-right-pointers-in-each-node-ii.py)| _O(n)_ | _O(1)_ | Hard || +127| [Word Ladder](https://leetcode.com/problems/word-ladder/)|[Python](./Python/word-ladder.py) | _O(n * d)_ | _O(d)_ | Medium || +130| [Surrounded Regions](https://leetcode.com/problems/surrounded-regions/)|[C++](./C++/surrounded-regions.cpp) [Python](./Python/surrounded-regions.py)| _O(m * n)_ | _O(m + n)_ | Medium || +133| [Clone Graph](https://leetcode.com/problems/clone-graph/)| [Python](./Python/clone-graph.py) | _O(n)_ | _O(n)_ | Medium || +207| [Course Schedule](https://leetcode.com/problems/course-schedule/)| [Python](./Python/course-schedule.py) | _O(\|V\| + \|E\|)_ | _O(\|E\|)_ | Medium || Topological Sort | +210| [Course Schedule II](https://leetcode.com/problems/course-schedule-ii/)| [Python](./Python/course-schedule-ii.py) | _O(\|V\| + \|E\|)_ | _O(\|E\|)_ | Medium || Topological Sort | +261| [Graph Valid Tree](https://leetcode.com/problems/graph-valid-tree/)| [C++](./C++/graph-valid-tree.cpp) [Python](./Python/graph-valid-tree.py) | _O(\|V\| + \|E\|)_ | _O(\|V\| + \|E\|)_ | Medium | 📖 | +269| [Alien Dictionary](https://leetcode.com/problems/alien-dictionary/) | [C++](./C++/alien-dictionary.cpp) [Python](./Python/alien-dictionary.py) | _O(n)_ | _O(1)_ | Hard |📖| Topological Sort, BFS, DFS | +286| [Walls and Gates](https://leetcode.com/problems/walls-and-gates/)| [C++](./C++/walls-and-gates.cpp) [Python](./Python/walls-and-gates.py) | _O(m * n)_ | _O(g)_ | Medium | 📖 | +310| [Minimum Height Trees](https://leetcode.com/problems/minimum-height-trees/)| [C++](./C++/minimum-height-trees.cpp) [Python](./Python/minimum-height-trees.py) | _O(n)_ | _O(n)_ | Medium || +317| [Shortest Distance from All Buildings](https://leetcode.com/problems/shortest-distance-from-all-buildings/)| [C++](./C++/shortest-distance-from-all-buildings.cpp) [Python](./Python/shortest-distance-from-all-buildings.py) | _O(k * m * n)_ | _O(m * n)_ | Hard | 📖 | +433| [Minimum Genetic Mutation](https://leetcode.com/problems/minimum-genetic-mutation/)| [C++](./C++/minimum-genetic-mutation.cpp) [Python](./Python/minimum-genetic-mutation.py) | _O(n * b)_ | _O(b)_ | Medium || +444| [Sequence Reconstruction](https://leetcode.com/problems/sequence-reconstruction/)| [C++](./C++/sequence-reconstruction.cpp) [Python](./Python/sequence-reconstruction.py) | _O(n * s)_ | _O(n)_ | Medium |📖| Topological Sort | +666| [Path Sum IV](https://leetcode.com/problems/path-sum-iv/)| [C++](./C++/path-sum-iv.cpp) [Python](./Python/path-sum-iv.py) | _O(n)_ | _O(w)_ | Medium |📖| Topological Sort | +675|[Cut Off Trees for Golf Event](https://leetcode.com/problems/cut-off-trees-for-golf-event/)| [C++](./C++/cut-off-trees-for-golf-event.cpp) [Python](./Python/cut-off-trees-for-golf-event.py)| _O(t * m * n)_ | _O(m * n)_ | Hard | | `A* Search Algorithm` | +742|[Closest Leaf in a Binary Tree](https://leetcode.com/problems/closest-leaf-in-a-binary-tree/)| [C++](./C++/closest-leaf-in-a-binary-tree.cpp) [Python](./Python/closest-leaf-in-a-binary-tree.py)| _O(n)_ | _O(n)_ | Medium | | | +743|[Network Delay Time](https://leetcode.com/problems/network-delay-time/)| [C++](./C++/network-delay-time.cpp) [Python](./Python/network-delay-time.py)| _O(\|E\| + \|V\|log\|V\|)_ | _O(\|E\| + \|V\|)_ | Medium | | `Dijkstra's algorithm` | + +## Depth-First Search +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +112| [Path Sum](https://leetcode.com/problems/path-sum/) | [Python](./Python/path-sum.py) | _O(n)_ | _O(h)_ | Easy || +113| [Path Sum II](https://leetcode.com/problems/path-sum-ii/) | [Python](./Python/path-sum-ii.py) | _O(n)_ | _O(h)_ | Medium || +199| [Binary Tree Right Side View](https://leetcode.com/problems/binary-tree-right-side-view/) | [Python](./Python/binary-tree-right-side-view.py) | _O(n)_ | _O(h)_ | Medium || +200| [Number of Islands](https://leetcode.com/problems/number-of-islands/) | [Python](./Python/number-of-islands.py) | _O(m * n)_ | _O(m * n)_| Medium || +236 | [Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) | [C++](./C++/lowest-common-ancestor-of-a-binary-tree.cpp) [Python](./Python/lowest-common-ancestor-of-a-binary-tree.py) | _O(n)_ | _O(h)_ | Medium | EPI | +247| [Strobogrammatic Number II](https://leetcode.com/problems/strobogrammatic-number-ii/) | [C++](./C++/strobogrammatic-number-ii.cpp) [Python](./Python/strobogrammatic-number-ii.py) | _O(n^2 * 5^(n/2))_ | _O(n)_ | Medium |📖|| +250| [Count Univalue Subtrees](https://leetcode.com/problems/count-univalue-subtrees) | [C++](./C++/count-univalue-subtrees.cpp) [Python](./Python/count-univalue-subtrees.py) | _O(n)_ | _O(h)_ | Medium |📖|| +257| [Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/) | [C++](./C++/binary-tree-paths.cpp) [Python](./Python/binary-tree-paths.py) | _O(n * h)_ | _O(h)_ | Easy ||| +282| [Expression Add Operators](https://leetcode.com/problems/expression-add-operators/) | [C++](./C++/expression-add-operators.cpp) [Python](./Python/expression-add-operators.py) | _O(4^n)_ | _O(n)_ | Hard ||| +301| [Remove Invalid Parentheses](https://leetcode.com/problems/remove-invalid-parentheses/) | [C++](./C++/remove-invalid-parentheses.cpp) [Python](./Python/remove-invalid-parentheses.py) | _O(C(n, c))_ | _O(c)_ | Hard ||| +329| [Longest Increasing Path in a Matrix](https://leetcode.com/problems/longest-increasing-path-in-a-matrix/) | [C++](./C++/longest-increasing-path-in-a-matrix.cpp) [Python](./Python/longest-increasing-path-in-a-matrix.py) | _O(m * n)_ | _O(m * n)_ | Hard ||| +332| [Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/) | [C++](./C++/reconstruct-itinerary.cpp) [Python](./Python/reconstruct-itinerary.py) | _O(t! / (n1! * n2! * ... nk!))_ | _O(t)_ | Medium ||| +339| [Nested List Weight Sum](https://leetcode.com/problems/nested-list-weight-sum/) | [C++](./C++/nested-list-weight-sum.cpp) [Python](./Python/nested-list-weight-sum.py) | _O(n)_ | _O(h)_ | Easy |📖|| +364| [Nested List Weight Sum II](https://leetcode.com/problems/nested-list-weight-sum-ii/) | [C++](./C++/nested-list-weight-sum-ii.cpp) [Python](./Python/nested-list-weight-sum-ii.py) | _O(n)_ | _O(h)_ | Medium |📖|| +366| [Find Leaves of Binary Tree](https://leetcode.com/problems/find-leaves-of-binary-tree/) | [C++](./C++/find-leaves-of-binary-tree.cpp) [Python](./Python/find-leaves-of-binary-tree.py) | _O(n)_ | _O(h)_ | Medium |📖|| +399| [Evaluate Division](https://leetcode.com/problems/evaluate-division/) | [C++](./C++/evaluate-division.cpp) [Python](./Python/evaluate-division.py) | _O(q * \|V\|!)_ | _O(e)_ | Medium ||| +417 | [Pacific Atlantic Water Flow](https://leetcode.com/problems/pacific-atlantic-water-flow/) | [C++](./C++/pacific-atlantic-water-flow.cpp) [Python](./Python/pacific-atlantic-water-flow.py) | _O(m * n)_ | _O(m * n)_ | Medium || +440| [K-th Smallest in Lexicographical Order](https://leetcode.com/problems/k-th-smallest-in-lexicographical-order/) | [C++](./C++/k-th-smallest-in-lexicographical-order.cpp) [Python](./Python/k-th-smallest-in-lexicographical-order.py) | _O(logn)_ | _O(logn)_ | Hard || +464| [Can I Win](https://leetcode.com/problems/can-i-win/) | [C++](./C++/can-i-win.cpp) [Python](./Python/can-i-win.py) | _O(n!)_ | _O(n)_ | Medium || +547| [Friend Circles](https://leetcode.com/problems/friend-circles/) | [C++](./C++/friend-circles.cpp) [Python](./Python/friend-circles.py) | _O(n^2)_ | _O(n)_ | Medium || Union Find | +582| [Kill Process](https://leetcode.com/problems/kill-process/) | [C++](./C++/kill-process.cpp) [Python](./Python/kill-process.py) | _O(n)_ | _O(n)_ | Medium |📖| DFS, BFS | +638| [Shopping Offers](https://leetcode.com/problems/shopping-offers/) | [C++](./C++/shopping-offers.cpp) [Python](./Python/shopping-offers.py) | _O(n * 2^n)_ | _O(n)_ | Medium || +690| [Employee Importance](https://leetcode.com/problems/employee-importance/) | [C++](./C++/employee-importance.cpp) [Python](./Python/employee-importance.py) | _O(n)_ | _O(h)_ | Easy || DFS, BFS +694| [Number of Distinct Islands](https://leetcode.com/problems/number-of-distinct-islands/) | [C++](./C++/number-of-distinct-islands.cpp) [Python](./Python/number-of-distinct-islands.py) | _O(m * n)_ | _O(m * n)_ | Medium |📖|| +695| [Max Area of Island](https://leetcode.com/problems/max-area-of-island/) | [C++](./C++/max-area-of-island.cpp) [Python](./Python/max-area-of-island.py) | _O(m * n)_ | _O(m * n)_ | Easy || +711| [Number of Distinct Islands II](https://leetcode.com/problems/number-of-distinct-islands-ii/) | [C++](./C++/number-of-distinct-islands-ii.cpp) [Python](./Python/number-of-distinct-islands-ii.py) | _O((m * n) * log(m * n))_ | _O(m * n)_ | Hard |📖| Hash | +733| [Max Area of Island](https://leetcode.com/problems/flood-fill/) | [C++](./C++/flood-fill.cpp) [Python](./Python/flood-fill.py) | _O(m * n)_ | _O(m * n)_ | Easy || +749| [Contain Virus](https://leetcode.com/problems/contain-virus/) | [C++](./C++/contain-virus.cpp) [Python](./Python/contain-virus.py) | _O((m * n)^(4/3))_ | _O(m * n)_ | Hard || Simulation| + +## Backtracking +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +17| [Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number/)| [Python](./Python/letter-combinations-of-a-phone-number.py) | _O(n * 4^n)_ | _O(n)_ | Medium || +22| [Generate Parentheses](https://leetcode.com/problems/generate-parentheses/)| [Python](./Python/generate-parentheses.py)| _O(4^n / n^(3/2))_ | _O(n)_ | Medium || +37| [Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) | [Python](./Python/sudoku-solver.py) | _O((9!)^9)_ | _O(1)_ | Hard || +39| [Combination Sum](https://leetcode.com/problems/combination-sum/)| [Python](./Python/combination-sum.py) | _O(k * n^k)_ | _O(k)_ | Medium || +40| [Combination Sum II](https://leetcode.com/problems/combination-sum-ii/)| [Python](./Python/combination-sum-ii.py)| _O(k * C(n, k))_| _O(k)_ | Medium || +46| [Permutations](https://leetcode.com/problems/permutations/)| [Python](./Python/permutations.py) | _O(n * n!)_ | _O(n)_ | Medium || +47| [Permutations II](https://leetcode.com/problems/permutations-ii/)| [Python](./Python/permutations-ii.py) | _O(n * n!)_ | _O(n)_ | Medium || +51| [N-Queens](https://leetcode.com/problems/n-queens/) | [Python](./Python/n-queens.py) | _O(n!)_ | _O(n)_ | Hard || +52| [N-Queens-II](https://leetcode.com/problems/n-queens-ii/) | [Python](./Python/n-queens-ii.py) | _O(n!)_ | _O(n)_ | Hard || +77| [Combinations](https://leetcode.com/problems/combinations/) | [Python](./Python/combinations.py) | _O(n!)_ | _O(n)_ | Medium || +79| [Word Search](https://leetcode.com/problems/word-search/) | [Python](./Python/word-search.py) | _O(m * n * l)_ | _O(l)_ | Medium || +93| [Restore IP Addresses](https://leetcode.com/problems/restore-ip-addresses/) | [Python](./Python/restore-ip-addresses.py) | _O(1)_ | _O(1)_ | Medium || +78| [Subsets](https://leetcode.com/problems/subsets/) | [C++](./C++/subsets.cpp) [Python](./Python/subsets.py) | _O(n * 2^n)_ | _O(1)_ | Medium || +90| [Subsets II](https://leetcode.com/problems/subsets-ii/) | [C++](./C++/subsets-ii.cpp) [Python](./Python/subsets-ii.py) | _O(n * 2^n)_ | _O(1)_ | Medium || +126| [Word Ladder II](https://leetcode.com/problems/word-ladder-ii/) |[Python](./Python/word-ladder-ii.py) | _O(n * d)_ | _O(d)_ | Hard || +131| [Palindrome Partitioning](https://leetcode.com/problems/palindrome-partitioning/) | [Python](./Python/palindrome-partitioning.py) | _O(n^2)_ ~ _O(2^n)_ | _O(n^2)_ | Medium || +140| [Word Break II](https://leetcode.com/problems/word-break-ii/) | [C++](./C++/word-break-ii.cpp) [Python](./Python/word-break-ii.py) | _O(n * l^2 + n * r)_ | _O(n^2)_ | Hard || +212| [Word Search II](https://leetcode.com/problems/word-search-ii/) | [C++](./C++/word-search-ii.cpp) [Python](./Python/word-search-ii.py) | _O(m * n * l)_ | _O(l)_ | Hard | LintCode | Trie, DFS +216| [Combination Sum III](https://leetcode.com/problems/combination-sum-iii/)| [C++](./C++/combination-sum-iii.cpp) [Python](./Python/combination-sum-iii.py) | _O(k * C(n, k))_ | _O(k)_ | Medium || +254| [Factor Combinations](https://leetcode.com/problems/factor-combinations/) | [C++](./C++/factor-combinations.cpp) [Python](./Python/factor-combinations.py) | _O(nlogn)_ | _O(logn)_ | Medium |📖|| +267| [Palindrome Permutation II](https://leetcode.com/problems/palindrome-permutation-ii/) | [C++](./C++/palindrome-permutation-ii.cpp) [Python](./Python/palindrome-permutation-ii.py) | _O(n * n!)_ | _O(n)_ | Medium |📖|| +291| [Word Pattern II](https://leetcode.com/problems/word-pattern-ii/) | [C++](./C++/word-pattern-ii.cpp) [Python](./Python/word-pattern-ii.py) | _O(n * C(n - 1, c - 1))_ | _O(n + c)_ | Hard |📖|| +294| [Flip Game II](https://leetcode.com/problems/flip-game-ii/) | [C++](./C++/flip-game-ii.cpp) [Python](./Python/flip-game-ii.py) | _O(n + c^2)_ | _O(c)_ | Medium |📖| DP, Hash | +320| [Generalized Abbreviation](https://leetcode.com/problems/generalized-abbreviation/) | [C++](./C++/generalized-abbreviation.cpp) [Python](./Python/generalized-abbreviation.py) | _O(n * 2^n)_ | _O(n)_ | Medium |📖|| +425| [Word Squares](https://leetcode.com/problems/word-squares/) | [C++](./C++/word-squares.cpp) [Python](./Python/word-squares.py) | _O(n^2 * n!)_ | _O(n^2)_ | Hard |📖|| +676| [Implement Magic Dictionary](https://leetcode.com/problems/implement-magic-dictionary/) | [C++](./C++/implement-magic-dictionary.cpp) [Python](./Python/implement-magic-dictionary.py) | _O(n)_ | _O(d)_ | Medium || Trie, DFS +679| [24 Game](https://leetcode.com/problems/24-game/) | [C++](./C++/24-game.cpp) [Python](./Python/24-game.py) | _O(1)_ | _O(1)_ | Hard || DFS +698| [Partition to K Equal Sum Subsets](https://leetcode.com/problems/partition-to-k-equal-sum-subsets/) | [C++](./C++/partition-to-k-equal-sum-subsets.cpp) [Python](./Python/partition-to-k-equal-sum-subsets.py) | _O(n * 2^n)_ | _O(2^n)_ | Medium || DFS, DP, Memoization +718 | [Maximum Length of Repeated Subarray](https://leetcode.com/problems/maximum-length-of-repeated-subarray/) | [C++](./C++/maximum-length-of-repeated-subarray.cpp) [Python](./Python/maximum-length-of-repeated-subarray.py) | _O(m * n)_ | _O(min(m, n))_ | Medium || DP, Hash, Binary Search + +## Dynamic Programming +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +10| [Regular Expression Matching](https://leetcode.com/problems/regular-expression-matching/) | [Python](./Python/regular-expression-matching.py) | _O(m * n)_ | _O(n)_ | Hard || +53| [Maximum Subarray](https://leetcode.com/problems/maximum-subarray/)|[Python](./Python/maximum-subarray.py)| _O(n)_ | _O(1)_ | Medium || +62| [Unique Paths](https://leetcode.com/problems/unique-paths/) | [Python](./Python/unique-paths.py)| _O(m * n)_ | _O(m + n)_ | Medium || +63| [Unique Paths II](https://leetcode.com/problems/unique-paths-ii/) | [Python](./Python/unique-paths-ii.py) | _O(m * n)_ | _O(m + n)_ | Medium || +64| [Minimum Path Sum](https://leetcode.com/problems/minimum-path-sum/)| [Python](./Python/minimum-path-sum.py)| _O(m * n)_ | _O(m + n)_ | Medium || +70| [Climbing Stairs](https://leetcode.com/problems/climbing-stairs/)| [Python](./Python/climbing-stairs.py) | _O(n)_ | _O(1)_ | Easy || +72| [Edit Distance](https://leetcode.com/problems/edit-distance/)|[Python](./Python/edit-distance.py)| _O(m * n)_ | _O(m + n)_ | Hard || +87| [Scramble String](https://leetcode.com/problems/scramble-string/) | [Python](./Python/scramble-string.py) | _O(n^4)_ | _O(n^3)_ | Hard || +91| [Decode Ways](https://leetcode.com/problems/decode-ways/) | [C++](./Python/decode-ways.cpp) [Python](./Python/decode-ways.py)| _O(n)_ | _O(1)_ | Medium || +96| [Unique Binary Search Trees](https://leetcode.com/problems/unique-binary-search-trees/) | [Python](./Python/unique-binary-search-trees.py) | _O(n)_ | _O(1)_ | Medium || Math +97| [Interleaving String](https://leetcode.com/problems/interleaving-string/)|[Python](./Python/interleaving-string.py)| _O(m * n)_ | _O(m + n)_ | Hard || +115| [Distinct Subsequences](https://leetcode.com/problems/distinct-subsequences/)|[Python](./Python/distinct-subsequences.py)| _O(n^2)_ | _O(n)_ | Hard || +120| [Triangle](https://leetcode.com/problems/triangle/) | [Python](./Python/triangle.py) | _O(m * n)_ | _O(n)_ | Medium || +123| [Best Time to Buy and Sell Stock III](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) | [Python](./Python/best-time-to-buy-and-sell-stock-iii.py) | _O(n)_ | _O(1)_ | Hard || +132| [Palindrome Partitioning II](https://leetcode.com/problems/palindrome-partitioning-ii/) | [Python](./Python/palindrome-partitioning-ii.py) | _O(n^2)_ | _O(n^2)_ | Hard || +139| [Word Break](https://leetcode.com/problems/word-break/) | [C++](./C++/word-break.cpp) [Python](./Python/word-break.py) | _O(n * l^2)_ | _O(n)_ | Medium || +152| [Maximum Product Subarray](https://leetcode.com/problems/maximum-product-subarray/)|[Python](./Python/maximum-product-subarray.py)| _O(n)_ | _O(1)_ | Medium || +174| [Dungeon Game](https://leetcode.com/problems/dungeon-game/) | [Python](./Python/dungeon-game.py)| _O(m * n)_ | _O(m + n)_ | Hard || +188| [Best Time to Buy and Sell Stock IV](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/)| [Python](./Python/best-time-to-buy-and-sell-stock-iv.py) | _O(k * n)_ | _O(k)_ | Hard || +198| [House Robber](https://leetcode.com/problems/house-robber/)| [Python](./Python/house-robber.py) | _O(n)_ | _O(1)_ | Easy || +213| [House Robber II](https://leetcode.com/problems/house-robber-ii/)| [C++](./C++/house-robber-ii.cpp) [Python](./Python/house-robber-ii.py) | _O(n)_ | _O(1)_ | Medium || +221| [Maximal Square](https://leetcode.com/problems/maximal-square/)| [C++](./C++/maximal-square.cpp) [Python](./Python/maximal-square.py) | _O(n^2)_ | _O(n)_ | Medium | EPI | +256| [Paint House](https://leetcode.com/problems/paint-house/) | [C++](./C++/paint-house.cpp) [Python](./Python/paint-house.py) | _O(n)_| _O(1)_| Medium |📖|| +265| [Paint House II](https://leetcode.com/problems/paint-house-ii/) | [C++](./C++/paint-house-ii.cpp) [Python](./Python/paint-house-ii.py) | _O(n * k)_| _O(k)_| Hard |📖|| +276| [Paint Fence](https://leetcode.com/problems/paint-fence/) | [C++](./C++/paint-fence.cpp) [Python](./Python/paint-fence.py) | _O(n)_| _O(1)_| Easy |📖|| +279| [Perfect Squares](https://leetcode.com/problems/perfect-squares/)| [C++](./C++/perfect-squares.cpp) [Python](./Python/perfect-squares.py) | _O(n * sqrt(n))_ | _O(n)_ | Medium || Hash | +303| [Range Sum Query - Immutable](https://leetcode.com/problems/range-sum-query-immutable/)| [C++](./C++/range-sum-query-immutable.cpp) [Python](./Python/range-sum-query-immutable.py) | ctor: _O(n)_, lookup: _O(1)_ | _O(n)_ | Easy || +304| [Range Sum Query 2D - Immutable](https://leetcode.com/problems/range-sum-query-2d-immutable/)| [C++](./C++/range-sum-query-2d-immutable.cpp) [Python](./Python/range-sum-query-2d-immutable.py) | ctor: _O(m * n)_, lookup: _O(1)_ | _O(m * n)_ | Medium || +309| [Best Time to Buy and Sell Stock with Cooldown](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) | [C++](./C++/best-time-to-buy-and-sell-stock-with-cooldown.cpp) [Python](./Python/best-time-to-buy-and-sell-stock-with-cooldown.py) | _O(n)_ | _O(1)_ | Medium || +312| [Burst Balloons](https://leetcode.com/problems/burst-balloons/) | [C++](./C++/burst-balloons.cpp) [Python](./Python/burst-balloons.py) | _O(n^3)_ | _O(n^2)_ | Hard || +322| [Coin Change](https://leetcode.com/problems/coin-change/) | [C++](./C++/coin-change.cpp) [Python](./Python/coin-change.py) | _O(n * k)_ | _O(k)_ | Medium || +351| [Android Unlock Patterns](https://leetcode.com/problems/android-unlock-patterns/) | [C++](./C++/android-unlock-patterns.cpp) [Python](./Python/android-unlock-patterns.py) | _O(9^2 * 2^9)_ | _O(9 * 2^9)_ | Medium | 📖 | Backtracking | +357| [Count Numbers with Unique Digits](https://leetcode.com/problems/count-numbers-with-unique-digits/) | [C++](./C++/count-numbers-with-unique-digits.cpp) [Python](./Python/count-numbers-with-unique-digits.py) | _O(n)_ | _O(1)_ | Medium || Backtracking, Math | +361| [Bomb Enemy](https://leetcode.com/problems/bomb-enemy/) | [C++](./C++/bomb-enemy.cpp) [Python](./Python/bomb-enemy.py) | _O(m * n)_ | _O(m * n)_ | Medium | 📖 | | +368| [Largest Divisible Subset](https://leetcode.com/problems/largest-divisible-subset/) | [C++](./C++/largest-divisible-subset.cpp) [Python](./Python/largest-divisible-subset.py) | _O(n^2)_ | _O(n)_ | Medium | | | +375| [Guess Number Higher or Lower II](https://leetcode.com/problems/guess-number-higher-or-lower-ii/)| [C++](./C++/guess-number-higher-or-lower-ii.cpp) [Python](./Python/guess-number-higher-or-lower-ii.py) | _O(n^2)_ | _O(n^2)_ | Medium | | +377| [Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/)| [C++](./C++/combination-sum-iv.cpp) [Python](./Python/combination-sum-iv.py) | _O(nlogn + n * t)_ | _O(t)_ | Medium | | +403 | [Frog Jump](https://leetcode.com/problems/frog-jump/) | [C++](./C++/frog-jump.cpp) [Python](./Python/frog-jump.py) | _O(n)_ | _O(n) ~ O(n^2)_ | Hard || +416 | [Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum/) | [C++](./C++/partition-equal-subset-sum.cpp) [Python](./Python/partition-equal-subset-sum.py) | _O(n * s)_ | _O(s)_ | Medium || +418 | [Sentence Screen Fitting](https://leetcode.com/problems/sentence-screen-fitting/) | [C++](./C++/sentence-screen-fitting.cpp) [Python](./Python/sentence-screen-fitting.py) | _O(r + n * c)_ | _O(n)_ | Medium |📖| +446 | [Arithmetic Slices II - Subsequence](https://leetcode.com/problems/arithmetic-slices-ii-subsequence/) | [C++](./C++/arithmetic-slices-ii-subsequence.cpp) [Python](./Python/arithmetic-slices-ii-subsequence.py) | _O(n^2)_ | _O(n * d)_ | Hard || +465 | [Optimal Account Balancing](https://leetcode.com/problems/optimal-account-balancing/) | [C++](./C++/optimal-account-balancing.cpp) [Python](./Python/optimal-account-balancing.py) | _O(n * 2^n)_ | _O(n * 2^n)_ | Hard |📖| +466 | [Count The Repetitions](https://leetcode.com/problems/count-the-repetitions/) | [C++](./C++/count-the-repetitions.cpp) [Python](./Python/count-the-repetitions.py) | _O(s1 * min(s2, n1))_ | _O(s2)_ | Hard || +467 | [Unique Substrings in Wraparound String](https://leetcode.com/problems/unique-substrings-in-wraparound-string/) | [C++](./C++/unique-substrings-in-wraparound-string.cpp) [Python](./Python/unique-substrings-in-wraparound-string.py) | _O(n)_ | _O(1)_ | Medium || +471 | [Encode String with Shortest Length](https://leetcode.com/problems/encode-string-with-shortest-length/) | [C++](./C++/encode-string-with-shortest-length.cpp) [Python](./Python/encode-string-with-shortest-length.py) | _O(n^3)_ on average | _O(n^2)_ | Medium |📖| +472 | [Concatenated Words](https://leetcode.com/problems/concatenated-words/) | [C++](./C++/concatenated-words.cpp) [Python](./Python/concatenated-words.py) | _O(n * l^2)_ | _O(n * l)_ | Medium || +474 | [Ones and Zeroes](https://leetcode.com/problems/ones-and-zeroes/) | [C++](./C++/ones-and-zeroes.cpp) [Python](./Python/ones-and-zeroes.py) | _O(s * m * n)_ | _O(m * n)_ | Medium || +552 | [Student Attendance Record II](https://leetcode.com/problems/student-attendance-record-ii/) | [C++](./C++/student-attendance-record-ii.cpp) [Python](./Python/student-attendance-record-ii.py) | _O(n)_ | _O(1)_ | Hard ||| +562 | [Longest Line of Consecutive One in Matrix](https://leetcode.com/problems/longest-line-of-consecutive-one-in-matrix/) | [C++](./C++/longest-line-of-consecutive-one-in-matrix.cpp) [Python](./Python/longest-line-of-consecutive-one-in-matrix.py) | _O(m * n)_ | _O(n)_ | Medium |📖|| +568 | [Maximum Vacation Days](https://leetcode.com/problems/maximum-vacation-days/) | [C++](./C++/maximum-vacation-days.cpp) [Python](./Python/maximum-vacation-days.py) | _O(n^2 * k)_ | _O(k)_ | Hard |📖|| +576 | [Out of Boundary Paths](https://leetcode.com/problems/out-of-boundary-paths/) | [C++](./C++/out-of-boundary-paths.cpp) [Python](./Python/out-of-boundary-paths.py) | _O(N * m * n)_ | _O(m * n)_ | Medium ||| +583 | [Delete Operation for Two Strings](https://leetcode.com/problems/delete-operation-for-two-strings/) | [C++](./C++/delete-operation-for-two-strings.cpp) [Python](./Python/delete-operation-for-two-strings.py) | _O(m * n)_ | _O(n)_ | Medium ||| +600 | [Non-negative Integers without Consecutive Ones](https://leetcode.com/problems/non-negative-integers-without-consecutive-ones/) | [C++](./C++/non-negative-integers-without-consecutive-ones.cpp) [Python](./Python/non-negative-integers-without-consecutive-ones.py) | _O(1)_ | _O(1)_ | Hard ||| +629 | [K Inverse Pairs Array](https://leetcode.com/problems/k-inverse-pairs-array/) | [C++](./C++/k-inverse-pairs-array.cpp) [Python](./Python/k-inverse-pairs-array.py) | _O(n * k)_ | _O(k)_ | Hard ||| +639 | [Decode Ways II](https://leetcode.com/problems/decode-ways-ii/) | [C++](./C++/decode-ways-ii.cpp) [Python](./Python/decode-ways-ii.py) | _O(n)_ | _O(1)_ | Hard ||| +650 | [2 Keys Keyboard](https://leetcode.com/problems/2-keys-keyboard/) | [C++](./C++/2-keys-keyboard.cpp) [Python](./Python/2-keys-keyboard.py) | _O(sqrt(n))_ | _O(1)_ | Medium ||| +656 | [Coin Path](https://leetcode.com/problems/coin-path/) | [C++](./C++/coin-path.cpp) [Python](./Python/coin-path.py) | _O(n * B)_ | _O(n)_ | Hard |📖| +664 | [Strange Printer](https://leetcode.com/problems/strange-printer/) | [C++](./C++/strange-printer.cpp) [Python](./Python/strange-printer.py) | _O(n^3)_ | _O(n^2)_ | Hard || +673 | [Number of Longest Increasing Subsequence](https://leetcode.com/problems/number-of-longest-increasing-subsequence/) | [C++](./C++/number-of-longest-increasing-subsequence.cpp) [Python](./Python/number-of-longest-increasing-subsequence.py) | _O(n^2)_ | _O(n)_ | Medium || +688 | [Knight Probability in Chessboard](https://leetcode.com/problems/knight-probability-in-chessboard/) | [C++](./C++/knight-probability-in-chessboard.cpp) [Python](./Python/knight-probability-in-chessboard.py) | _O(k * n^2)_ | _O(n^2)_ | Medium || +689 | [Maximum Sum of 3 Non-Overlapping Subarrays](https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/) | [C++](./C++/maximum-sum-of-3-non-overlapping-subarrays.cpp) [Python](./Python/maximum-sum-of-3-non-overlapping-subarrays.py) | _O(n)_ | _O(n)_ | Hard || +691 | [Stickers to Spell Word](https://leetcode.com/problems/stickers-to-spell-word/) | [C++](./C++/stickers-to-spell-word.cpp) [Python](./Python/stickers-to-spell-word.py) | _O(T * S^T)_ | _O(T * S^T)_ | Hard || Backtracking, Memoization +712 | [Minimum ASCII Delete Sum for Two Strings](https://leetcode.com/problems/minimum-ascii-delete-sum-for-two-strings/) | [C++](./C++/minimum-ascii-delete-sum-for-two-strings.cpp) [Python](./Python/minimum-ascii-delete-sum-for-two-strings.py) | _O(m * n)_ | _O(n)_ | Medium || +714 | [Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) | [C++](./C++/best-time-to-buy-and-sell-stock-with-transaction-fee.cpp) [Python](./Python/best-time-to-buy-and-sell-stock-with-transaction-fee.py) | _O(n)_ | _O(1)_ | Medium || +727 | [Minimum Window Subsequence](https://leetcode.com/problems/minimum-window-subsequence/) | [C++](./C++/minimum-window-subsequence.cpp) [Python](./Python/minimum-window-subsequence.py) | _O(s * t)_ | _O(s)_ | Hard |📖| +730 | [Count Different Palindromic Subsequences](https://leetcode.com/problems/count-different-palindromic-subsequences/) | [C++](./C++/count-different-palindromic-subsequences.cpp) [Python](./Python/count-different-palindromic-subsequences.py) | _O(n^2)_ | _O(n)_ | Hard || +740 | [Delete and Earn](https://leetcode.com/problems/delete-and-earn/) | [C++](./C++/delete-and-earn.cpp) [Python](./Python/delete-and-earn.py) | _O(n)_ | _O(1)_ | Medium || +741 | [Cherry Pickup](https://leetcode.com/problems/cherry-pickup/) | [C++](./C++/cherry-pickup.cpp) [Python](./Python/cherry-pickup.py) | _O(n^3)_ | _O(n^2)_ | Hard || +746 | [Min Cost Climbing Stairs](https://leetcode.com/problems/min-cost-climbing-stairs/) | [C++](./C++/min-cost-climbing-stairs.cpp) [Python](./Python/min-cost-climbing-stairs.py) | _O(n)_ | _O(1)_ | Easy || +750 | [Number Of Corner Rectangles](https://leetcode.com/problems/number-of-corner-rectangles/) | [C++](./C++/number-of-corner-rectangles.cpp) [Python](./Python/number-of-corner-rectangles.py) | _O(n * m^2)_ | _O(n * m)_ | Medium || + +## Greedy +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +11| [Container With Most Water](https://leetcode.com/problems/container-with-most-water/)| [C++](./C++/container-with-most-water.cpp) [Python](./Python/container-with-most-water.py) | _O(n)_ | _O(1)_ | Medium || +42| [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) | [C++](./C++/trapping-rain-water.cpp) [Python](./Python/trapping-rain-water.py) | _O(n)_ | _O(1)_ | Hard || Tricky +44| [Wildcard Matching](https://leetcode.com/problems/wildcard-matching/) | [Python](./Python/wildcard-matching.py) | _O(m + n)_ | _O(1)_ | Hard || Tricky +45| [Jump Game II](https://leetcode.com/problems/jump-game-ii/) | [Python](./Python/jump-game-ii.py) | _O(n)_ | _O(1)_ | Hard || +55| [Jump Game](https://leetcode.com/problems/jump-game/) | [Python](./Python/jump-game.py) | _O(n)_ | _O(1)_ | Medium || +122| [Best Time to Buy and Sell Stock II](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)| [Python](./Python/best-time-to-buy-and-sell-stock-ii.py) | _O(n)_ | _O(1)_ | Medium || +134| [Gas Station](https://leetcode.com/problems/gas-station/)| [Python](./Python/gas-station.py) | _O(n)_ | _O(1)_ | Medium || +135| [Candy](https://leetcode.com/problems/candy/)| [C++](./C++/candy.cpp) [Python](./Python/candy.py) | _O(n)_ | _O(n)_ | Hard || +316| [Remove Duplicate Letters](https://leetcode.com/problems/remove-duplicate-letters/) | [C++](./C++/remove-duplicate-letters.cpp) [Python](./Python/remove-duplicate-letters.py) | _O(n)_| _O(k)_| Hard || Ascending Stack | +321| [Create Maximum Number](https://leetcode.com/problems/create-maximum-number/)| [C++](./C++/create-maximum-number.cpp) [Python](./Python/create-maximum-number.py) | _O(k * (m + n + k))_ ~ _O(k * (m + n + k^2))_| _O(m + n + k^2)_ | Hard | variant of [Delete Digits](http://www.lintcode.com/en/problem/delete-digits/) | Greedy, DP +330| [Patching Array](https://leetcode.com/problems/patching-array/) | [C++](./C++/patching-array.cpp) [Python](./Python/patching-array.py) | _O(s + logn)_ | _O(1)_ | Hard || +376| [Wiggle Subsequence](https://leetcode.com/problems/wiggle-subsequence/)| [C++](./C++/wiggle-subsequence.cpp) [Python](./Python/wiggle-subsequence.py) | _O(n)_ | _O(1)_ | Medium || +392| [Is Subsequence](https://leetcode.com/problems/is-subsequence/)| [C++](./C++/is-subsequence.cpp) [Python](./Python/is-subsequence.py) | _O(n)_ | _O(1)_ | Medium || +397| [Integer Replacement](https://leetcode.com/problems/integer-replacement/)| [C++](./C++/integer-replacement.cpp) [Python](./Python/integer-replacement.py) | _O(n)_ | _O(1)_ | Medium || Math +402 | [Remove K Digits](https://leetcode.com/problems/remove-k-digits/) | [C++](./C++/remove-k-digits.cpp) [Python](./Python/remove-k-digits.py) | _O(n)_ | _O(n)_ | Medium | LintCode | +435 | [Non-overlapping Intervals](https://leetcode.com/problems/non-overlapping-intervals/) | [C++](./C++/non-overlapping-intervals.cpp) [Python](./Python/non-overlapping-intervals.py) | _O(nlogn)_ | _O(1)_ | Medium | | +452 | [Minimum Number of Arrows to Burst Balloons](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/) | [C++](./C++/minimum-number-of-arrows-to-burst-balloons.cpp) [Python](./Python/minimum-number-of-arrows-to-burst-balloons.py) | _O(nlogn)_ | _O(1)_ | Medium | | +455 | [Assign Cookies](https://leetcode.com/problems/assign-cookies/) | [C++](./C++/assign-cookies.cpp) [Python](./Python/assign-cookies.py) | _O(nlogn)_ | _O(1)_ | Easy | | +621 | [Task Scheduler](https://leetcode.com/problems/task-scheduler/) | [C++](./C++/task-scheduler.cpp) [Python](./Python/task-scheduler.py) | _O(n)_ | _O(1)_ | Medium | | +630 | [Course Schedule III](https://leetcode.com/problems/course-schedule-iii/) | [C++](./C++/course-schedule-iii.cpp) [Python](./Python/course-schedule-iii.py) | _O(nlogn)_ | _O(k)_ | Hard || +646 | [Maximum Length of Pair Chain](https://leetcode.com/problems/maximum-length-of-pair-chain/) | [C++](./C++/maximum-length-of-pair-chain.cpp) [Python](./Python/maximum-length-of-pair-chain.py) | _O(nlogn)_ | _O(1)_ | Medium || Scan Line +649 | [Dota2 Senate](https://leetcode.com/problems/dota2-senate/) | [C++](./C++/dota2-senate.cpp) [Python](./Python/dota2-senate.py) | _O(n)_ | _O(n)_ | Medium ||| +659 | [Split Array into Consecutive Subsequences](https://leetcode.com/problems/split-array-into-consecutive-subsequences/) | [C++](./C++/split-array-into-consecutive-subsequences.cpp) [Python](./Python/split-array-into-consecutive-subsequences.py) | _O(n)_ | _O(1)_ | Medium | | +738 | [Monotone Increasing Digits](https://leetcode.com/problems/monotone-increasing-digits/) | [C++](./C++/monotone-increasing-digits.cpp) [Python](./Python/monotone-increasing-digits.py) | _O(1)_ | _O(1)_ | Medium | | + +## Geometry +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +587 | [Erect the Fence](https://leetcode.com/problems/erect-the-fence/) | [C++](./C++/erect-the-fence.cpp) [Python](./Python/erect-the-fence.py) | _O(nlogn)_| _O(n)_| Hard || `Monotone Chain` | + +## Design +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +146| [LRU Cache](https://leetcode.com/problems/lru-cache/) | [C++](./C++/lru-cache.cpp) [Python](./Python/lru-cache.py) | _O(1)_ | _O(k)_ | Hard || +225| [Implement Stack using Queues](https://leetcode.com/problems/implement-stack-using-queues/) | [C++](./C++/implement-stack-using-queues.cpp) [Python](./Python/implement-stack-using-queues.py) | push: _O(n)_, pop: _O(1)_, top: _O(1)_ | _O(n)_ | Easy || +284| [Peeking Iterator](https://leetcode.com/problems/peeking-iterator/)| [C++](./C++/peeking-iterator.cpp) [Python](./Python/peeking-iterator.py) | _O(1)_ | _O(1)_ | Medium || +348| [Design Tic-Tac-Toe](https://leetcode.com/problems/design-tic-tac-toe/) | [C++](./C++/design-tic-tac-toe.cpp) [Python](./Python/design-tic-tac-toe.py) | _O(1)_ | _O(n^2)_ | Medium |📖|| +353| [Design Snake Game](https://leetcode.com/problems/design-snake-game/) | [C++](./C++/design-snake-game.cpp) [Python](./Python/design-snake-game.py) | _O(1)_ | _O(s)_ | Medium |📖| Deque | +355| [Design Twitter](https://leetcode.com/problems/design-twitter/) | [C++](./C++/design-twitter.cpp) [Python](./Python/design-twitter.py) | _O(klogu)_ | _O(t + f)_ | Medium | LintCode | Heap | +359| [Logger Rate Limiter](https://leetcode.com/problems/logger-rate-limiter/) | [C++](./C++/logger-rate-limiter.cpp) [Python](./Python/logger-rate-limiter.py) | _O(1), amortized_ | _O(k)_ | Easy |📖| Deque | +362| [Design Hit Counter](https://leetcode.com/problems/design-hit-counter/) | [C++](./C++/design-hit-counter.cpp) [Python](./Python/design-hit-counter.py) | _O(1), amortized_ | _O(k)_ | Medium |📖| Deque | +379| [Design Phone Directory](https://leetcode.com/problems/design-phone-directory/) | [C++](./C++/design-phone-directory.cpp) [Python](./Python/design-phone-directory.py) | _O(1)_ | _O(n)_ | Medium |📖| | +380| [Insert Delete GetRandom O(1)](https://leetcode.com/problems/insert-delete-getrandom-o1/) | [C++](./C++/insert-delete-getrandom-o1.cpp) [Python](./Python/insert-delete-getrandom-o1.py) | _O(1)_ | _O(n)_| Hard || | +381| [Insert Delete GetRandom O(1) - Duplicates allowed](https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/) | [C++](./C++/insert-delete-getrandom-o1-duplicates-allowed.cpp) [Python](./Python/insert-delete-getrandom-o1-duplicates-allowed.py) | _O(1)_ | _O(n)_ | Hard || | +432| [All O\`one Data Structure](https://leetcode.com/problems/all-oone-data-structure/) | [C++](./C++/all-oone-data-structure.cpp) [Python](./Python/all-oone-data-structure.py) | _O(1)_ | _O(n)_| Hard || | +460| [LFU Cache](https://leetcode.com/problems/lfu-cache/) | [C++](./C++/lfu-cache.cpp) [Python](./Python/lfu-cache.py) | _O(1)_ | _O(k)_ | Hard || | +588| [Design In-Memory File System](https://leetcode.com/problems/design-in-memory-file-system/) | [C++](./C++/design-in-memory-file-system.cpp) [Python](./Python/design-in-memory-file-system.py) | ls: _O(l + klogk)_
mkdir: _O(l)_
addContentToFile: _O(l + c)_
readContentFromFile: _O(l + c)_ | _O(n + s)_ | Hard |📖| | +604| [Design Compressed String Iterator](https://leetcode.com/problems/design-compressed-string-iterator/) | [C++](./C++/design-compressed-string-iterator.cpp) [Python](./Python/design-compressed-string-iterator.py) | _O(1)_ | _O(1)_ | Easy |📖| | +631| [Design Excel Sum Formula](https://leetcode.com/problems/design-excel-sum-formula/) | [C++](./C++/design-excel-sum-formula.cpp) [Python](./Python/design-excel-sum-formula.py) | set: _O((r * c)^2)_
get: _O(1)_
sum: _O((r * c)^2)_ | _O(r * c)_ | Hard |📖| | +635| [Design Log Storage System](https://leetcode.com/problems/design-log-storage-system/) | [C++](./C++/design-log-storage-system.cpp) [Python](./Python/design-log-storage-system.py) | put: _O(1)_
retrieve: _O(n + dlogd)_ | _O(n)_ | Medium |📖| | +642| [Design Search Autocomplete System](https://leetcode.com/problems/design-search-autocomplete-system/) | [C++](./C++/design-search-autocomplete-system.cpp) [Python](./Python/design-search-autocomplete-system.py) | _O(p^2)_ | _O(p * t + s)_ | Hard |📖| | +715| [Range Module](https://leetcode.com/problems/range-module/) | [C++](./C++/range-module.cpp) [Python](./Python/range-module.py) | add: _O(n)_
remove: _O(n)_
query: _O(logn)_ | _O(n)_ | Hard || | +716| [Max Stack](https://leetcode.com/problems/max-stack/) | [C++](./C++/max-stack.cpp) [Python](./Python/max-stack.py) | push: _O(logn)_
pop: _O(logn)_
popMax: _O(logn)_
top: _O(1)_
peekMax: _O(1)_ | _O(n)_ | Easy || | +745| [Prefix and Suffix Search](https://leetcode.com/problems/prefix-and-suffix-search/) | [C++](./C++/prefix-and-suffix-search.cpp) [Python](./Python/prefix-and-suffix-search.py) | ctor: _O(w * l^2)_
search : _O(p + s)_ | _O(t)_ | Hard || Trie | + +## SQL +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +175| [Combine Two Tables](https://leetcode.com/problems/combine-two-tables/) | [MySQL](./MySQL/combine-two-tables.sql) | _O(m + n)_ | _O(m + n)_ | Easy || +176| [Second Highest Salary](https://leetcode.com/problems/second-highest-salary/) | [MySQL](./MySQL/second-highest-salary.sql) | _O(n)_ | _O(1)_ | Easy || +177| [Nth Highest Salary](https://leetcode.com/problems/nth-highest-salary/) | [MySQL](./MySQL/nth-highest-salary.sql) | _O(n^2)_ | _O(n)_ | Medium || +178| [Rank Scores](https://leetcode.com/problems/rank-scores/) | [MySQL](./MySQL/rank-scores.sql) | _O(n^2)_ | _O(n)_ | Medium || +180| [Consecutive Numbers](https://leetcode.com/problems/consecutive-numbers/) | [MySQL](./MySQL/consecutive-numbers.sql) | _O(n)_ | _O(n)_ | Medium || +181| [Employees Earning More Than Their Managers](https://leetcode.com/problems/employees-earning-more-than-their-managers/) | [MySQL](./MySQL/employees-earning-more-than-their-managers.sql) | _O(n^2)_ | _O(1)_ | Easy || +182| [Duplicate Emails](https://leetcode.com/problems/duplicate-emails/) | [MySQL](./MySQL/duplicate-emails.sql) | _O(n^2)_ | _O(n)_ | Easy || +183| [Customers Who Never Order](https://leetcode.com/problems/customers-who-never-order/) | [MySQL](./MySQL/customers-who-never-order.sql) | _O(n^2)_ | _O(1)_ | Easy || +184| [Department Highest Salary](https://leetcode.com/problems/department-highest-salary/) | [MySQL](./MySQL/department-highest-salary.sql) | _O(n^2)_ | _O(n)_ | Medium || +185| [Department Top Three Salaries](https://leetcode.com/problems/department-top-three-salaries/) | [MySQL](./MySQL/department-top-three-salaries.sql) | _O(n^2)_ | _O(n)_ | Hard || +196| [Delete Duplicate Emails](https://leetcode.com/problems/delete-duplicate-emails/) | [MySQL](./MySQL/delete-duplicate-emails.sql) | _O(n^2)_ | _O(n)_ | Easy || +197| [Rising Temperature](https://leetcode.com/problems/rising-temperature/) | [MySQL](./MySQL/rising-temperature.sql) | _O(n^2)_ | _O(n)_ | Easy || +262| [Trips and Users](https://leetcode.com/problems/trips-and-users/) | [MySQL](./MySQL/trips-and-users.sql) | _O((t * u) + tlogt)_ | _O(t)_ | Hard || + +## Shell Script +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +192 | [Word Frequency](https://leetcode.com/problems/word-frequency/) | [Shell](./Shell/word-frequency.sh) | _O(n)_ | _O(k)_ | Medium || +193 | [Valid Phone Numbers](https://leetcode.com/problems/valid-phone-numbers/) | [Shell](./Shell/valid-phone-numbers.sh) | _O(n)_ | _O(1)_ | Easy || +194 | [Transpose File](https://leetcode.com/problems/transpose-file/) | [Shell](./Shell/transpose-file.sh) | _O(n^2)_ | _O(n^2)_ | Medium || +195 | [Tenth Line](https://leetcode.com/problems/tenth-line/) | [Shell](./Shell/tenth-line.sh) | _O(n)_ | _O(1)_ | Easy || diff --git a/Shell/tenth-line.sh b/Shell/tenth-line.sh new file mode 100644 index 000000000..631890a85 --- /dev/null +++ b/Shell/tenth-line.sh @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(1) +# +# How would you print just the 10th line of a file? +# +# For example, assume that file.txt has the following content: +# +# Line 1 +# Line 2 +# Line 3 +# Line 4 +# Line 5 +# Line 6 +# Line 7 +# Line 8 +# Line 9 +# Line 10 +# Your script should output the tenth line, which is: +# Line 10 +# +# Hint: +# 1. If the file contains less than 10 lines, what should you output? +# 2. There's at least three different solutions. Try to explore all possibilities. +# +# Read from the file file.txt and output the tenth line to stdout. + +# Solution 1 +awk '{if(NR==10) print $0}' file.txt +awk 'NR == 10' file.txt + +# Solution 2 +sed -n 10p file.txt + +# Solution 3 +tail -n+10 file.txt | head -1 diff --git a/Shell/transpose-file.sh b/Shell/transpose-file.sh new file mode 100644 index 000000000..e912f219d --- /dev/null +++ b/Shell/transpose-file.sh @@ -0,0 +1,35 @@ +# Time: O(n^2) +# Space: O(n^2) +# +# Given a text file file.txt, transpose its content. +# +# You may assume that each row has the same number of +# columns and each field is separated by the ' ' character. +# +# For example, if file.txt has the following content: +# +# name age +# alice 21 +# ryan 30 +# Output the following: +# +# name alice ryan +# age 21 30 +# + +# Read from the file file.txt and print its transposed content to stdout. +awk ' +{ + for (i = 1; i <= NF; i++) { + if(NR == 1) { + s[i] = $i; + } else { + s[i] = s[i] " " $i; + } + } +} +END { + for (i = 1; s[i] != ""; i++) { + print s[i]; + } +}' file.txt diff --git a/Shell/valid-phone-numbers.sh b/Shell/valid-phone-numbers.sh new file mode 100644 index 000000000..ca2e85fbf --- /dev/null +++ b/Shell/valid-phone-numbers.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Time: O(n) +# Space: O(1) +# +# Given a text file file.txt that contains list of +# phone numbers (one per line), write a one liner +# bash script to print all valid phone numbers. +# +# You may assume that a valid phone number must +# appear in one of the following two formats: +# (xxx) xxx-xxxx or xxx-xxx-xxxx. (x means a digit) +# +# You may also assume each line in the text file +# must not contain leading or trailing white spaces. +# +# For example, assume that file.txt has the following content: +# +# 987-123-4567 +# 123 456 7890 +# (123) 456-7890 +# Your script should output the following valid phone numbers: +# 987-123-4567 +# (123) 456-7890 +# +# +# Read from the file file.txt and output all valid phone numbers to stdout. +# Using grep: +grep -P '^(\d{3}-|\(\d{3}\) )\d{3}-\d{4}$' file.txt + +# Using sed: +sed -n -E '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/p' file.txt + +# Using awk: +awk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt diff --git a/Shell/word-frequency.sh b/Shell/word-frequency.sh new file mode 100644 index 000000000..1775f0504 --- /dev/null +++ b/Shell/word-frequency.sh @@ -0,0 +1,29 @@ +# Time: O(n) +# Space: O(k), k is number of words +# +# Write a bash script to calculate the frequency of each word in a text file words.txt. +# +# For simplicity sake, you may assume: +# +# words.txt contains only lowercase characters and +# space ' ' characters. +# Each word must consist of lowercase characters only. +# Words are separated by one or more whitespace characters. +# For example, assume that words.txt has the following content: +# +# the day is sunny the the +# the sunny is is +# Your script should output the following, +# sorted by descending frequency: +# the 4 +# is 3 +# sunny 2 +# day 1 +# Note: +# Don't worry about handling ties, +# it is guaranteed that each word's frequency count is unique. +# + +# Read from the file words.txt and output the word frequency list to stdout. +awk '{for(i=1;i<=NF;i++) a[$i]++} END {for(k in a) print k,a[k]}' words.txt | sort -k2 -nr +