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++/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-two-numbers.cpp b/C++/add-two-numbers.cpp new file mode 100644 index 000000000..800431821 --- /dev/null +++ b/C++/add-two-numbers.cpp @@ -0,0 +1,37 @@ +// 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 = ListNode(0); + ListNode *cur = &dummy; + int carry = 0; + while (l1 || l2) { + int val {carry}; + if (l1) { + val += l1->val; + l1 = l1->next; + } + if (l2) { + val += l2->val; + l2 = l2->next; + } + carry = val / 10; + cur->next = new ListNode(val % 10); + cur = cur->next; + } + if (carry) { + cur->next = new ListNode(carry); + } + 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..f6eb45970 --- /dev/null +++ b/C++/alien-dictionary.cpp @@ -0,0 +1,218 @@ +// 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) { + 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++/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++/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++/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-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-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++/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++/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-cow.cpp b/C++/bulls-and-cow.cpp new file mode 100644 index 000000000..373ec2c6d --- /dev/null +++ b/C++/bulls-and-cow.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++/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..87f16941d --- /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 (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++/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++/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..0231eb157 --- /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(logn). + 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++/copy-list-with-random-pointer.cpp b/C++/copy-list-with-random-pointer.cpp new file mode 100644 index 000000000..c730b93a2 --- /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 *cur = head; cur; cur = cur->next->next) { + auto *node = new RandomListNode(cur->label); + node->next = cur->next; + cur->next = node; + } + + // Update random node. + for (auto *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 (auto *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++/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-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..dcafc14bf --- /dev/null +++ b/C++/count-primes.cpp @@ -0,0 +1,36 @@ +// 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 { +public: + int countPrimes(int n) { + if (2 >= n) { + return 0; + } + bool* primes = new bool[n]; + for (int i = 2; i < n; ++i) + primes[i] = true; + + int sqr = sqrt(n - 1); + int sum = 0; + for (int i = 2; i < n; ++i) { + if (primes[i]) { + ++sum; + for (int j = i + i; j < n; j += i) { + primes[j] = false; + } + } + } + + delete[] primes; + + return sum; + } +}; 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..7891f8827 --- /dev/null +++ b/C++/create-maximum-number.cpp @@ -0,0 +1,112 @@ +// Time: O(k * (m + n + k)) ~ O(k * (m + n + k^2)) +// Space: O(m + n + k^2) + +// DP + Greedy solution. (48ms) +class Solution { +public: + vector maxNumber(vector& nums1, vector& nums2, int k) { + vector res(k); + const int m = nums1.size(), n = nums2.size(); + vector> max_digits1(k + 1), max_digits2(k + 1); + getMaxDigits(nums1, max(0, k - n), min(k, m), &max_digits1); // O(k * m) time, O(m + k^2) space. + getMaxDigits(nums2, max(0, k - m), min(k, n), &max_digits2); // O(k * n) time, O(n + k^2) space. + for (int i = max(0, k - n); i <= min(k, m); ++i) { // k * O(k) ~ k * O(k^2) time. + int j = k - i; + vector tmp(k); + merge(max_digits1[i], max_digits2[j], &tmp); + if (compareVector(tmp, res)) { + res = tmp; + } + } + return res; + } + +private: + void getMaxDigits(vector nums, int start, int end, vector> *maxDigits) { + (*maxDigits)[end] = maxDigit(nums, end); + for (int i = end - 1; i >= start; --i) { + (*maxDigits)[i] = deleteDigit((*maxDigits)[i + 1]); + } + } + + // Time: O(n) + // Space: O(n) + vector maxDigit(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 deleteDigit(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) + // Space: O(1) + bool compareVector(const vector& vec1, const vector& vec2) { + auto first1 = vec1.begin(), last1 = vec1.end(), + first2 = vec2.begin(), last2 = vec2.end(); + for (; first1 != last1 && first2 != last2; ++first1, ++first2) { + if (*first1 > *first2) { + return true; + } else if (*first1 < *first2) { + return false; + } + } + if (first1 == last1) { + return false; + } else { + return true; + } + } + + // 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 (*first2 > *first1) { + *result++ = *first2++; + } else if (*first2 < *first1) { + *result++ = *first1++; + } else { + auto pos1 = first1, pos2 = first2; + while (true) { // O(1) ~ O(k) time. + int val1 = (++pos1 != last1) ? *(pos1) : numeric_limits::min(); + int val2 = (++pos2 != last2) ? *(pos2) : numeric_limits::min(); + if (val1 > val2) { + *result++ = *first1++; + break; + } else if (val1 < val2) { + *result++ = *first2++; + break; + } + } + } + } + if (first1 == last1) { + std::copy(first2, last2, result); + } else if (first2 == last2) { + std::copy(first1, last1, result); + } + } +}; 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-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++/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++/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++/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++/expression-add-operators.cpp b/C++/expression-add-operators.cpp new file mode 100644 index 000000000..7a817a5c3 --- /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(move(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++/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-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-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++/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++/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++/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++/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++/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++/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++/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++/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++/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++/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..a344f90e6 --- /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(); + } + } + + // Removes 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; + } + + // Removes 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..ca1140f77 --- /dev/null +++ b/C++/implement-strstr.cpp @@ -0,0 +1,66 @@ +// 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) { + if (needle.empty()) { + return 0; + } + + 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++/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++/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++/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++/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++/isomorphic-strings.cpp b/C++/isomorphic-strings.cpp new file mode 100644 index 000000000..de37015b8 --- /dev/null +++ b/C++/isomorphic-strings.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + bool isIsomorphic(string s, string t) { + if (s.length() != t.length()) { + return false; + } + vector m1(256, 0); + vector m2(256, 0); + int n = s.size(); + for (int i = 0; i < n; ++i) { + if (m1[s[i]] != m2[t[i]]) return false; + m1[s[i]] = i + 1; + m2[t[i]] = i + 1; + } + return true; + } +}; 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++/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++/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++/linked-list-cycle-ii.cpp b/C++/linked-list-cycle-ii.cpp new file mode 100644 index 000000000..c4cf61ba2 --- /dev/null +++ b/C++/linked-list-cycle-ii.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 *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++/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-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++/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++/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..af65f6921 --- /dev/null +++ b/C++/lowest-common-ancestor-of-a-binary-tree.cpp @@ -0,0 +1,29 @@ +// 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* 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++/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++/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..240cd6f70 --- /dev/null +++ b/C++/maximal-rectangle.cpp @@ -0,0 +1,43 @@ +// Time: O(m * n) +// Space: 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 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 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. + res = max(res, H[j] * (R[j] - L[j])); + } else { + right = j; + } + } + } + + return res; + } +}; diff --git a/C++/maximal-square.cpp b/C++/maximal-square.cpp new file mode 100644 index 000000000..8fdafb1a0 --- /dev/null +++ b/C++/maximal-square.cpp @@ -0,0 +1,115 @@ +// Time: O(n^2) +// Space: O(n) + +// DP with rolling window. +class Solution { +public: + int maximalSquare(vector>& A) { + if (A.empty()) { + return 0; + } + const int m = A.size(), n = A[0].size(); + vector> size(2, vector(n, 0)); + int max_size = 0; + + for (int j = 0; j < n; ++j) { + size[0][j] = A[0][j] - '0'; + max_size = max(max_size, size[0][j]); + } + for (int i = 1; i < m; ++i) { + size[i % 2][0] = A[i][0] - '0'; + for (int j = 1; j < n; ++j) { + if (A[i][j] == '1') { + size[i % 2][j] = min(size[i % 2][j - 1], + min(size[(i - 1) % 2][j], + size[(i - 1) % 2][j - 1])) + 1; + max_size = max(max_size, size[i % 2][j]); + } else { + size[i % 2][j] = 0; + } + } + } + return max_size * max_size; + } +}; + +// Time: O(n^2) +// Space: O(n^2) +// DP. +class Solution2 { +public: + int maximalSquare(vector>& A) { + if (A.empty()) { + return 0; + } + const int m = A.size(), n = A[0].size(); + vector> size(m, vector(n, 0)); + int max_size = 0; + + for (int j = 0; j < n; ++j) { + size[0][j] = A[0][j] - '0'; + max_size = max(max_size, size[0][j]); + } + for (int i = 1; i < m; ++i) { + size[i][0] = A[i][0] - '0'; + for (int j = 1; j < n; ++j) { + if (A[i][j] == '1') { + size[i][j] = min(size[i][j - 1], + min(size[i - 1][j], + size[i - 1][j - 1])) + 1; + max_size = max(max_size, size[i][j]); + } else { + size[i][j] = 0; + } + } + } + return max_size * max_size; + } +}; + +// Time: O(n^2) +// Space: O(n^2) +// DP. +class Solution3 { +public: + struct MaxHW { + int h, w; + }; + + int maximalSquare(vector>& A) { + if (A.empty()) { + return 0; + } + + // DP table stores (h, w) for each (i, j). + vector> table(A.size(), vector(A.front().size())); + for (int i = A.size() - 1; i >= 0; --i) { + for (int j = A[i].size() - 1; j >= 0; --j) { + // Find the largest h such that (i, j) to (i + h - 1, j) are feasible. + // Find the largest w such that (i, j) to (i, j + w - 1) are feasible. + table[i][j] = A[i][j] == '1' + ? MaxHW{i + 1 < A.size() ? table[i + 1][j].h + 1 : 1, + j + 1 < A[i].size() ? table[i][j + 1].w + 1 : 1} + : MaxHW{0, 0}; + } + } + + // A table stores the length of largest square for each (i, j). + vector> s(A.size(), vector(A.front().size(), 0)); + int max_square_area = 0; + for (int i = A.size() - 1; i >= 0; --i) { + for (int j = A[i].size() - 1; j >= 0; --j) { + int side = min(table[i][j].h, table[i][j].w); + if (A[i][j]) { + // Get the length of largest square with bottom-left corner (i, j). + if (i + 1 < A.size() && j + 1 < A[i + 1].size()) { + side = min(s[i + 1][j + 1] + 1, side); + } + s[i][j] = side; + max_square_area = max(max_square_area, side * side); + } + } + } + return max_square_area; + } +}; diff --git a/C++/maximalRectangle.cpp b/C++/maximalRectangle.cpp deleted file mode 100644 index 829905865..000000000 --- a/C++/maximalRectangle.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Time Complexity: O(m * n) -// Space Complexity: O(n) - -class Solution { - public: - int maximalRectangle(vector > &matrix) { - if(matrix.empty()) - return 0; - - const int m = matrix.size(); - const int n = matrix.front().size(); - - int ans = 0; - - vector H(n, 0); // height of all ones rectangle include matrix[i][j] - vector L(n, 0); // left closed bound of all ones rectangle include matrix[i][j] - vector R(n, n); // right open bound of all onces rectangle include matrix[i][j] - - for(int i = 0; i < m; ++i) { - int left = 0, right = n; - for(int j = 0; j < n; ++j) { - if(matrix[i][j] == '1') { - ++H[j]; // update height - L[j] = max(L[j], left); // update left bound - } - else { - left = j + 1; - H[j] = L[j] = 0; - R[j] = n; - } - } - - for(int j = n - 1; j >= 0; --j) { - if(matrix[i][j] == '1') { - R[j] = min(R[j], right); // update right bound - ans = max(ans, H[j] * (R[j] - L[j])); - } - else { - right = j; - } - } - } - - return ans; - } -}; diff --git a/C++/maximum-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++/median-of-two-sorted-arrays.cpp b/C++/median-of-two-sorted-arrays.cpp new file mode 100644 index 000000000..9bbd45091 --- /dev/null +++ b/C++/median-of-two-sorted-arrays.cpp @@ -0,0 +1,44 @@ +// 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); + } +}; 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++/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-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++/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-zeros.cpp b/C++/move-zeros.cpp new file mode 100644 index 000000000..8f984a02e --- /dev/null +++ b/C++/move-zeros.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++/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++/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++/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-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-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..c13ebbefc --- /dev/null +++ b/C++/number-of-digit-one.cpp @@ -0,0 +1,34 @@ +// Time: O(logn) +// 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++/odd-even-linked-list.cpp b/C++/odd-even-linked-list.cpp new file mode 100644 index 000000000..4c6efad0a --- /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 (ListNode *odd_tail = head, *cur = head->next; + cur && cur->next; + cur = cur->next) { + ListNode *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; + } + } + 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++/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-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++/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++/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-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++/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++/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++/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++/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..17e9afefa --- /dev/null +++ b/C++/range-sum-query-2d-mutable.cpp @@ -0,0 +1,200 @@ +// 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(mlogm * nlogn) +// 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()) { + bit_ = vector>(matrix_.size() + 1, + vector(matrix_[0].size() + 1)); + for (int i = 0; i < matrix_.size(); ++i) { + for (int j = 0; j < matrix_[0].size(); ++j) { + add(i, j, matrix_[i][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) { + int sum = sumRegion_bit(row2, col2); + if (row1 > 0 && col1 > 0) { + sum += sumRegion_bit(row1 - 1, col1 - 1); + } + if (col1 > 0) { + sum -= sumRegion_bit(row2, col1 - 1); + } + if (row1 > 0) { + sum -= sumRegion_bit(row1 - 1, col2); + } + return sum; + } + +private: + vector> &matrix_; + vector> bit_; + + int sumRegion_bit(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; + } + } + } + + 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..e67971f04 --- /dev/null +++ b/C++/range-sum-query-mutable.cpp @@ -0,0 +1,162 @@ +// Time: ctor: O(n), +// update: O(logn), +// query: O(logn) +// Space: O(n) + +// Segment Tree solution. +class NumArray { +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); + } +}; + +// Time: ctor: O(nlogn), +// update: O(logn), +// query: O(logn) +// Space: O(n) +// Binary Indexed Tree (BIT) solution. +class NumArray2 { +public: + NumArray(vector &nums) : nums_(nums) { + bit_ = vector(nums_.size() + 1); + for (int i = 0; i < nums_.size(); ++i) { + add(i, nums_[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) { + int sum = sumRegion_bit(j); + if (i > 0) { + sum -= sumRegion_bit(i - 1); + } + return sum; + } + +private: + vector &nums_; + vector bit_; + + int sumRegion_bit(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; + } + } + + int lower_bit(int i) { + return i & -i; + } +}; + + +// 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++/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++/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++/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..f7e70a2a6 --- /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 = ListNode(0); + ListNode *pre = &dummy; + while (head) { + if (head->next && head->next->val == head->val) { + auto val = head->val; + while (head && head->val == val) { + head = head->next; + } + pre->next = head; + } else { + pre->next = head; + pre = 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-linked-list-elements.cpp b/C++/remove-linked-list-elements.cpp new file mode 100644 index 000000000..cbfc500f1 --- /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) { + auto dummy = ListNode(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++/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++/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-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..edf8ecd92 --- /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_head = new ListNode(0); + + while (head) { + auto *tmp = head->next; + head->next = dummy_head->next; + dummy_head->next = head; + head = tmp; + } + + return dummy_head->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..a3d16c385 --- /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 = ListNode(0); + dummy.next = head; + ListNode *cur = head, *cur_dummy = &dummy; + int len = 0; + + while (cur) { + ListNode *next_cur = cur->next; + len = (len + 1) % k; + + if (len == 0) { + ListNode *next_dummy = cur_dummy->next; + reverse(&cur_dummy, cur->next); + cur_dummy = next_dummy; + } + cur = next_cur; + } + return dummy.next; + } + + void reverse(ListNode **begin, const ListNode *end) { + ListNode *first = (*begin)->next; + ListNode *cur = first->next; + + while (cur != end) { + first->next = cur->next; + cur->next = (*begin)->next; + (*begin)->next = cur; + cur = first->next; + } + } +}; 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++/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-image.cpp b/C++/rotate-image.cpp new file mode 100644 index 000000000..70ff90fcd --- /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) { + 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; + } + } + } +}; + +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..c4dac2a4e --- /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; + ListNode *cur = head; + for (; cur->next; cur = cur->next) { + ++n; + } + cur->next = head; + + ListNode *tail = cur; + k = n - k % n; + cur = head; + for (int i = 0; i < k; cur = cur->next, ++i) { + tail = cur; + } + + tail->next = nullptr; + return cur; + } +}; 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++/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++/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++/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++/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..6c8a60392 --- /dev/null +++ b/C++/shortest-word-distance-iii.cpp @@ -0,0 +1,23 @@ +// Time: O(n) +// Space: O(1) + +class Solution { +public: + int shortestWordDistance(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) { + if (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++/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..f92542a27 --- /dev/null +++ b/C++/sliding-window-maximum.cpp @@ -0,0 +1,36 @@ +// Time: O(n) +// Space: O(k) + +class Solution { +public: + vector maxSlidingWindow(vector& nums, int k) { + const int n = nums.size(); + deque q; + vector max_numbers; + + for (int i = 0; i < k; ++i) { + while (!q.empty() && nums[i] >= nums[q.back()]) { + q.pop_back(); + } + q.emplace_back(i); + } + + for (int i = k; i < n; ++i) { + max_numbers.emplace_back(nums[q.front()]); + + while (!q.empty() && nums[i] >= nums[q.back()]) { + q.pop_back(); + } + while (!q.empty() && q.front() <= i - k) { + q.pop_front(); + } + q.emplace_back(i); + } + + if (!q.empty()) { + max_numbers.emplace_back(nums[q.front()]); + } + + return max_numbers; + } +}; 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-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++/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++/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++/summary-ranges.cpp b/C++/summary-ranges.cpp new file mode 100644 index 000000000..30b834516 --- /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 { + string 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-ugly-number.cpp b/C++/super-ugly-number.cpp new file mode 100644 index 000000000..bb20c20d7 --- /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.push({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.push({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.push({primes[k], k}); + ugly_set.emplace(primes[k]); + } + + for (int i = 1; i < n; ++i) { + int k; + tie(uglies[i]) = heap.top(); + heap.pop(); + while (ugly_set.count(primes[k] * uglies[idx[k]])) { + ++idx[k]; + } + heap.push({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.push({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.push({primes[k] * uglies[++idx[k]], k}); + } + } + + return uglies[n - 1]; + } +}; diff --git a/C++/surrounded-regions.cpp b/C++/surrounded-regions.cpp new file mode 100644 index 000000000..d7bfb0756 --- /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(make_pair(i, 0)); + q.emplace(make_pair(i, board[0].size() - 1)); + } + + for (int j = 0; j < board[0].size(); ++j) { + q.emplace(make_pair(0, j)); + q.emplace(make_pair(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(make_pair(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..05fe77e0b --- /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 = ListNode(0); + dummy.next = head; + ListNode *cur = &dummy; + while (cur->next && cur->next->next) { + ListNode *next_one = cur->next; + ListNode *next_two = next_one->next; + ListNode *next_three = next_two->next; + cur->next = next_two; + next_two->next = next_one; + next_one->next = next_three; + cur = next_one; + } + return dummy.next; + } +}; 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-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++/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++/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..b804fc34d --- /dev/null +++ b/C++/ugly-number.cpp @@ -0,0 +1,17 @@ +// Time: O(logn) +// 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-word-abbreviation.cpp b/C++/unique-word-abbreviation.cpp new file mode 100644 index 000000000..646c46d1d --- /dev/null +++ b/C++/unique-word-abbreviation.cpp @@ -0,0 +1,32 @@ +// 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) { + 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++/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-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++/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..b93946378 --- /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(make_pair(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(make_pair(I, J)); + } + } + } + } +}; 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++/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++/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..135c5de69 --- /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(make_pair(v1.size(), v1.cbegin())); + } + if (!v2.empty()) { + q.emplace(make_pair(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(make_pair(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/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..b0d82f1f5 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 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/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/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/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/3sum-closest.py b/Python/3sum-closest.py index 0681ae221..35301b24a 100644 --- a/Python/3sum-closest.py +++ b/Python/3sum-closest.py @@ -11,26 +11,29 @@ # 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..a622d76bf 100644 --- a/Python/3sum.py +++ b/Python/3sum.py @@ -15,29 +15,31 @@ # (-1, -1, 2) # -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 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.py b/Python/4sum.py index c049c577c..0ad8b8075 100644 --- a/Python/4sum.py +++ b/Python/4sum.py @@ -1,5 +1,5 @@ -# Time: O(n^2) ~ O(n^4) -# Space: O(n^2) +# Time: O(n^2 * p) +# Space: O(n^2 * p) # # Given an array S of n integers, # are there elements a, b, c, and d in S such that a + b + c + d = target? @@ -19,11 +19,37 @@ class Solution: # @return a list of lists of length 4, [[val1,val2,val3,val4]] def fourSum(self, nums, target): - nums, result, lookup = sorted(nums), [], {} + 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 Solution2: + # @return a list of lists of length 4, [[val1,val2,val3,val4]] + def fourSum(self, nums, target): + 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(): 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..baaa5cde5 --- /dev/null +++ b/Python/add-digits.py @@ -0,0 +1,25 @@ +# 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: + # @param {integer} num + # @return {integer} + def addDigits(self, num): + return (num - 1) % 9 + 1 if num > 0 else 0 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..08178ab1e --- /dev/null +++ b/Python/alien-dictionary.py @@ -0,0 +1,104 @@ +# 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)): + 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)): + 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/anagrams.py b/Python/anagrams.py index 7930db78c..a9e815abe 100644 --- a/Python/anagrams.py +++ b/Python/anagrams.py @@ -1,4 +1,4 @@ -# Time: O(n) +# Time: O(nlogg) = O(n / g * glogg), g is max size of groups # Space: O(n) # # Given an array of strings, return all groups of strings that are anagrams. @@ -6,22 +6,21 @@ # 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 + print result 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/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-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-tree-inorder-traversal.py b/Python/binary-tree-inorder-traversal.py index 5f68d1e39..094ed428b 100644 --- a/Python/binary-tree-inorder-traversal.py +++ b/Python/binary-tree-inorder-traversal.py @@ -66,7 +66,7 @@ def inorderTraversal(self, root): if parent.right in (None, last_traversed): if parent.right is None: result.append(parent.val) - last_traversed= stack.pop() + last_traversed = stack.pop() else: result.append(parent.val) current = parent.right @@ -76,14 +76,13 @@ class Solution3: # @param root, a tree node # @return a list of integers def inorderTraversal(self, root): - result, stack, current, last_traversed = [], [], root, None + result, stack, current = [], [], root while stack or current: if current: stack.append(current) current = current.left else: - current = stack[-1] - stack.pop() + current = stack.pop() result.append(current.val) current = current.right return 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-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-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/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/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-cow.py b/Python/bulls-and-cow.py new file mode 100644 index 000000000..b0c8849f4 --- /dev/null +++ b/Python/bulls-and-cow.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/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.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..bc4f909ef 100644 --- a/Python/compare-version-numbers.py +++ b/Python/compare-version-numbers.py @@ -1,25 +1,56 @@ # 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 # +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): @@ -41,4 +72,4 @@ def compareVersion(self, version1, version2): 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/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/count-and-say.py b/Python/count-and-say.py index 325fdc8e5..f1b27c374 100644 --- a/Python/count-and-say.py +++ b/Python/count-and-say.py @@ -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-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..8c3337efd --- /dev/null +++ b/Python/count-primes.py @@ -0,0 +1,30 @@ +# 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. +# + +from math import sqrt + +class Solution: + # @param {integer} n + # @return {integer} + def countPrimes(self, n): + if n <= 2: + return 0 + + is_prime = [True] * n + sqr = sqrt(n - 1) + + num = 0 + for i in xrange(2, n): + if is_prime[i]: + num += 1 + for j in xrange(i+i, n, i): + is_prime[j] = False + + return num + 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..27a762944 --- /dev/null +++ b/Python/counting-bits.py @@ -0,0 +1,38 @@ +# 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 diff --git a/Python/course-schedule-ii.py b/Python/course-schedule-ii.py new file mode 100644 index 000000000..0bffc2a61 --- /dev/null +++ b/Python/course-schedule-ii.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, 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: + # @param {integer} numCourses + # @param {integer[][]} prerequisites + # @return {integer[]} + def findOrder(self, numCourses, prerequisites): + 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] = sets.Set() + if j not in out_degree: + out_degree[j] = sets.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..395adba24 --- /dev/null +++ b/Python/course-schedule.py @@ -0,0 +1,69 @@ +# 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: + # @param {integer} numCourses + # @param {integer[][]} prerequisites + # @return {boolean} + def canFinish(self, numCourses, prerequisites): + zero_in_degree_queue, in_degree, out_degree = collections.deque(), {}, {} + + for i, j in prerequisites: + if i not in in_degree: + in_degree[i] = sets.Set() + if j not in out_degree: + out_degree[j] = sets.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/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-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/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/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/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/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-peak-element.py b/Python/find-peak-element.py index 84eb19221..1fe1ac83b 100644 --- a/Python/find-peak-element.py +++ b/Python/find-peak-element.py @@ -30,10 +30,9 @@ def findPeakElement(self, num): high = mid - 1 else: low = mid + 1 - mid = low + (high - low) / 2 return low 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-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-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/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/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/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/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/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/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/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..db2379811 --- /dev/null +++ b/Python/house-robber.py @@ -0,0 +1,30 @@ +# 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 + +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 9b7149b10..97042a17f 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): + """ + :type haystack: str + :type needle: str + :rtype: int + """ if not needle: return 0 - if len(haystack) < len(needle): - return -1 - - i = self.KMP(haystack, needle) - if i > -1: - return i - else: - return -1 + 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] @@ -49,17 +44,19 @@ def getPrefix(self, pattern): prefix[i] = j return prefix -# 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-triplet-subsequence.py b/Python/increasing-triplet-subsequence.py new file mode 100644 index 000000000..a9e76c280 --- /dev/null +++ b/Python/increasing-triplet-subsequence.py @@ -0,0 +1,54 @@ +# 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/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-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/isomorphic-strings.py b/Python/isomorphic-strings.py new file mode 100644 index 000000000..c66061412 --- /dev/null +++ b/Python/isomorphic-strings.py @@ -0,0 +1,40 @@ +# 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. +# + +class Solution: + # @param {string} s + # @param {string} t + # @return {boolean} + 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..bd771dabf 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. @@ -14,6 +14,24 @@ # 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): 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/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-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/letter-combinations-of-a-phone-number.py b/Python/letter-combinations-of-a-phone-number.py index c3d5e7779..c876137ca 100644 --- a/Python/letter-combinations-of-a-phone-number.py +++ b/Python/letter-combinations-of-a-phone-number.py @@ -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(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/longest-common-prefix.py b/Python/longest-common-prefix.py index 5c39975ab..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): + """ + :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"]) - 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-palindromic-substring.py b/Python/longest-palindromic-substring.py index 79abaf5af..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 not s: - 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") diff --git a/Python/longest-valid-parentheses.py b/Python/longest-valid-parentheses.py index 559ce3e30..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) 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..1b5e75d47 --- /dev/null +++ b/Python/lowest-common-ancestor-of-a-binary-tree.py @@ -0,0 +1,47 @@ +# Time: O(h) +# 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/majority-element-ii.py b/Python/majority-element-ii.py new file mode 100644 index 000000000..3a0d51fac --- /dev/null +++ b/Python/majority-element-ii.py @@ -0,0 +1,44 @@ +# 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. +# + +class Solution: + # @param {integer[]} nums + # @return {integer[]} + def majorityElement(self, nums): + k, n, hash = 3, len(nums), {} + + for i in nums: + if i not in hash: + hash[i] = 1 + else: + hash[i] += 1 + # 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 len(hash) == k: + for i in hash.keys(): + if hash[i] == 0: + del hash[i] + + # Resets hash for the following counting. + for i in hash.keys(): + hash[i] = 0 + + # Counts the occurrence of each candidate integer. + for i in nums: + if i in hash: + hash[i] += 1 + + # Selects the integer which occurs > [n / k] times. + ret = [] + for i in hash.keys(): + if hash[i] > n / k: + ret.append(i) + + return ret 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/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-gap.py b/Python/maximum-gap.py index 6bc30d14f..fd574a9ac 100644 --- a/Python/maximum-gap.py +++ b/Python/maximum-gap.py @@ -15,47 +15,47 @@ # # bucket sort +# Time: O(n) +# Space: O(n) + class Solution: - # @param num, a list of integer - # @return an integer - def maximumGap(self, num): - if len(num) < 2: + # @param numss: a list of integers + # @return: the maximum difference + def maximumGap(self, nums): + 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) 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/median-of-two-sorted-arrays.py b/Python/median-of-two-sorted-arrays.py index 644f74927..24b51a481 100644 --- a/Python/median-of-two-sorted-arrays.py +++ b/Python/median-of-two-sorted-arrays.py @@ -1,4 +1,4 @@ -# Time: O(log(m + n)) +# Time: O(log(min(m, n))) # Space: O(1) # # There are two sorted arrays A and B of size m and n respectively. @@ -14,6 +14,39 @@ def findMedianSortedArrays(self, A, B): 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): + m, n = len(A), len(B) + if m > n: + return self.getKth(B, A, k) + + left, right = 0, m + while left < right: + mid = left + (right - left) / 2 + j = k - 1 - mid + if 0 <= j < n and A[mid] >= B[j]: + right = mid + else: + left = mid + 1 + + Ai_minus_1, Bj = float("-inf"), float("-inf") + if left - 1 >= 0: + Ai_minus_1 = A[left - 1] + if k - 1 - left >= 0: + Bj = B[k - 1 - left] + + return max(Ai_minus_1, Bj) + +# Time: O(log(m + n)) +# Space: O(1) +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): b = max(0, k - len(B)) t = min(len(A), k) @@ -46,7 +79,7 @@ def getKth(self, A, B, k): # Time: O(log(m + n)) # Space: O(log(m + n)) -class Solution2: +class Solution3: # @return a float def findMedianSortedArrays(self, A, B): lenA, lenB = len(A), len(B) @@ -76,8 +109,8 @@ def getKth(self, A, i, B, j, k): else: return A[i + pa - 1] -# using list slicing (O(k)) may be slower than solution1 -class Solution3: +# using list slicing (O(k)) may be slower than Solution3 +class Solution4: # @return a float def findMedianSortedArrays(self, A, B): lenA, lenB = len(A), len(B) 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-k-sorted-lists.py b/Python/merge-k-sorted-lists.py index 0cd4e311b..8003ec215 100644 --- a/Python/merge-k-sorted-lists.py +++ b/Python/merge-k-sorted-lists.py @@ -1,5 +1,5 @@ # Time: O(nlogk) -# Space: O(1) +# Space: O(k) # # Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. import heapq @@ -41,4 +41,4 @@ def mergeKLists(self, lists): 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/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-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/missing-number.py b/Python/missing-number.py new file mode 100644 index 000000000..2abee7bb6 --- /dev/null +++ b/Python/missing-number.py @@ -0,0 +1,22 @@ +# 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))) 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-zeros.py b/Python/move-zeros.py new file mode 100644 index 000000000..820f2a5aa --- /dev/null +++ b/Python/move-zeros.py @@ -0,0 +1,42 @@ +# 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 + + +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 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/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..619248d22 --- /dev/null +++ b/Python/nim-game.py @@ -0,0 +1,25 @@ +# 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/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-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/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/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/pascals-triangle-ii.py b/Python/pascals-triangle-ii.py index f8aaa06d1..390a804cb 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,17 @@ def getRow(self, rowIndex): old, result[j] = result[j], old + result[j] return result + +# 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..822acab84 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. # 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/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-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..a3b5e1158 100644 --- a/Python/permutation-sequence.py +++ b/Python/permutation-sequence.py @@ -1,5 +1,5 @@ -# 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. # diff --git a/Python/permutations-ii.py b/Python/permutations-ii.py index 1f473145a..8f1cd2889 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,31 @@ # [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 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(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/power-of-three.py b/Python/power-of-three.py new file mode 100644 index 000000000..182c44b9f --- /dev/null +++ b/Python/power-of-three.py @@ -0,0 +1,21 @@ +# 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? +# + +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..f0eaac76d --- /dev/null +++ b/Python/power-of-two.py @@ -0,0 +1,17 @@ +# 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/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/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..74b2cf71c --- /dev/null +++ b/Python/range-sum-query-2d-mutable.py @@ -0,0 +1,82 @@ +# Time: ctor: O(mlogm * nlogn) +# 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(len(self.__matrix)): + for j in xrange(len(self.__matrix[0])): + self.__add(i, j, matrix[i][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 + """ + def sumRegion_bit(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 + + ret = sumRegion_bit(row2, col2) + if row1 > 0 and col1 > 0: + ret += sumRegion_bit(row1 - 1, col1 - 1) + if col1 > 0: + ret -= sumRegion_bit(row2, col1 - 1) + if row1 > 0: + ret -= sumRegion_bit(row1 - 1, col2) + 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..dbd1b079e --- /dev/null +++ b/Python/range-sum-query-mutable.py @@ -0,0 +1,165 @@ +# 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. +# + +# Segment Tree solutoin. +class NumArray(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 + +# Time: ctor: O(nlogn), +# update: O(logn), +# query: O(logn) +# Space: O(n) +# Binary Indexed Tree (BIT) solution. +class NumArray2(object): + def __init__(self, nums): + """ + initialize your data structure here. + :type nums: List[int] + """ + # Build segment tree. + if not nums: + return + self.__nums = nums + self.__bit = [0] * (len(self.__nums) + 1) + for i, num in enumerate(self.__nums): + self.__add(i, num) + + 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 + """ + def sumRegion_bit(i): + i += 1 + ret = 0 + while i > 0: + ret += self.__bit[i] + i -= (i & -i) + return ret + + ret = sumRegion_bit(j) + if i > 0: + ret -= sumRegion_bit(i - 1) + return ret + + def __add(self, i, val): + i += 1 + while i <= len(self.__nums): + self.__bit[i] += val + i += (i & -i) + +# 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/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/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/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 969a92981..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,12 +62,46 @@ 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): + 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: @@ -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-list-ii.py b/Python/remove-duplicates-from-sorted-list-ii.py index 5c8f44e14..e1b71703c 100644 --- a/Python/remove-duplicates-from-sorted-list-ii.py +++ b/Python/remove-duplicates-from-sorted-list-ii.py @@ -21,21 +21,25 @@ 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 +47,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..cb3f9fb59 100644 --- a/Python/remove-duplicates-from-sorted-list.py +++ b/Python/remove-duplicates-from-sorted-list.py @@ -9,32 +9,28 @@ # # 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 - else: - current = 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 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-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 index b3b926173..e2727b908 100644 --- a/Python/repeated-dna-sequences.py +++ b/Python/repeated-dna-sequences.py @@ -18,18 +18,15 @@ class Solution: # @param s, a string # @return a list of strings def findRepeatedDnaSequences(self, s): - dict = {} - rolling_hash = 0 - res = [] + dict, rolling_hash, res = {}, 0, [] for i in xrange(len(s)): rolling_hash = rolling_hash << 3 & 0x3fffffff | ord(s[i]) & 7 - if dict.get(rolling_hash) is None: + if rolling_hash not in dict: dict[rolling_hash] = True - else: - if dict[rolling_hash]: - res.append(s[i - 9: i + 1]) - dict[rolling_hash] = False + elif dict[rolling_hash]: + res.append(s[i - 9: i + 1]) + dict[rolling_hash] = False return res if __name__ == "__main__": 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..4dc5252b9 --- /dev/null +++ b/Python/reverse-bits.py @@ -0,0 +1,26 @@ +# 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 + +if __name__ == '__main__': + print Solution().reverseBits(1) diff --git a/Python/reverse-integer.py b/Python/reverse-integer.py index 69692d017..154445314 100644 --- a/Python/reverse-integer.py +++ b/Python/reverse-integer.py @@ -28,10 +28,10 @@ def reverse(self, x): while x: ans = ans * 10 + x % 10 x /= 10 - return ans + return ans if ans <= 2147483647 else 0 # Handle overflow. else: return -self.reverse(-x) 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-words-in-a-string-ii.py b/Python/reverse-words-in-a-string-ii.py index 09bd7f87b..6656ae327 100644 --- a/Python/reverse-words-in-a-string-ii.py +++ b/Python/reverse-words-in-a-string-ii.py @@ -1,9 +1,11 @@ # 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. +# 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. +# 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", @@ -12,23 +14,25 @@ # Could you do it in-place without allocating extra space? # -class Solution: - # @param s, a list of 1 length strings, e.g., s = ['h','e','l','l','o'] - # @return nothing +class Solution(object): def reverseWords(self, s): - self.reverse(s, 0, len(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] == ' ': - self.reverse(s, i, j) + reverse(s, i, j) i = j + 1 - - def reverse(self, s, begin, end): - for i in xrange((end - begin) / 2): - s[begin + i], s[end - 1 - i] = s[end - 1 - i], s[begin + i] + if __name__ == '__main__': s = ['h','e','l','l','o', ' ', 'w', 'o', 'r', 'l', 'd'] Solution().reverseWords(s) - print s \ No newline at end of file + print s 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/scramble-string.py b/Python/scramble-string.py index 5d7d4feeb..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 not s1: + 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)): 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-for-a-range.py b/Python/search-for-a-range.py index 505961eed..6e6c84d7b 100644 --- a/Python/search-for-a-range.py +++ b/Python/search-for-a-range.py @@ -17,10 +17,12 @@ class Solution: # @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) + # Find the first index where target <= A[idx] + left = self.binarySearch(lambda x, y: x <= y, A, target) if left >= len(A) or A[left] != target: return [-1, -1] - right = self.binarySearch(lambda x, y: x >= y, A, target) + # Find the first index where target < A[idx] + right = self.binarySearch(lambda x, y: x < y, A, target) return [left, right - 1] def binarySearch(self, compare, A, target): @@ -28,11 +30,31 @@ def binarySearch(self, compare, A, target): while start < end: mid = start + (end - start) / 2 if compare(target, A[mid]): + end = mid + else: start = mid + 1 + return start + + def binarySearch2(self, compare, A, target): + start, end = 0, len(A) - 1 + while start <= end: + mid = start + (end - start) / 2 + if compare(target, A[mid]): + end = mid - 1 else: - end = mid + start = mid + 1 return start + + def binarySearch3(self, compare, A, target): + start, end = -1, len(A) + while end - start > 1: + mid = start + (end - start) / 2 + if compare(target, A[mid]): + end = mid + else: + start = mid + return end 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/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/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/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..d0ba8d235 --- /dev/null +++ b/Python/shortest-word-distance-iii.py @@ -0,0 +1,24 @@ +# 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") + i, index1, index2 = 0, None, None + while i < len(words): + if words[i] == word1: + if 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/single-number-iii.py b/Python/single-number-iii.py new file mode 100644 index 000000000..c90e79bd2 --- /dev/null +++ b/Python/single-number-iii.py @@ -0,0 +1,45 @@ +# 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? +# + +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] diff --git a/Python/sliding-window-maximum.py b/Python/sliding-window-maximum.py new file mode 100644 index 000000000..1818c2a36 --- /dev/null +++ b/Python/sliding-window-maximum.py @@ -0,0 +1,58 @@ +# 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: + # @param {integer[]} nums + # @param {integer} k + # @return {integer[]} + def maxSlidingWindow(self, nums, k): + q = deque() + max_numbers = [] + + for i in xrange(k): + while q and nums[i] >= nums[q[-1]]: + q.pop() + q.append(i) + + for i in xrange(k, len(nums)): + max_numbers.append(nums[q[0]]) + + while q and nums[i] >= nums[q[-1]]: + q.pop() + + while q and q[0] <= i - k: + q.popleft() + + q.append(i) + + if q: + max_numbers.append(nums[q[0]]) + + return max_numbers 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-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/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/string-to-integer-atoi.py b/Python/string-to-integer-atoi.py index 17b23e886..970fd09b6 100644 --- a/Python/string-to-integer-atoi.py +++ b/Python/string-to-integer-atoi.py @@ -26,9 +26,12 @@ # 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 @@ -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 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/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/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-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/surrounded-regions.py b/Python/surrounded-regions.py index a0badb16c..98e7a65ad 100644 --- a/Python/surrounded-regions.py +++ b/Python/surrounded-regions.py @@ -25,27 +25,28 @@ class Solution: def solve(self, board): 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: diff --git a/Python/text-justification.py b/Python/text-justification.py index 5ccab0e51..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) + 1 - spaceCount %= i - begin - 1 - else: - everyCount = 1 +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 - # add space - j = begin - while j < i: - if j == begin: - s = words[j] - else: - s += ' ' * everyCount - if spaceCount > 0 and i < len(words): - s += ' ' - spaceCount -= 1 - s += words[j] - j += 1 - s += ' ' * spaceCount - result.append(s) - - return result if __name__ == "__main__": print Solution().fullJustify(["This", "is", "an", "example", "of", "text", "justification."], 16) 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/two-sum-iii-data-structure-design.py b/Python/two-sum-iii-data-structure-design.py index 0bcaf917e..828b5db15 100644 --- a/Python/two-sum-iii-data-structure-design.py +++ b/Python/two-sum-iii-data-structure-design.py @@ -16,15 +16,13 @@ class TwoSum: # initialize your data structure here def __init__(self): - self.lookup = {} + self.lookup = collections.defaultdict(int) # @return nothing def add(self, number): - if number in self.lookup: - self.lookup[number] += 1 - else: - self.lookup[number] = 1 + self.lookup[number] += 1 + # @param value, an integer # @return a Boolean @@ -44,4 +42,4 @@ def find(self, value): for i in (4, 7): print Sol.find(i) - \ No newline at end of file + diff --git a/Python/ugly-number-ii.py b/Python/ugly-number-ii.py new file mode 100644 index 000000000..7afc95156 --- /dev/null +++ b/Python/ugly-number-ii.py @@ -0,0 +1,42 @@ +# 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 diff --git a/Python/ugly-number.py b/Python/ugly-number.py new file mode 100644 index 000000000..003756ec7 --- /dev/null +++ b/Python/ugly-number.py @@ -0,0 +1,21 @@ +# Time: O(logn) +# 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-word-abbreviation.py b/Python/unique-word-abbreviation.py new file mode 100644 index 000000000..b6e84e88d --- /dev/null +++ b/Python/unique-word-abbreviation.py @@ -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(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 + """ + l = len(word) + abbr = self.abbreviation(word) + return self.lookup_[abbr] <= {word} + + + def abbreviation(self, word): + return word[0] + str(len(word)) + 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/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..8a5c744e7 100644 --- a/Python/valid-number.py +++ b/Python/valid-number.py @@ -21,7 +21,7 @@ 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 @@ -63,11 +63,11 @@ class Solution2: # @return a boolean def isNumber(self, s): 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/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/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/wildcard-matching.py b/Python/wildcard-matching.py index d930727d7..7965368aa 100644 --- a/Python/wildcard-matching.py +++ b/Python/wildcard-matching.py @@ -94,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 not p: - return not s + if not p or not s: + return not s and not p if p[0] != '*': - if not s 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 diff --git a/Python/word-break.py b/Python/word-break.py index bd39ed955..b1f9ad9ee 100644 --- a/Python/word-break.py +++ b/Python/word-break.py @@ -12,6 +12,34 @@ # class Solution: + # @param s: A string s + # @param dict: A dictionary of words dict + def wordSegmentation(self, s, dict): + if not s: + return True + + cnt = {} + for w in dict: + for c in w: + if c not in cnt: + cnt[c] = 0 + cnt[c] += 1 + for c in s: + if c not in cnt: + return False + + n = len(s) + possible = [False for _ in xrange(n)] + for i in xrange(n): + for j in reversed(xrange(i + 1)): + if (j == 0 or possible[j-1]) and s[j:i+1] in dict: + possible[i] = True + break + + return possible[n-1] + +# slower +class Solution2: # @param s, a string # @param dict, a set of string # @return a boolean @@ -29,4 +57,4 @@ def wordBreak(self, s, dict): return possible[n-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 8d47c5806..b7ffb1180 100644 --- a/Python/word-ladder-ii.py +++ b/Python/word-ladder-ii.py @@ -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': 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..36b7afe93 --- /dev/null +++ b/Python/word-search-ii.py @@ -0,0 +1,74 @@ +# 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: + # 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: + # @param {character[][]} board + # @param {string[]} words + # @return {string[]} + def findWords(self, board, words): + 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/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/README.md b/README.md index 9ef16ae91..5c1e3341c 100644 --- a/README.md +++ b/README.md @@ -1,761 +1,478 @@ -LeetCode -======== +# [LeetCode](https://leetcode.com/problemset/algorithms/) ![Language](https://img.shields.io/badge/language-Python-orange.svg) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.md) ![Progress](https://img.shields.io/badge/progress-338%20%2F%20338-ff69b4.svg) -Up to date (2015-02-24), there are total `189` problems on [LeetCode Online Judge](https://oj.leetcode.com/). -The number of problems is increasing recently. -Here is the classification of all `189` problems. +Up to date (2016-03-17), there are `321` Algorithms / `13` Database / `4` Shell questions on [LeetCode Online Judge](https://leetcode.com/). +The number of questions is increasing recently. +Here is the classification of all `338` 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) * [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 Array] | [rotate-array.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 Array]:https://oj.leetcode.com/problems/rotate-array/ -[rotate-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/rotate-array.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 | -[Compare Version Numbers] | [compare-version-numbers.py] | _O(n)_ | _O(1)_ | Easy | -[Count and Say] | [count-and-say.py]| _O(n * 2^n)_ | _O(2^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 | -[Reverse Words in a String II] | [reverse-words-in-a-string-ii.py] | _O(n)_ | _O(1)_ | 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 -[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 -[Reverse Words in a String II]:https://oj.leetcode.com/problems/reverse-words-in-a-string-ii/ -[reverse-words-in-a-string-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-words-in-a-string-ii.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(h)_| 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(h)_ | 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 | -[Anagrams] | [anagrams.py] | _O(n)_ | _O(n)_ | 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)_ | _O(k)_ | Hard | -[Repeated DNA Sequences] | [repeated-dna-sequences.py] | _O(n)_ | _O(n)_ | Medium | -[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^2)_ | _O(n)_ | Easy | - -[4 Sum]: https://oj.leetcode.com/problems/4sum/ -[4sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/4sum.py -[Anagrams]:https://oj.leetcode.com/problems/anagrams/ -[anagrams.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/anagrams.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 -[Repeated DNA Sequences]:https://oj.leetcode.com/problems/repeated-dna-sequences/ -[repeated-dna-sequences.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/repeated-dna-sequences.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(nlogn)_ | _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(logn)_ | 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)_ | Medium || +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| + +## 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 || +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 || +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)_ | Medium || +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)_ | Easy | | +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)_ | Medium |📖|| +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 ||| + +## 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` +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)_ | Medium | | +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 | | + +## 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 || +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)_ | Medium || +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 | +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 | +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)_ | Easy | | + +## Stack + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +20| [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/)| [Python](./Python/valid-parentheses.py) | _O(n)_ | _O(n)_ | Easy || +32| [Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/)| [Python](./Python/longest-valid-parentheses.py) | _O(n)_ | _O(1)_ | Hard || +71| [Simplify Path](https://leetcode.com/problems/simplify-path/)| [Python](./Python/simplify-path.py) | _O(n)_ | _O(n)_ | Medium || +101| [Symmetric Tree](https://leetcode.com/problems/symmetric-tree/)| [Python](./Python/symmetric-tree.py) | _O(n)_ | _O(h)_ | Easy || +150| [Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/)| [Python](./Python/evaluate-reverse-polish-notation.py)| _O(n)_| _O(n)_| Medium || +155| [Min Stack](https://leetcode.com/problems/min-stack/) | [Python](./Python/min-stack.py) | _O(n)_ | _O(1)_ | Easy || +173| [Binary Search Tree Iterator](https://leetcode.com/problems/binary-search-tree-iterator/) | [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)_| Medium || +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 ||| + +## 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 |📖|| + +## Heap + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +23| [Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) | [Python](./Python/merge-k-sorted-lists.py) | _O(nlogk)_| _O(k)_| Hard || +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 | + +## Tree + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +94 | [Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) | [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/) | [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/) | [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/) | [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/) | [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)_ | Medium | 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/) | [Python](./Python/two-sum.py) | _O(n)_ | _O(n)_ | Medium || +3| [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) | [Python](./Python/longest-substring-without-repeating-characters.py) | _O(n)_ | _O(1)_ | Medium || +18| [4 Sum](https://leetcode.com/problems/4sum/) |[Python](./Python/4sum.py) | _O(n^2 * p)_ | _O(n^2 * p)_ | Medium || +30| [Substring with Concatenation of All Words](https://leetcode.com/problems/substring-with-concatenation-of-all-words/) | [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/) | [Python](./Python/valid-sudoku.py) | _O(n^2)_ | _O(n)_ | Easy || +49| [Group Anagrams](https://leetcode.com/problems/anagrams/) | [Python](./Python/anagrams.py) | _O(nlogg)_ | _O(n)_ | Medium || +76| [Minimum Window Substring](https://leetcode.com/problems/minimum-window-substring/) | [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/) | [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/)| [Python](./Python/longest-substring-with-at-most-two-distinct-characters.py) | _O(n^2)_ | _O(1)_ | Hard |📖| +170| [Two Sum III - Data structure design](https://leetcode.com/problems/two-sum-iii-data-structure-design/) | [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/) | [Python](./Python/count-primes.py) | _O(n)_ | _O(n)_ | Easy || +205| [Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) | [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 Cow](https://leetcode.com/problems/bulls-and-cow/) | [C++](./C++/bulls-and-cow.cpp) [Python](./Python/bulls-and-cow.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)_| Easy | 📖 | +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 | | | + +## Data Structure + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +146| [LRU Cache](https://leetcode.com/problems/lru-cache/) | [Python](./Python/lru-cache.py) | _O(1)_ | _O(n)_ | 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)_ | Medium || + +## Math + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +7| [Reverse Integer](https://leetcode.com/problems/reverse-integer/) | [Python](./Python/reverse-integer.py) | _O(logn)_ | _O(1)_ | Easy || +9| [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | [Python](./Python/palindrome-number.py) | _O(1)_ | _O(1)_ | Easy || +12| [Integer to Roman](https://leetcode.com/problems/integer-to-roman/) | [Python](./Python/integer-to-roman.py) | _O(n)_ | _O(1)_ | Medium || +13| [Roman to Integer](https://leetcode.com/problems/roman-to-integer/) | [Python](./Python/roman-to-integer.py) | _O(n)_ | _O(1)_ | Easy || +29| [Divide Two Integers](https://leetcode.com/problems/divide-two-integers/) | [Python](./Python/divide-two-integers.py) | _O(logn)_ | _O(1)_ | Medium || +60| [Permutation Sequence](https://leetcode.com/problems/permutation-sequence/) | [Python](./Python/permutation-sequence.py) | _O(n^2)_ | _O(n)_ | Medium || `Cantor Ordering` +65| [Valid Number](https://leetcode.com/problems/valid-number/) | [Python](./Python/valid-number.py) | _O(n)_ | _O(1)_ | Hard || `Automata` +89| [Gray Code](https://leetcode.com/problems/gray-code/) | [Python](./Python/gray-code.py) | _O(2^n)_ | _O(1)_ | Medium || +166| [Fraction to Recurring Decimal](https://leetcode.com/problems/fraction-to-recurring-decimal/) | [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/) | [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/) | [Python](./Python/excel-sheet-column-number.py) | _O(n)_ | _O(1)_ | Easy || +172| [Factorial Trailing Zeroes](https://leetcode.com/problems/factorial-trailing-zeroes/) | [Python](./Python/factorial-trailing-zeroes.py) | _O(logn)_ | _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(logn)_ | _O(1)_ | Medium | 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(logn)_ | _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)_ | Medium ||| +338 | [Counting Bits](https://leetcode.com/problems/counting-bits/) | [C++](./C++/counting-bits.cpp) [Python](./Python/counting-bits.py) | _O(n)_ | _O(n)_ | Medium ||| + +## Sort + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +21| [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/)| [Python](./Python/merge-two-sorted-lists.py) | _O(n)_ | _O(1)_ | Easy || +56| [Merge Intervals](https://leetcode.com/problems/merge-intervals/)| [Python](./Python/merge-intervals.py) | _O(nlogn)_ | _O(1)_ | Hard || +57| [Insert Interval](https://leetcode.com/problems/insert-interval/)| [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/)| [Python](./Python/merge-sorted-array.py) | _O(n)_ | _O(1)_ | Easy || +147| [Insertion Sort List](https://leetcode.com/problems/insertion-sort-list/)|[Python](./Python/insertion-sort-list.py) | _O(n^2)_ | _O(1)_ | Medium || +148| [Sort List](https://leetcode.com/problems/sort-list/) | [Python](./Python/sort-list.py) | _O(nlogn)_ | _O(logn)_ | Medium || +164| [Maximum Gap](https://leetcode.com/problems/maximum-gap/) | [Python](./Python/maximum-gap.py)| _O(n)_ | _O(n)_ | Hard || Tricky +179| [Largest Number](https://leetcode.com/problems/largest-number/) | [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 | + +## 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/)| [Python](./Python/remove-nth-node-from-end-of-list.py) | _O(n)_ | _O(1)_ | Easy || +86| [Partition List](https://leetcode.com/problems/partition-list/)| [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)_ | Medium || +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/)| [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/) | [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 Zeros](https://leetcode.com/problems/move-zeros/) | [C++](./C++/move-zeros.cpp) [Python](./Python/move-zeros.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 | + +## Divide and Conquer + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +95| [Unique Binary Search Trees II](https://leetcode.com/problems/unique-binary-search-trees-ii/) | [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/)|[Python](./Python/validate-binary-search-tree.py)| _O(n)_ | _O(1)_ | Medium || +100| [Same Tree](https://leetcode.com/problems/same-tree/) |[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/)|[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/) | [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/) | [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/) | [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/) | [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 || + +## 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/) | [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/) | [Python](./Python/search-for-a-range.py) | _O(logn)_ | _O(1)_ | Medium || +35| [Search Insert Position](https://leetcode.com/problems/search-insert-position/) | [Python](./Python/search-insert-position.py) | _O(logn)_ | _O(1)_ | Medium || +50| [Pow(x, n)](https://leetcode.com/problems/powx-n/) | [Python](./Python/powx-n.py) | _O(logn)_ | _O(logn)_ | Medium || +69| [Sqrt(x)](https://leetcode.com/problems/sqrtx/) | [Python](./Python/sqrtx.py) | _O(logn)_ | _O(1)_ | Medium || +74| [Search a 2D Matrix](https://leetcode.com/problems/search-a-2d-matrix/) | [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/) | [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/) | [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/) | [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/) | [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)_ | Medium | 📖 | + +## 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 | 📖 | + +## 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/)| [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 | 📖 | + +## 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(h)_ | _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)_ | Medium ||| +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)_ | Medium ||| +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 ||| + +## 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)_ | Hard || +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/) | [Python](./Python/subsets.py) | _O(n * 2^n)_ | _O(1)_ | Medium || +90| [Subsets II](https://leetcode.com/problems/subsets-ii/) | [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/) | [Python](./Python/word-break-ii.py) | _O(n^2)_ | _O(n)_ | 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 |📖|| + +## 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 || +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 || +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/) | [Python](./Python/word-break.py) | _O(n^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)_ | Medium || +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 || + +## Greedy + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +11| [Container With Most Water](https://leetcode.com/problems/container-with-most-water/)| [Python](./Python/container-with-most-water.py) | _O(n)_ | _O(1)_ | Medium || +42| [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) | [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 || +84| [Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) | [Python](./Python/largest-rectangle-in-histogram.py) | _O(n)_ | _O(n)_ | Hard || Tricky +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/)| [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)_| Medium || 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)_ | Medium || --- - -##Brute Force Search -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Letter Combinations of a Phone Number]| [letter-combinations-of-a-phone-number.py] | _O(n * 4^n)_ | _O(n)_ | Medium | -[Permutations]| [permutations.py] | _O(n!)_ | _O(n)_ | Medium | -[Permutations II]| [permutations-ii.py] | _O(n!)_ | _O(n)_ | Hard | -[Subsets] | [subsets.py] | _O(n * 2^n)_ | _O(1)_ | Medium | -[Subsets II] | [subsets-ii.py] | _O(n * 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(h)_ | Easy | -[Binary Tree Maximum Path Sum]| [binary-tree-maximum-path-sum.py] | _O(n)_| _O(h)_| 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(h)_ | Medium | -[Maximum Depth of Binary Tree]|[maximum-depth-of-binary-tree.py]| _O(n)_ | _O(h)_ | Easy | -[Minimum Depth of Binary Tree]|[minimum-depth-of-binary-tree.py]| _O(n)_ | _O(h)_ | Easy | -[Populating Next Right Pointers in Each Node]|[populating-next-right-pointers-in-each-node.py]| _O(n)_ | _O(1)_ | Medium | -[Same Tree] |[same-tree.py] | _O(n)_ | _O(h)_ | Easy | -[Sum Root to Leaf Numbers] | [sum-root-to-leaf-numbers.py] | _O(n)_ | _O(h)_ | 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(1)_ | 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/ -[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(1)_ | 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(n * d)_ | _O(d)_ | 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(h)_ | Easy | -[Path Sum II] | [path-sum-ii.py] | _O(n)_ | _O(h)_ | 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 | -[Best Time to Buy and Sell Stock IV]| [best-time-to-buy-and-sell-stock-iv.py] | _O(k * n)_ | _O(k)_ | 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 -[Best Time to Buy and Sell Stock IV]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/ -[best-time-to-buy-and-sell-stock-iv.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock-iv.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(n * d)_ | _O(d)_ | 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 | -[Customers Who Never Order] | [customers-who-never-order.sql] | _O(n^2)_ | _O(1)_ | Easy | -[Department Highest Salary] | [department-highest-salary.sql] | _O(n^2)_ | _O(n)_ | Medium | -[Department Top Three Salaries] | [department-top-three-salaries.sql] | _O(n^2)_ | _O(n)_ | Hard | -[Duplicate Emails] | [duplicate-emails.sql] | _O(n^2)_ | _O(n)_ | Easy | -[Employees Earning More Than Their Managers] | [employees-earning-more-than-their-managers.sql] | _O(n^2)_ | _O(1)_ | Easy | -[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 -[Customers Who Never Order]:https://oj.leetcode.com/problems/customers-who-never-order/ -[customers-who-never-order.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/customers-who-never-order.sql -[Department Highest Salary]:https://oj.leetcode.com/problems/department-highest-salary/ -[department-highest-salary.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/department-highest-salary.sql -[Department Top Three Salaries]:https://oj.leetcode.com/problems/department-top-three-salaries/ -[department-top-three-salaries.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/department-top-three-salaries.sql -[Duplicate Emails]:https://oj.leetcode.com/problems/duplicate-emails/ -[duplicate-emails.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/duplicate-emails.sql -[Employees Earning More Than Their Managers]:https://oj.leetcode.com/problems/employees-earning-more-than-their-managers/ -[employees-earning-more-than-their-managers.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/employees-earning-more-than-their-managers.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 || + +## 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..561fde3a0 --- /dev/null +++ b/Shell/valid-phone-numbers.sh @@ -0,0 +1,33 @@ +# 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 +