diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..4042179a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +.idea/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject 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++/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++/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++/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++/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-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-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++/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++/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++/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++/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++/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.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-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.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-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++/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.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++/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++/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++/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++/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++/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-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++/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-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-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-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.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++/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.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++/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++/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-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-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-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++/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++/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++/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++/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++/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++/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++/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-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-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-peak-element.cpp b/C++/find-peak-element.cpp new file mode 100644 index 000000000..8e9dc8bf2 --- /dev/null +++ b/C++/find-peak-element.cpp @@ -0,0 +1,23 @@ +// 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 ((mid == 0 || nums[mid - 1] < nums[mid]) && + (mid + 1 == nums.size() || nums[mid] > nums[mid + 1])) { + return mid; + } else if (!(mid == 0 || nums[mid - 1] < nums[mid])) { + 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-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-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-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++/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-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++/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++/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++/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-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++/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++/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-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..c37a7626f --- /dev/null +++ b/C++/lfu-cache.cpp @@ -0,0 +1,70 @@ +// Time: O(1), per operation. +// Space: O(k), k is the capacity of cache. + +#include + +class LFUCache{ +public: + // @param capacity, an integer + LFUCache(int capacity) : capa_(capacity) { + } + + int get(int key) { + if (map_.find(key) != map_.end() && capa_) { + // It key exists, update it. + const auto value = map_[key]->value; + update(key, value); + return value; + } else { + return -1; + } + } + + void set(int key, int value) + if (!capa_) { + return; + } + // If cache is full while inserting, remove the last one. + if (map_.find(key) == map_.end() && list_.size() == capa_) { + auto del = list_.front(); list_.pop_front(); + map_.erase(del.key); + } + update(key, value); + } + +private: + struct node { + node(int k, int v, int f) : key(k), value(v), freq(f) {} + int key; + int value; + int freq; + }; + using List = list; + List list_; // key, value + unordered_map map_; // key, list iterator + int capa_; + + // Update (key, iterator of (key, value)) pair + void update(int key, int value) { + int freq = 0; + auto l_it = list_.begin(); + auto it = map_.find(key); + if (it != map_.end()) { + freq = it->second->freq; + l_it = next(it->second); + list_.erase(it->second); + } + ++freq; + while (l_it != list_.end() && freq >= l_it->freq) { + ++l_it; + } + map_[key] = list_.emplace(l_it, node(key, value, freq)); + } +}; + +/** + * Your LFUCache object will be instantiated and called as such: + * LFUCache obj = new LFUCache(capacity); + * int param_1 = obj.get(key); + * obj.set(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..3a6bec697 --- /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 = head_->val; + auto n = 1; + for (auto curr = head_->next; 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++/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-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-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-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-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++/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..e9fb97680 --- /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 set(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++/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-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-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++/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-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-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-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..fd47192ae --- /dev/null +++ b/C++/median-of-two-sorted-arrays.cpp @@ -0,0 +1,100 @@ +// 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 left is the (k + 1)-th 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 + 1 < right) { + const auto mid = left + (right - left) / 2; + if (match(arrays, mid, k)) { + right = mid; + } else { + left = mid; + } + } + // case: xoo + // ^^ + if (match(arrays, left, k)) { + return left; + } + // case: xo + // ^^ + return right; + } + + 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-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-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++/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-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-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-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-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++/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++/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++/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-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-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-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-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-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-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++/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++/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.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..5d20da082 --- /dev/null +++ b/C++/path-sum-iii.cpp @@ -0,0 +1,30 @@ +// Time: O(n^2) +// 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) { + 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++/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-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-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++/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..32ed28e72 --- /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; + int n = 0; + for (int i = 0; i < nums_.size(); ++i) { + if (nums_[i] != target) { + continue; + } + if (++n == 1 || 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.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-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++/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-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++/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.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++/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++/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++/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++/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-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-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-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++/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-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++/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++/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++/string-to-integer-atoi.cpp b/C++/string-to-integer-atoi.cpp new file mode 100644 index 000000000..f82d208a6 --- /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 ' '. + while (str[i] == ' ') { + ++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++/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..c1356a90c --- /dev/null +++ b/C++/substring-with-concatenation-of-all-words.cpp @@ -0,0 +1,39 @@ +// 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 Solution { +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++/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-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++/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++/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..dcda833a1 --- /dev/null +++ b/C++/top-k-frequent-elements.cpp @@ -0,0 +1,51 @@ +// Time: O(n) ~ O(n^2), O(n) on average. +// Space: O(n) + +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (const auto& i : nums) { + ++counts[i]; + } + + vector> p; + for (auto it = counts.begin(); it != counts.end(); ++it) { + p.emplace_back(-(it->second), it->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 Solution2 { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (int i = 0; i < nums.size(); ++i) { + ++counts[nums[i]]; + } + priority_queue> heap; + for (auto it = counts.begin(); it != counts.end(); ++it) { + heap.emplace(-(it->second), it->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++/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++/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.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.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-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-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-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..21c402d2a --- /dev/null +++ b/C++/water-and-jug-problem.cpp @@ -0,0 +1,19 @@ +// Time: O(logn), n is the max of (x, y) +// Space: O(1) + +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/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/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/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/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/second-highest-salary.sql b/MySQL/second-highest-salary.sql index 0a1a3e1c7..2565e2a61 100644 --- a/MySQL/second-highest-salary.sql +++ b/MySQL/second-highest-salary.sql @@ -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/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/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/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/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/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/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-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-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/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/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/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/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/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.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-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/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/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/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/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/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-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/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-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-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-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.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/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.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/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/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-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-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/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/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/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/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/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/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/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-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-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-peak-element.py b/Python/find-peak-element.py index 84eb19221..03b265932 100644 --- a/Python/find-peak-element.py +++ b/Python/find-peak-element.py @@ -1,39 +1,44 @@ # 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]): + while left < right: + mid = left + (right - left) / 2 + if (mid == 0 or nums[mid - 1] < nums[mid]) and \ + (mid + 1 == len(nums) or nums[mid] > nums[mid + 1]): return mid - elif mid > 0 and num[mid - 1] > num[mid]: - high = mid - 1 + elif not (mid == 0 or nums[mid - 1] < nums[mid]): + 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-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-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-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..3994a8649 --- /dev/null +++ b/Python/first-unique-character-in-a-string.py @@ -0,0 +1,55 @@ +# 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. +import collections +import string + + +class Solution(object): + def firstUniqChar(self, s): + """ + :type s: str + :rtype: int + """ + lookup = collections.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 + + def firstUniqChar2(self, s): + """ + :type s: str + :rtype: int + """ + return min([s.find(c) for c in string.ascii_lowercase if s.count(c) == 1] or [-1]) + + def firstUniqChar3(self, s): + """ + :type s: str + :rtype: int + """ + cnt = collections.Counter(s) + if cnt: + for i in cnt.keys(): + if cnt[i] == 1: + return s.index(i) + return -1 + else: + return -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/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/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/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/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..4642fdcc5 100644 --- a/Python/intersection-of-two-linked-lists.py +++ b/Python/intersection-of-two-linked-lists.py @@ -33,11 +33,12 @@ 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 while curA and curB: if curA == curB: - return curA + begin = curA + break if curA.next: curA = curA.next @@ -55,4 +56,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/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-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/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/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-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/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..c07627521 --- /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 = self.__head.val + curr, n = self.__head.next, 1 + 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/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-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-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-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-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/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..b327f8cdd 100644 --- a/Python/lru-cache.py +++ b/Python/lru-cache.py @@ -1,6 +1,6 @@ -# 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 set. # @@ -8,7 +8,6 @@ # # 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. -# class ListNode: def __init__(self, key, val): @@ -106,4 +105,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/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-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-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-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-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-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-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-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-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/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-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-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-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-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-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/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/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/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-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-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-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-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-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-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/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/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/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..a02b434f0 --- /dev/null +++ b/Python/path-sum-iii.py @@ -0,0 +1,59 @@ +# Time: O(n^2) +# 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, prev, sum): + if not root: + return 0 + + curr = prev + root.val; + return int(curr == sum) + \ + pathSumHelper(root.left, curr, sum) + \ + pathSumHelper(root.right, curr, sum) + + if not root: + return 0 + + return pathSumHelper(root, 0, sum) + \ + self.pathSum(root.left, sum) + \ + self.pathSum(root.right, sum) 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-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-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/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..59fbaadf9 --- /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 n == 0 or 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.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-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/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/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..a4c72fc78 --- /dev/null +++ b/Python/repeated-dna-sequences.py @@ -0,0 +1,47 @@ +# 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: + # @param s, a string + # @return a list of strings + def findRepeatedDnaSequences(self, s): + 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-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/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/rotate-array.py b/Python/rotate-array.py new file mode 100644 index 000000000..f4df62d44 --- /dev/null +++ b/Python/rotate-array.py @@ -0,0 +1,67 @@ +# 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 + + +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..088473598 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 index where target <= nums[idx] + 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 index where target < nums[idx] + 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 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/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/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/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/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-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-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-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/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-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/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/string-to-integer-atoi.py b/Python/string-to-integer-atoi.py index b10431638..970fd09b6 100644 --- a/Python/string-to-integer-atoi.py +++ b/Python/string-to-integer-atoi.py @@ -26,14 +26,17 @@ # 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 @@ -48,12 +51,8 @@ def atoi(self, str): 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 - + if result > (INT_MAX - (ord(str[i]) - ord('0'))) / 10: + return INT_MAX if sign > 0 else INT_MIN result = result * 10 + ord(str[i]) - ord('0') i += 1 @@ -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/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..03e5fa7f3 100644 --- a/Python/substring-with-concatenation-of-all-words.py +++ b/Python/substring-with-concatenation-of-all-words.py @@ -19,23 +19,18 @@ class Solution: # @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]) + result, word_num, word_len = [], len(L), len(L[0]) + words = collections.defaultdict(int) for i in L: - if i not in words: - words[i] = 1 - else: - words[i] += 1 + words[i] += 1 for i in xrange(len(S) + 1 - word_len * word_num): - cur, j = {}, 0 + cur, j = collections.defaultdict(int), 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 - else: - cur[word] += 1 + cur[word] += 1 if cur[word] > words[word]: break j += 1 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-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/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/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..bf3741127 --- /dev/null +++ b/Python/top-k-frequent-elements.py @@ -0,0 +1,75 @@ +# Time: O(n) ~ O(n^2), O(n) on average. +# 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. + +from random import randint + +class Solution(object): + def topKFrequent(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + counts = collections.defaultdict(int) + for i in nums: + counts[i] += 1 + + 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][0] + new_pivot_idx = left + nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx] + for i in xrange(left, right): + if nums[i][0] > 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 Solution2(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/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/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.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-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..5fe61e61e --- /dev/null +++ b/Python/valid-anagram.py @@ -0,0 +1,48 @@ +# 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 + +# 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.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-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-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-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..20030b4ad --- /dev/null +++ b/Python/water-and-jug-problem.py @@ -0,0 +1,39 @@ +# 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 + + +def gcd(a, b): + while b: + a, b = b, a%b + return a + +class Solution(object): + def canMeasureWater(self, x, y, z): + """ + :type x: int + :type y: int + :type z: int + :rtype: bool + """ + return z == 0 or ((x + y >= z) 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..17cdb9a77 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: # 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..932f75cc2 100644 --- a/README.md +++ b/README.md @@ -1,734 +1,609 @@ -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) ![Progress](https://img.shields.io/badge/progress-468%20%2F%20468-ff69b4.svg) -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. +Up to date (2016-12-18), there are `447` Algorithms / `13` Database / `4` Shell / `4` Draft questions on [LeetCode Online Judge](https://leetcode.com/). +The number of questions is increasing recently. +Here is the classification of all `468` questions. +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) +* [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 +## 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 || + +## 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 ||| + + +## 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 | | +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 | | + +## 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 ||| + +## 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 || + +## 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 || + +## 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 | + +## 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 || + +## Data Structure +| # | 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 || + +## 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 || Euclidean Algorithm | +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 |📖|| + +## 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)_ on average | _O(n)_ | Medium | | Quick Select, Heap | +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 | | | +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 | | | + + +## 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 || + +## 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^2)_ | _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 | | + +## 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 | + +## 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 || + +## 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 |📖|| + +## 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 || + +## 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 | | --- - -##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 - +## Design +| # | Title | Solution | Time | Space | Difficulty | Tag | Note| +|-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------|-----| +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 || | + +## 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 +