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/customers-who-never-order.sql b/MySQL/customers-who-never-order.sql new file mode 100644 index 000000000..c63d41aaa --- /dev/null +++ b/MySQL/customers-who-never-order.sql @@ -0,0 +1,42 @@ +# Time: O(n^2) +# Space: O(1) +# +# Suppose that a website contains two tables, the Customers table and the Orders table. Write a SQL query to find all customers who never order anything. +# +# Table: Customers. +# +# +----+-------+ +# | Id | Name | +# +----+-------+ +# | 1 | Joe | +# | 2 | Henry | +# | 3 | Sam | +# | 4 | Max | +# +----+-------+ +# Table: Orders. +# +# +----+------------+ +# | Id | CustomerId | +# +----+------------+ +# | 1 | 3 | +# | 2 | 1 | +# +----+------------+ +# Using the above tables as example, return the following: +# +# +-----------+ +# | Customers | +# +-----------+ +# | Henry | +# | Max | +# +-----------+ +# + +# Time: O(n^2) +# Space: O(1) +# Write your MySQL query statement below +SELECT Name AS Customers FROM Customers WHERE Id NOT IN (SELECT CustomerId FROM Orders) + +# Time: O(n^2) +# Space: O(n) +# Write your MySQL query statement below +SELECT Customers.Name AS Customers FROM (Customers LEFT JOIN Orders ON Customers.Id = Orders.CustomerId) WHERE Orders.CustomerId IS NULL diff --git a/MySQL/delete-duplicate-emails.sql b/MySQL/delete-duplicate-emails.sql new file mode 100644 index 000000000..b098426ca --- /dev/null +++ b/MySQL/delete-duplicate-emails.sql @@ -0,0 +1,28 @@ +# Time: O(n^2) +# Space: O(n) +# +# Write a SQL query to delete all duplicate email entries in a table named Person, +# keeping only unique emails based on its smallest Id. +# +# +----+------------------+ +# | Id | Email | +# +----+------------------+ +# | 1 | john@example.com | +# | 2 | bob@example.com | +# | 3 | john@example.com | +# +----+------------------+ +# Id is the primary key column for this table. +# For example, after running your query, the above Person table should have the following rows: +# +# +----+------------------+ +# | Id | Email | +# +----+------------------+ +# | 1 | john@example.com | +# | 2 | bob@example.com | +# +----+------------------+ +# + +# Write your MySQL query statement below +DELETE p1 +FROM Person p1, Person p2 +WHERE p1.Email = p2.Email AND p1.Id > p2.Id diff --git a/MySQL/department-highest-salary.sql b/MySQL/department-highest-salary.sql new file mode 100644 index 000000000..69c88f734 --- /dev/null +++ b/MySQL/department-highest-salary.sql @@ -0,0 +1,42 @@ +# Time: O(n^2) +# Space: O(n) +# +# The Employee table holds all employees. Every employee has an Id, a salary, and there is also a column for the department Id. +# +# +----+-------+--------+--------------+ +# | Id | Name | Salary | DepartmentId | +# +----+-------+--------+--------------+ +# | 1 | Joe | 70000 | 1 | +# | 2 | Henry | 80000 | 2 | +# | 3 | Sam | 60000 | 2 | +# | 4 | Max | 90000 | 1 | +# +----+-------+--------+--------------+ +# The Department table holds all departments of the company. +# +# +----+----------+ +# | Id | Name | +# +----+----------+ +# | 1 | IT | +# | 2 | Sales | +# +----+----------+ +# Write a SQL query to find employees who have the highest salary in each of the departments. For the above tables, Max has the highest salary in the IT department and Henry has the highest salary in the Sales department. +# +# +------------+----------+--------+ +# | Department | Employee | Salary | +# +------------+----------+--------+ +# | IT | Max | 90000 | +# | Sales | Henry | 80000 | +# +------------+----------+--------+ +# +# Write your MySQL query statement below +SELECT d.Department AS Department, e.Name AS Employee, d.Salary AS Salary +FROM (SELECT Department.Id AS DepartmentId, Department.Name AS Department, emp.Salary AS Salary + FROM Department JOIN (SELECT DepartmentId, MAX(Salary) AS Salary FROM Employee GROUP BY DepartmentId) emp + ON Department.Id = emp.DepartmentId) d + JOIN Employee e + ON e.DepartmentId = d.DepartmentId and e.Salary = d.Salary + +# Write your MySQL query statement below +SELECT Department.Name AS Department, Employee.Name AS Employee, Employee.Salary AS Salary +FROM Department JOIN Employee ON Employee.DepartmentId = Department.Id +WHERE Employee.Salary IN (SELECT MAX(e.Salary) FROM Employee e WHERE e.DepartmentId = Employee.DepartmentId) diff --git a/MySQL/department-top-three-salaries.sql b/MySQL/department-top-three-salaries.sql new file mode 100644 index 000000000..337c3ff81 --- /dev/null +++ b/MySQL/department-top-three-salaries.sql @@ -0,0 +1,41 @@ +# Time: O(n^2) +# Space: O(n) +# +# The Employee table holds all employees. Every employee has an Id, and there is also a column for the department Id. +# +# +----+-------+--------+--------------+ +# | Id | Name | Salary | DepartmentId | +# +----+-------+--------+--------------+ +# | 1 | Joe | 70000 | 1 | +# | 2 | Henry | 80000 | 2 | +# | 3 | Sam | 60000 | 2 | +# | 4 | Max | 90000 | 1 | +# | 5 | Janet | 69000 | 1 | +# | 6 | Randy | 85000 | 1 | +# +----+-------+--------+--------------+ +# The Department table holds all departments of the company. +# +# +----+----------+ +# | Id | Name | +# +----+----------+ +# | 1 | IT | +# | 2 | Sales | +# +----+----------+ +# Write a SQL query to find employees who earn the top three salaries in each of the department. For the above tables, your SQL query should return the following rows. +# +# +------------+----------+--------+ +# | Department | Employee | Salary | +# +------------+----------+--------+ +# | IT | Max | 90000 | +# | IT | Randy | 85000 | +# | IT | Joe | 70000 | +# | Sales | Henry | 80000 | +# | Sales | Sam | 60000 | +# +------------+----------+--------+ + +# Write your MySQL query statement below +SELECT D.Name AS Department, E.Name AS Employee, E.Salary AS Salary +FROM Employee E INNER JOIN Department D ON E.DepartmentId = D.Id +WHERE (SELECT COUNT(DISTINCT(Salary)) FROM Employee + WHERE DepartmentId = E.DepartmentId AND Salary > E.Salary) < 3 +ORDER by E.DepartmentId, E.Salary DESC; diff --git a/MySQL/duplicate-emails.sql b/MySQL/duplicate-emails.sql new file mode 100644 index 000000000..836ad0490 --- /dev/null +++ b/MySQL/duplicate-emails.sql @@ -0,0 +1,24 @@ +# Time: O(n^2) +# Space: O(n) +# +# Write a SQL query to find all duplicate emails in a table named Person. +# +# +----+---------+ +# | Id | Email | +# +----+---------+ +# | 1 | a@b.com | +# | 2 | c@d.com | +# | 3 | a@b.com | +# +----+---------+ +# For example, your query should return the following for the above table: +# +# +---------+ +# | Email | +# +---------+ +# | a@b.com | +# +---------+ +# Note: All emails are in lowercase. +# + +# Write your MySQL query statement below +SELECT Email FROM Person GROUP BY Email HAVING COUNT(*) > 1 diff --git a/MySQL/employees-earning-more-than-their-managers.sql b/MySQL/employees-earning-more-than-their-managers.sql new file mode 100644 index 000000000..eaafe2a00 --- /dev/null +++ b/MySQL/employees-earning-more-than-their-managers.sql @@ -0,0 +1,37 @@ +# Time: O(n^2) +# Space: O(1) +# +# The Employee table holds all employees including their managers. Every employee has an Id, and there is also a column for the manager Id. +# +# +----+-------+--------+-----------+ +# | Id | Name | Salary | ManagerId | +# +----+-------+--------+-----------+ +# | 1 | Joe | 70000 | 3 | +# | 2 | Henry | 80000 | 4 | +# | 3 | Sam | 60000 | NULL | +# | 4 | Max | 90000 | NULL | +# +----+-------+--------+-----------+ +# Given the Employee table, write a SQL query that finds out employees who earn more than their managers. For the above table, Joe is the only employee who earns more than his manager. +# +# +----------+ +# | Employee | +# +----------+ +# | Joe | +# +----------+ +# + +# Time: O(n^2) +# Space: O(n) +# Write your MySQL query statement below +SELECT e.Name AS Employee FROM Employee e LEFT JOIN Employee b + ON e.ManagerId=b.Id + WHERE e.Salary > b.Salary + +# Time: O(n^2) +# Space: O(1) +# Write your MySQL query statement below +SELECT Name AS Employee + FROM Employee e + WHERE e.ManagerId IS NOT NULL AND e.Salary > (SELECT Salary + FROM Employee + WHERE e.ManagerId = Id) diff --git a/MySQL/rising-temperature.sql b/MySQL/rising-temperature.sql new file mode 100644 index 000000000..91c25d228 --- /dev/null +++ b/MySQL/rising-temperature.sql @@ -0,0 +1,28 @@ +# Time: O(n^2) +# Space: O(n) +# +# Given a Weather table, write a SQL query to find all dates' +# Ids with higher temperature compared to its previous (yesterday's) dates. +# +# +---------+------------+------------------+ +# | Id(INT) | Date(DATE) | Temperature(INT) | +# +---------+------------+------------------+ +# | 1 | 2015-01-01 | 10 | +# | 2 | 2015-01-02 | 25 | +# | 3 | 2015-01-03 | 20 | +# | 4 | 2015-01-04 | 30 | +# +---------+------------+------------------+ +# For example, return the following Ids for the above Weather table: +# +----+ +# | Id | +# +----+ +# | 2 | +# | 4 | +# +----+ +# + +# Write your MySQL query statement below +SELECT wt1.Id +FROM Weather wt1, Weather wt2 +WHERE wt1.Temperature > wt2.Temperature AND + TO_DAYS(wt1.DATE)-TO_DAYS(wt2.DATE)=1; diff --git a/MySQL/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/balanced-binary-tree.py b/Python/balanced-binary-tree.py index 532657698..fbf1326ab 100644 --- a/Python/balanced-binary-tree.py +++ b/Python/balanced-binary-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, determine if it is height-balanced. # diff --git a/Python/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-iii.py b/Python/best-time-to-buy-and-sell-stock-iii.py index 7b08da290..114c1b321 100644 --- a/Python/best-time-to-buy-and-sell-stock-iii.py +++ b/Python/best-time-to-buy-and-sell-stock-iii.py @@ -12,7 +12,43 @@ # (ie, you must sell the stock before you buy again). # +# Time: O(n) +# Space: O(1) class Solution: + # @param prices, a list of integer + # @return an integer + def maxProfit(self, prices): + hold1, hold2 = float("-inf"), float("-inf") + release1, release2 = 0, 0 + for i in prices: + release2 = max(release2, hold2 + i) + hold2 = max(hold2, release1 - i) + release1 = max(release1, hold1 + i) + hold1 = max(hold1, -i); + return release2 + +# Time: O(k * n) +# Space: O(k) +class Solution2: + # @param prices, a list of integer + # @return an integer + def maxProfit(self, prices): + return self.maxAtMostKPairsProfit(prices, 2) + + def maxAtMostKPairsProfit(self, prices, k): + max_buy = [float("-inf") for _ in xrange(k + 1)] + max_sell = [0 for _ in xrange(k + 1)] + + for i in xrange(len(prices)): + for j in xrange(1, min(k, i/2+1) + 1): + max_buy[j] = max(max_buy[j], max_sell[j-1] - prices[i]) + max_sell[j] = max(max_sell[j], max_buy[j] + prices[i]) + + return max_sell[k] + +# Time: O(n) +# Space: O(n) +class Solution3: # @param prices, a list of integer # @return an integer def maxProfit(self, prices): diff --git a/Python/best-time-to-buy-and-sell-stock-iv.py b/Python/best-time-to-buy-and-sell-stock-iv.py new file mode 100644 index 000000000..0235f07df --- /dev/null +++ b/Python/best-time-to-buy-and-sell-stock-iv.py @@ -0,0 +1,38 @@ +# Time: O(k * n) +# Space: O(k) +# +# Say you have an array for which the ith element is the price of a given stock on day i. +# +# Design an algorithm to find the maximum profit. You may complete at most k transactions. +# +# Note: +# You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). +# + +class Solution: + # @return an integer as the maximum profit + def maxProfit(self, k, prices): + if k >= len(prices) / 2: + return self.maxAtMostNPairsProfit(prices) + + return self.maxAtMostKPairsProfit(prices, k) + + def maxAtMostNPairsProfit(self, prices): + profit = 0 + for i in xrange(len(prices) - 1): + profit += max(0, prices[i + 1] - prices[i]) + return profit + + def maxAtMostKPairsProfit(self, prices, k): + max_buy = [float("-inf") for _ in xrange(k + 1)] + max_sell = [0 for _ in xrange(k + 1)] + + for i in xrange(len(prices)): + for j in xrange(1, min(k, i/2+1) + 1): + max_buy[j] = max(max_buy[j], max_sell[j-1] - prices[i]) + max_sell[j] = max(max_sell[j], max_buy[j] + prices[i]) + + return max_sell[k] + +if __name__ == "__main__": + print Solution().maxAtMostKPairsProfit([1, 2, 3, 4], 2) diff --git a/Python/best-time-to-buy-and-sell-stock-with-cooldown.py b/Python/best-time-to-buy-and-sell-stock-with-cooldown.py new file mode 100644 index 000000000..2e95e742b --- /dev/null +++ b/Python/best-time-to-buy-and-sell-stock-with-cooldown.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space: O(1) + +# Say you have an array for which the ith element is the price of a given stock on day i. +# +# Design an algorithm to find the maximum profit. You may complete as +# many transactions as you like (ie, buy one and sell one share of the +# stock multiple times) with the following restrictions: +# +# You may not engage in multiple transactions at the same time +# (ie, you must sell the stock before you buy again). +# After you sell your stock, you cannot buy stock on next day. +# (ie, cooldown 1 day) +# Example: +# +# prices = [1, 2, 3, 0, 2] +# maxProfit = 3 +# transactions = [buy, sell, cooldown, buy, sell] +# + +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + if not prices: + return 0 + buy, sell, coolDown = [0] * 2, [0] * 2, [0] * 2 + buy[0] = -prices[0] + for i in xrange(1, len(prices)): + # Bought before or buy today. + buy[i % 2] = max(buy[(i - 1) % 2], coolDown[(i - 1) % 2] - prices[i]) + # Sell today. + sell[i % 2] = buy[(i - 1) % 2] + prices[i] + # Sold before yesterday or sold yesterday. + coolDown[i % 2] = max(coolDown[(i - 1) % 2], sell[(i - 1) % 2]) + return max(coolDown[(len(prices) - 1) % 2], sell[(len(prices) - 1) % 2]) diff --git a/Python/binary-search-tree-iterator.py b/Python/binary-search-tree-iterator.py index c198f87ec..428c8d4a3 100644 --- a/Python/binary-search-tree-iterator.py +++ b/Python/binary-search-tree-iterator.py @@ -1,5 +1,5 @@ # Time: O(1) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Implement an iterator over a binary search tree (BST). # Your iterator will be initialized with the root node of a BST. @@ -47,4 +47,4 @@ def next(self): i, v = BSTIterator(root), [] while i.hasNext(): v.append(i.next()) - print v \ No newline at end of file + print v diff --git a/Python/binary-tree-inorder-traversal.py b/Python/binary-tree-inorder-traversal.py index 5972f569b..094ed428b 100644 --- a/Python/binary-tree-inorder-traversal.py +++ b/Python/binary-tree-inorder-traversal.py @@ -66,15 +66,30 @@ 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 return result +class Solution3: + # @param root, a tree node + # @return a list of integers + def inorderTraversal(self, root): + result, stack, current = [], [], root + while stack or current: + if current: + stack.append(current) + current = current.left + else: + current = stack.pop() + result.append(current.val) + current = current.right + return result + if __name__ == "__main__": root = TreeNode(1) root.right = TreeNode(2) root.right.left = TreeNode(3) result = Solution().inorderTraversal(root) - print result \ No newline at end of file + print result diff --git a/Python/binary-tree-longest-consecutive-sequence.py b/Python/binary-tree-longest-consecutive-sequence.py new file mode 100644 index 000000000..769c417ee --- /dev/null +++ b/Python/binary-tree-longest-consecutive-sequence.py @@ -0,0 +1,37 @@ +# Time: O(n) +# Space: O(h) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestConsecutive(self, root): + """ + :type root: TreeNode + :rtype: int + """ + self.max_len = 0 + + def longestConsecutiveHelper(root): + if not root: + return 0 + + left_len = longestConsecutiveHelper(root.left) + right_len = longestConsecutiveHelper(root.right) + + cur_len = 1 + if root.left and root.left.val == root.val + 1: + cur_len = max(cur_len, left_len + 1); + if root.right and root.right.val == root.val + 1: + cur_len = max(cur_len, right_len + 1) + + self.max_len = max(self.max_len, cur_len, left_len, right_len) + + return cur_len + + longestConsecutiveHelper(root) + return self.max_len diff --git a/Python/binary-tree-maximum-path-sum.py b/Python/binary-tree-maximum-path-sum.py index 2c2705aa1..d71f6eeba 100644 --- a/Python/binary-tree-maximum-path-sum.py +++ b/Python/binary-tree-maximum-path-sum.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, find the maximum path sum. # diff --git a/Python/binary-tree-paths.py b/Python/binary-tree-paths.py new file mode 100644 index 000000000..657e8d579 --- /dev/null +++ b/Python/binary-tree-paths.py @@ -0,0 +1,51 @@ +# Time: O(n * h) +# Space: O(h) +# +# Given a binary tree, return all root-to-leaf paths. +# +# For example, given the following binary tree: +# +# 1 +# / \ +# 2 3 +# \ +# 5 +# All root-to-leaf paths are: +# +# ["1->2->5", "1->3"] +# +# +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @return {string[]} + def binaryTreePaths(self, root): + result, path = [], [] + self.binaryTreePathsRecu(root, path, result) + return result + + def binaryTreePathsRecu(self, node, path, result): + if node is None: + return + + if node.left is node.right is None: + ans = "" + for n in path: + ans += str(n.val) + "->" + result.append(ans + str(node.val)) + + if node.left: + path.append(node) + self.binaryTreePathsRecu(node.left, path, result) + path.pop() + + if node.right: + path.append(node) + self.binaryTreePathsRecu(node.right, path, result) + path.pop() diff --git a/Python/binary-tree-preorder-traversal.py b/Python/binary-tree-preorder-traversal.py index 2cf998dcd..51146c7bd 100644 --- a/Python/binary-tree-preorder-traversal.py +++ b/Python/binary-tree-preorder-traversal.py @@ -70,9 +70,25 @@ def preorderTraversal(self, root): current = parent.right return result +class Solution3: + # @param root, a tree node + # @return a list of integers + def preorderTraversal(self, root): + result, stack, current, last_traversed = [], [], root, None + while stack or current: + if current: + result.append(current.val) + stack.append(current) + current = current.left + else: + current = stack[-1] + stack.pop() + current = current.right + return result + if __name__ == "__main__": root = TreeNode(1) root.right = TreeNode(2) root.right.left = TreeNode(3) result = Solution().preorderTraversal(root) - print result \ No newline at end of file + print result diff --git a/Python/binary-tree-right-side-view.py b/Python/binary-tree-right-side-view.py new file mode 100644 index 000000000..56d5e3db2 --- /dev/null +++ b/Python/binary-tree-right-side-view.py @@ -0,0 +1,73 @@ +# Time: O(n) +# Space: O(h) +# +# Given a binary tree, imagine yourself standing on the right side of it, +# return the values of the nodes you can see ordered from top to bottom. +# +# For example: +# Given the following binary tree, +# 1 <--- +# / \ +# 2 3 <--- +# \ \ +# 5 4 <--- +# You should return [1, 3, 4]. +# + +# Definition for a binary tree node +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution: + # @param root, a tree node + # @return a list of integers + def rightSideView(self, root): + result = [] + self.rightSideViewDFS(root, 1, result) + return result + + def rightSideViewDFS(self, node, depth, result): + if not node: + return + + if depth > len(result): + result.append(node.val) + + self.rightSideViewDFS(node.right, depth+1, result) + self.rightSideViewDFS(node.left, depth+1, result) + +# BFS solution +# Time: O(n) +# Space: O(n) +class Solution2: + # @param root, a tree node + # @return a list of integers + def rightSideView(self, root): + if root is None: + return [] + + result, current = [], [root] + while current: + next_level = [] + for i, node in enumerate(current): + if node.left: + next_level.append(node.left) + if node.right: + next_level.append(node.right) + if i == len(current) - 1: + result.append(node.val) + current = next_level + + return result + +if __name__ == "__main__": + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.right = TreeNode(5) + root.right.right = TreeNode(4) + result = Solution().rightSideView(root) + print result diff --git a/Python/binary-tree-vertical-order-traversal.py b/Python/binary-tree-vertical-order-traversal.py new file mode 100644 index 000000000..8dd332ee4 --- /dev/null +++ b/Python/binary-tree-vertical-order-traversal.py @@ -0,0 +1,26 @@ +# Time: O(n) +# Space: O(n) + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# BFS + hash solution. +class Solution(object): + def verticalOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + """ + cols = collections.defaultdict(list) + queue = [(root, 0)] + for node, i in queue: + if node: + cols[i].append(node.val) + queue += (node.left, i - 1), (node.right, i + 1) + return [cols[i] for i in xrange(min(cols.keys()), max(cols.keys()) + 1)] \ + if cols else [] diff --git a/Python/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 5b55c29a4..f1b27c374 100644 --- a/Python/count-and-say.py +++ b/Python/count-and-say.py @@ -1,5 +1,5 @@ -# Time: O(n^2) -# Space: O(n) +# Time: O(n * 2^n) +# Space: O(2^n) # # The count-and-say sequence is the sequence of integers beginning as follows: # 1, 11, 21, 1211, 111221, ... @@ -27,7 +27,7 @@ def getNext(self, seq): while i < len(seq) - 1 and seq[i] == seq[i + 1]: cnt += 1 i += 1 - next_seq += "{}{}".format(cnt, seq[i]) + next_seq += str(cnt) + seq[i] i += 1 return next_seq diff --git a/Python/count-complete-tree-nodes.py b/Python/count-complete-tree-nodes.py new file mode 100644 index 000000000..24695387b --- /dev/null +++ b/Python/count-complete-tree-nodes.py @@ -0,0 +1,56 @@ +# Time: O(h * logn) = O((logn)^2) +# Space: O(1) + +# Given a complete binary tree, count the number of nodes. +# +# In a complete binary tree every level, except possibly the last, +# is completely filled, and all nodes in the last level are as far +# left as possible. It can have between 1 and 2h nodes inclusive at +# the last level h. +# + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + # @param {TreeNode} root + # @return {integer} + def countNodes(self, root): + if root is None: + return 0 + + node, level = root, 0 + while node.left is not None: + node = node.left + level += 1 + + # Binary search. + left, right = 2 ** level, 2 ** (level + 1) + while left < right: + mid = left + (right - left) / 2 + if not self.exist(root, mid): + right = mid + else: + left = mid + 1 + + return left - 1 + + # Check if the nth node exist. + def exist(self, root, n): + k = 1 + while k <= n: + k <<= 1 + k >>= 2 + + node = root + while k > 0: + if (n & k) == 0: + node = node.left + else: + node = node.right + k >>= 1 + return node is not None diff --git a/Python/count-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/first-missing-positive.py b/Python/first-missing-positive.py index b2fa788f0..134baa714 100644 --- a/Python/first-missing-positive.py +++ b/Python/first-missing-positive.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(n) +# Space: O(1) # # Given an unsorted integer array, find the first missing positive integer. # @@ -28,4 +28,4 @@ def firstMissingPositive(self, A): if __name__ == "__main__": print Solution().firstMissingPositive([1,2,0]) - print Solution().firstMissingPositive([3,4,-1,1]) \ No newline at end of file + print Solution().firstMissingPositive([3,4,-1,1]) diff --git a/Python/flatten-2d-vector.py b/Python/flatten-2d-vector.py new file mode 100644 index 000000000..7b40db259 --- /dev/null +++ b/Python/flatten-2d-vector.py @@ -0,0 +1,32 @@ +# Time: O(1) +# Space: O(1) + +class Vector2D: + x, y = 0, 0 + vec = None + + # Initialize your data structure here. + # @param {integer[][]} vec2d + def __init__(self, vec2d): + self.vec = vec2d + self.x = 0 + if self.x != len(self.vec): + self.y = 0 + self.adjustNextIter() + + # @return {integer} + def next(self): + ret = self.vec[self.x][self.y] + self.y += 1 + self.adjustNextIter() + return ret + + # @return {boolean} + def hasNext(self): + return self.x != len(self.vec) and self.y != len(self.vec[self.x]) + + def adjustNextIter(self): + while self.x != len(self.vec) and self.y == len(self.vec[self.x]): + self.x += 1 + if self.x != len(self.vec): + self.y = 0 diff --git a/Python/flatten-binary-tree-to-linked-list.py b/Python/flatten-binary-tree-to-linked-list.py index 8d081290a..579f2e319 100644 --- a/Python/flatten-binary-tree-to-linked-list.py +++ b/Python/flatten-binary-tree-to-linked-list.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, flatten it to a linked list in-place. # @@ -74,4 +74,4 @@ def flatten(self, root): print result.right.right.val print result.right.right.right.val print result.right.right.right.right.val - print result.right.right.right.right.right.val \ No newline at end of file + print result.right.right.right.right.right.val diff --git a/Python/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 543835dd4..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): - if len(haystack) < len(needle): - return None - - if len(needle) == 0: - return haystack - - i = self.KMP(haystack, needle) - if i > -1: - return haystack[i:] - else: - return None + """ + :type haystack: str + :type needle: str + :rtype: int + """ + if not needle: + return 0 + + return self.KMP(haystack, needle) def KMP(self, text, pattern): prefix = self.getPrefix(pattern) @@ -40,7 +35,7 @@ def KMP(self, text, pattern): def getPrefix(self, pattern): prefix = [-1] * len(pattern) - j = - 1 + j = -1 for i in xrange(1, len(pattern)): while j > -1 and pattern[j + 1] != pattern[i]: j = prefix[j] @@ -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/insert-interval.py b/Python/insert-interval.py index f108a7078..82e27eb9a 100644 --- a/Python/insert-interval.py +++ b/Python/insert-interval.py @@ -31,11 +31,11 @@ def insert(self, intervals, newInterval): return self.merge(intervals + [newInterval]) def merge(self, intervals): - if len(intervals) == 0: + if not intervals: return intervals intervals.sort(key = lambda x: x.start) result = [intervals[0]] - for i in range(1, len(intervals)): + for i in xrange(1, len(intervals)): prev, current = result[-1], intervals[i] if current.start <= prev.end: prev.end = max(prev.end, current.end) @@ -44,4 +44,4 @@ def merge(self, intervals): return result if __name__ == "__main__": - print Solution().insert([Interval(1, 2), Interval(3, 5), Interval(6, 7), Interval(8, 10), Interval(12, 16)], Interval(4, 9)) \ No newline at end of file + print Solution().insert([Interval(1, 2), Interval(3, 5), Interval(6, 7), Interval(8, 10), Interval(12, 16)], Interval(4, 9)) diff --git a/Python/integer-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/largest-rectangle-in-histogram.py b/Python/largest-rectangle-in-histogram.py index 2313b011f..e3dea568b 100644 --- a/Python/largest-rectangle-in-histogram.py +++ b/Python/largest-rectangle-in-histogram.py @@ -16,12 +16,12 @@ class Solution: def largestRectangleArea(self, height): increasing, area, i = [], 0, 0 while i <= len(height): - if len(increasing) == 0 or (i < len(height) and height[i] > height[increasing[-1]]): + if not increasing or (i < len(height) and height[i] > height[increasing[-1]]): increasing.append(i) i += 1 else: last = increasing.pop() - if len(increasing) == 0: + if not increasing: area = max(area, height[last] * i) else: area = max(area, height[last] * (i - increasing[-1] - 1 )) @@ -30,4 +30,4 @@ def largestRectangleArea(self, height): if __name__ == "__main__": print Solution().largestRectangleArea([2, 0, 2]) print Solution().largestRectangleArea([2, 1, 5, 6, 2, 3]) - \ No newline at end of file + diff --git a/Python/letter-combinations-of-a-phone-number.py b/Python/letter-combinations-of-a-phone-number.py index a818ce42b..c876137ca 100644 --- a/Python/letter-combinations-of-a-phone-number.py +++ b/Python/letter-combinations-of-a-phone-number.py @@ -1,5 +1,5 @@ -# Time: O(4^n) -# Space: O(1) +# Time: O(n * 4^n) +# Space: O(n) # # Given a digit string, return all possible letter combinations that the number could represent. # @@ -17,25 +17,33 @@ class Solution: # @return a list of strings, [s1, s2] def letterCombinations(self, digits): - lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"], [""] + if not digits: + return [] + + lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", \ + "pqrs", "tuv", "wxyz"], [""] - for digit in digits: + for digit in reversed(digits): choices = lookup[int(digit)] m, n = len(choices), len(result) - result.extend([result[i % n] for i in xrange(n, m * n)]) + result += [result[i % n] for i in xrange(n, m * n)] for i in xrange(m * n): - result[i] += choices[i / n] + result[i] = choices[i / n] + result[i] return result -# Time: O(4^n) + +# Time: O(n * 4^n) # Space: O(n) # Recursive Solution class Solution2: # @return a list of strings, [s1, s2] def letterCombinations(self, digits): - lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"], [] + if not digits: + return [] + lookup, result = ["", "", "abc", "def", "ghi", "jkl", "mno", \ + "pqrs", "tuv", "wxyz"], [] self.letterCombinationsRecu(result, digits, lookup, "", 0) return result diff --git a/Python/longest-common-prefix.py b/Python/longest-common-prefix.py index 2ffa96cfb..f5a918469 100644 --- a/Python/longest-common-prefix.py +++ b/Python/longest-common-prefix.py @@ -1,22 +1,24 @@ -# Time: O(n1 + n2 + ...) +# Time: O(n * k), k is the length of the common prefix # Space: O(1) -# -# Write a function to find the longest common prefix string amongst an array of strings. -# -class Solution: - # @return a string +# Write a function to find the longest common prefix string +# amongst an array of strings. + +class Solution(object): def longestCommonPrefix(self, strs): - if len(strs) == 0: + """ + :type strs: List[str] + :rtype: str + """ + if not strs: return "" - longest = strs[0] - for string in strs[1:]: - i = 0 - while i < len(string) and i < len(longest) and string[i] == longest[i]: - i += 1 - longest = longest[:i] - return longest - + + for i in xrange(len(strs[0])): + for string in strs[1:]: + if i >= len(string) or string[i] != strs[0][i]: + return strs[0][:i] + return strs[0] + + if __name__ == "__main__": print Solution().longestCommonPrefix(["hello", "heaven", "heavy"]) - \ No newline at end of file diff --git a/Python/longest-increasing-path-in-a-matrix.py b/Python/longest-increasing-path-in-a-matrix.py new file mode 100644 index 000000000..f5685d3a7 --- /dev/null +++ b/Python/longest-increasing-path-in-a-matrix.py @@ -0,0 +1,60 @@ +# Time: O(m * n) +# Space: O(m * n) + +# Given an integer matrix, find the length of the longest increasing path. +# +# From each cell, you can either move to four directions: left, right, up +# or down. You may NOT move diagonally or move outside of the boundary +# (i.e. wrap-around is not allowed). +# +# Example 1: +# +# nums = [ +# [9,9,4], +# [6,6,8], +# [2,1,1] +# ] +# Return 4 +# The longest increasing path is [1, 2, 6, 9]. +# +# Example 2: +# +# nums = [ +# [3,4,5], +# [3,2,6], +# [2,2,1] +# ] +# Return 4 +# The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed. + +# DFS + Memorization solution. +class Solution(object): + def longestIncreasingPath(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: int + """ + if not matrix: + return 0 + + def longestpath(matrix, i, j, max_lengths): + if max_lengths[i][j]: + return max_lengths[i][j] + + max_depth = 0 + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + for d in directions: + x, y = i + d[0], j + d[1] + if 0 <= x < len(matrix) and 0 <= y < len(matrix[0]) and \ + matrix[x][y] < matrix[i][j]: + max_depth = max(max_depth, longestpath(matrix, x, y, max_lengths)); + max_lengths[i][j] = max_depth + 1 + return max_lengths[i][j] + + res = 0 + max_lengths = [[0 for _ in xrange(len(matrix[0]))] for _ in xrange(len(matrix))] + for i in xrange(len(matrix)): + for j in xrange(len(matrix[0])): + res = max(res, longestpath(matrix, i, j, max_lengths)) + + return res diff --git a/Python/longest-increasing-subsequence.py b/Python/longest-increasing-subsequence.py new file mode 100644 index 000000000..596fffaaf --- /dev/null +++ b/Python/longest-increasing-subsequence.py @@ -0,0 +1,61 @@ +# Time: O(nlogn) +# Space: O(n) +# +# Given an unsorted array of integers, +# find the length of longest increasing subsequence. +# +# For example, +# Given [10, 9, 2, 5, 3, 7, 101, 18], +# The longest increasing subsequence is [2, 3, 7, 101], +# therefore the length is 4. Note that there may be more +# than one LIS combination, it is only necessary for you to return the length. +# +# Your algorithm should run in O(n2) complexity. +# +# Follow up: Could you improve it to O(n log n) time complexity? +# + +# Binary search solution. +class Solution(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + LIS = [] + def insert(target): + left, right = 0, len(LIS) - 1 + # Find the first index "left" which satisfies LIS[left] >= target + while left <= right: + mid = left + (right - left) / 2; + if LIS[mid] >= target: + right = mid - 1 + else: + left = mid + 1 + # If not found, append the target. + if left == len(LIS): + LIS.append(target); + else: + LIS[left] = target + + for num in nums: + insert(num) + + return len(LIS) + +# Time: O(n^2) +# Space: O(n) +# Traditional DP solution. +class Solution2(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + dp = [] # dp[i]: the length of LIS ends with nums[i] + for i in xrange(len(nums)): + dp.append(1) + for j in xrange(i): + if nums[j] < nums[i]: + dp[i] = max(dp[i], dp[j] + 1) + return max(dp) if dp else 0 diff --git a/Python/longest-palindromic-substring.py b/Python/longest-palindromic-substring.py index e882d6bf6..2c0f238d9 100644 --- a/Python/longest-palindromic-substring.py +++ b/Python/longest-palindromic-substring.py @@ -8,40 +8,44 @@ # Manacher's Algorithm # http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html -class Solution: +class Solution(object): def longestPalindrome(self, s): - string = self.preProcess(s) - palindrome = [0] * len(string) + """ + :type s: str + :rtype: str + """ + def preProcess(s): + if not s: + return ['^', '$'] + T = ['^'] + for c in s: + T += ['#', c] + T += ['#', '$'] + return T + + T = preProcess(s) + P = [0] * len(T) center, right = 0, 0 - for i in xrange(1, len(string) - 1): + for i in xrange(1, len(T) - 1): i_mirror = 2 * center - i if right > i: - palindrome[i] = min(right - i, palindrome[i_mirror]) + P[i] = min(right - i, P[i_mirror]) else: - palindrome[i] = 0 + P[i] = 0 - while string[i + 1 + palindrome[i]] == string[i - 1 - palindrome[i]]: - palindrome[i] += 1 + while T[i + 1 + P[i]] == T[i - 1 - P[i]]: + P[i] += 1 - if i + palindrome[i] > right: - center, right = i, i + palindrome[i] + if i + P[i] > right: + center, right = i, i + P[i] - max_len, max_center = 0, 0 - for i in xrange(1, len(string) - 1): - if palindrome[i] > max_len: - max_len = palindrome[i] - max_center = i - start = (max_center - 1 - max_len) / 2 - return s[start : start + max_len] - - def preProcess(self, s): - if len(s) == 0: - return "^$" - string = "^" - for i in s: - string += "#" + i - string += "#$" - return string + max_i = 0 + for i in xrange(1, len(T) - 1): + if P[i] > P[max_i]: + max_i = i + start = (max_i - 1 - P[max_i]) / 2 + return s[start : start + P[max_i]] + if __name__ == "__main__": - print Solution().longestPalindrome("abb") \ No newline at end of file + print Solution().longestPalindrome("abb") diff --git a/Python/longest-valid-parentheses.py b/Python/longest-valid-parentheses.py index 8d8b1647e..dd0376eb8 100644 --- a/Python/longest-valid-parentheses.py +++ b/Python/longest-valid-parentheses.py @@ -9,35 +9,28 @@ # Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4. # -class Solution: - # @param s, a string - # @return an integer +class Solution(object): def longestValidParentheses(self, s): - longest = 0 - - start, depth = -1, 0 - for i in xrange(len(s)): - if s[i] == "(": - depth += 1 - else: - depth -= 1 - if depth < 0: - start, depth = i, 0 - elif depth == 0: - longest = max(longest, i - start) - - start, depth = len(s), 0 - for i in reversed(xrange(len(s))): - if s[i] == ")": - depth += 1 - else: - depth -= 1 - if depth < 0: - start, depth = i, 0 - elif depth == 0: - longest = max(longest, start - i) - - return longest + """ + :type s: str + :rtype: int + """ + def length(it, start, c): + depth, longest = 0, 0 + for i in it: + if s[i] == c: + depth += 1 + else: + depth -= 1 + if depth < 0: + start, depth = i, 0 + elif depth == 0: + longest = max(longest, abs(i - start)) + return longest + + return max(length(xrange(len(s)), -1, '('), \ + length(reversed(xrange(len(s))), len(s), ')')) + # Time: O(n) # Space: O(n) @@ -49,11 +42,11 @@ def longestValidParentheses(self, s): for i in xrange(len(s)): if s[i] == '(': indices.append(i) - elif len(indices) == 0: + elif not indices: last = i else: indices.pop() - if len(indices) == 0: + if not indices: longest = max(longest, i - last) else: longest = max(longest, i - indices[-1]) diff --git a/Python/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-rectangle.py b/Python/maximal-rectangle.py index 05a99c943..f667a4de2 100644 --- a/Python/maximal-rectangle.py +++ b/Python/maximal-rectangle.py @@ -9,7 +9,7 @@ class Solution: # @param matrix, a list of lists of 1 length string # @return an integer def maximalRectangle(self, matrix): - if len(matrix) == 0: + if not matrix: return 0 result = 0 diff --git a/Python/maximal-square.py b/Python/maximal-square.py new file mode 100644 index 000000000..2f95f9b99 --- /dev/null +++ b/Python/maximal-square.py @@ -0,0 +1,127 @@ +# Time: O(n^2) +# Space: O(n) +# +# Given a 2D binary matrix filled with 0's and 1's, +# find the largest square containing all 1's and return its area. +# +# For example, given the following matrix: +# +# 1 0 1 0 0 +# 1 0 1 1 1 +# 1 1 1 1 1 +# 1 0 0 1 0 +# Return 4. +# + +# DP with sliding window. +class Solution: + # @param {character[][]} matrix + # @return {integer} + def maximalSquare(self, matrix): + if not matrix: + return 0 + + m, n = len(matrix), len(matrix[0]) + size = [[0 for j in xrange(n)] for i in xrange(2)] + max_size = 0 + + for j in xrange(n): + if matrix[0][j] == '1': + size[0][j] = 1 + max_size = max(max_size, size[0][j]) + + for i in xrange(1, m): + if matrix[i][0] == '1': + size[i % 2][0] = 1 + else: + size[i % 2][0] = 0 + for j in xrange(1, n): + if matrix[i][j] == '1': + size[i % 2][j] = min(size[i % 2][j - 1], \ + size[(i - 1) % 2][j], \ + size[(i - 1) % 2][j - 1]) + 1 + max_size = max(max_size, size[i % 2][j]) + else: + size[i % 2][j] = 0 + + return max_size * max_size + + +# Time: O(n^2) +# Space: O(n^2) +# DP. +class Solution2: + # @param {character[][]} matrix + # @return {integer} + def maximalSquare(self, matrix): + if not matrix: + return 0 + + m, n = len(matrix), len(matrix[0]) + size = [[0 for j in xrange(n)] for i in xrange(m)] + max_size = 0 + + for j in xrange(n): + if matrix[0][j] == '1': + size[0][j] = 1 + max_size = max(max_size, size[0][j]) + + for i in xrange(1, m): + if matrix[i][0] == '1': + size[i][0] = 1 + else: + size[i][0] = 0 + for j in xrange(1, n): + if matrix[i][j] == '1': + size[i][j] = min(size[i][j - 1], \ + size[i - 1][j], \ + size[i - 1][j - 1]) + 1 + max_size = max(max_size, size[i][j]) + else: + size[i][j] = 0 + + return max_size * max_size + + +# Time: O(n^2) +# Space: O(n^2) +# DP. +class Solution3: + # @param {character[][]} matrix + # @return {integer} + def maximalSquare(self, matrix): + if not matrix: + return 0 + + H, W = 0, 1 + # DP table stores (h, w) for each (i, j). + table = [[[0, 0] for j in xrange(len(matrix[0]))] \ + for i in xrange(len(matrix))] + for i in reversed(xrange(len(matrix))): + for j in reversed(xrange(len(matrix[i]))): + # Find the largest h such that (i, j) to (i + h - 1, j) are feasible. + # Find the largest w such that (i, j) to (i, j + w - 1) are feasible. + if matrix[i][j] == '1': + h, w = 1, 1 + if i + 1 < len(matrix): + h = table[i + 1][j][H] + 1 + if j + 1 < len(matrix[i]): + w = table[i][j + 1][W] + 1 + table[i][j] = [h, w] + + # A table stores the length of largest square for each (i, j). + s = [[0 for j in xrange(len(matrix[0]))] \ + for i in xrange(len(matrix))] + max_square_area = 0 + for i in reversed(xrange(len(matrix))): + for j in reversed(xrange(len(matrix[i]))): + side = min(table[i][j][H], table[i][j][W]) + if matrix[i][j] == '1': + # Get the length of largest square with bottom-left corner (i, j). + if i + 1 < len(matrix) and j + 1 < len(matrix[i + 1]): + side = min(s[i + 1][j + 1] + 1, side) + s[i][j] = side + max_square_area = max(max_square_area, side * side) + + return max_square_area; + diff --git a/Python/maximum-depth-of-binary-tree.py b/Python/maximum-depth-of-binary-tree.py index 14c258da1..016f720a6 100644 --- a/Python/maximum-depth-of-binary-tree.py +++ b/Python/maximum-depth-of-binary-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, find its maximum depth. # @@ -27,4 +27,4 @@ def maxDepth(self, root): root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) - print Solution().maxDepth(root) \ No newline at end of file + print Solution().maxDepth(root) diff --git a/Python/maximum-gap.py b/Python/maximum-gap.py index 6bc30d14f..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 47f6c6862..24b51a481 100644 --- a/Python/median-of-two-sorted-arrays.py +++ b/Python/median-of-two-sorted-arrays.py @@ -1,11 +1,85 @@ -# Time: O(log(m + n)) -# Space: 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. # Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). # class Solution: + # @return a float + def findMedianSortedArrays(self, A, B): + lenA, lenB = len(A), len(B) + if (lenA + lenB) % 2 == 1: + return self.getKth(A, 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): + 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) + while b < t: + x = b + (t - b) / 2 + A_x_1, A_x, B_k_x_1, B_k_x = float("-inf"), float("inf"), float("-inf"), float("inf") + if x > 0: + A_x_1 = A[x - 1] + if x < len(A): + A_x = A[x] + if k - x > 0: + B_k_x_1 = B[k - x - 1] + if k - x < len(B): + B_k_x = B[k - x] + + if A_x < B_k_x_1: + b = x + 1 + elif A_x_1 > B_k_x: + t = x - 1 + else: + return max(A_x_1, B_k_x_1) + + A_b_1, B_k_b_1 = float("-inf"), float("-inf") + if b > 0: + A_b_1 = A[b - 1] + if k - b - 1 >= 0: + B_k_b_1 = B[k - b - 1] + + return max(A_b_1, B_k_b_1) + +# Time: O(log(m + n)) +# Space: O(log(m + n)) +class Solution3: # @return a float def findMedianSortedArrays(self, A, B): lenA, lenB = len(A), len(B) @@ -35,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 Solution2: +# 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) @@ -69,4 +143,4 @@ def getKth(self, A, B, k): if __name__ == "__main__": print Solution().findMedianSortedArrays([1, 3, 5, 7], [2, 4, 6]) print Solution().findMedianSortedArrays([1, 3, 5], [2, 4, 6]) - \ No newline at end of file + diff --git a/Python/meeting-rooms-ii.py b/Python/meeting-rooms-ii.py new file mode 100644 index 000000000..5d6903447 --- /dev/null +++ b/Python/meeting-rooms-ii.py @@ -0,0 +1,34 @@ +# Time: O(nlogn) +# Space: O(n) + +# Definition for an interval. +# class Interval: +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution: + # @param {Interval[]} intervals + # @return {integer} + def minMeetingRooms(self, intervals): + starts, ends = [], [] + for i in intervals: + starts.append(i.start) + ends.append(i.end) + + starts.sort() + ends.sort() + + s, e = 0, 0 + min_rooms, cnt_rooms = 0, 0 + while s < len(starts): + if starts[s] < ends[e]: + cnt_rooms += 1 # Acquire a room. + # Update the min number of rooms. + min_rooms = max(min_rooms, cnt_rooms) + s += 1 + else: + cnt_rooms -= 1 # Release a room. + e += 1 + + return min_rooms diff --git a/Python/meeting-rooms.py b/Python/meeting-rooms.py new file mode 100644 index 000000000..f8ef52f66 --- /dev/null +++ b/Python/meeting-rooms.py @@ -0,0 +1,19 @@ +# Time: O(nlogn) +# Space: O(n) +# +# Definition for an interval. +# class Interval: +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution: + # @param {Interval[]} intervals + # @return {boolean} + def canAttendMeetings(self, intervals): + intervals.sort(key=lambda x: x.start) + + for i in xrange(1, len(intervals)): + if intervals[i].start < intervals[i-1].end: + return False + return True diff --git a/Python/merge-intervals.py b/Python/merge-intervals.py index 49641bb7d..f62b3f0a1 100644 --- a/Python/merge-intervals.py +++ b/Python/merge-intervals.py @@ -1,4 +1,4 @@ -# Time: O(n^2) +# Time: O(nlogn) # Space: O(1) # # Given a collection of intervals, merge all overlapping intervals. @@ -21,7 +21,7 @@ class Solution: # @param intervals, a list of Interval # @return a list of Interval def merge(self, intervals): - if len(intervals) == 0: + if not intervals: return intervals intervals.sort(key = lambda x: x.start) result = [intervals[0]] 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/min-stack.py b/Python/min-stack.py index 4036555b5..12df16163 100644 --- a/Python/min-stack.py +++ b/Python/min-stack.py @@ -17,7 +17,7 @@ def __init__(self): # @param x, an integer # @return an integer def push(self, x): - if len(self.stack) == 0: + if not self.stack: self.stack.append(0) self.min = x else: @@ -80,4 +80,4 @@ def getMin(self): stack = MinStack() stack.push(-1) print [stack.top(), stack.getMin()] - \ No newline at end of file + diff --git a/Python/minimum-depth-of-binary-tree.py b/Python/minimum-depth-of-binary-tree.py index 5494074ec..2833dcaab 100644 --- a/Python/minimum-depth-of-binary-tree.py +++ b/Python/minimum-depth-of-binary-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree, find its minimum depth. # @@ -28,4 +28,4 @@ def minDepth(self, root): if __name__ == "__main__": root = TreeNode(1) root.left = TreeNode(2) - print Solution().minDepth(root) \ No newline at end of file + print Solution().minDepth(root) diff --git a/Python/minimum-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/minimum-window-substring.py b/Python/minimum-window-substring.py index 37a001902..687402e30 100644 --- a/Python/minimum-window-substring.py +++ b/Python/minimum-window-substring.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(1) +# Space: O(k), k is the number of different characters # # Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). # 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/path-sum-ii.py b/Python/path-sum-ii.py index a6e835dcb..df35acde8 100644 --- a/Python/path-sum-ii.py +++ b/Python/path-sum-ii.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. # @@ -51,4 +51,4 @@ def pathSumRecu(self, result, cur, root, sum): if __name__ == "__main__": root = TreeNode(5) - print Solution().pathSum(root, 5) \ No newline at end of file + print Solution().pathSum(root, 5) diff --git a/Python/path-sum.py b/Python/path-sum.py index 0f686ec7f..b24c951a1 100644 --- a/Python/path-sum.py +++ b/Python/path-sum.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree and a sum, determine if the tree has a root-to-leaf path # such that adding up all the values along the path equals the given sum. @@ -42,4 +42,4 @@ def hasPathSum(self, root, sum): root.right = TreeNode(8) root.left.left = TreeNode(11) root.left.left.right = TreeNode(2) - print Solution().hasPathSum(root, 22) \ No newline at end of file + print Solution().hasPathSum(root, 22) diff --git a/Python/peeking-iterator.py b/Python/peeking-iterator.py new file mode 100644 index 000000000..f21db1fa3 --- /dev/null +++ b/Python/peeking-iterator.py @@ -0,0 +1,83 @@ +# Time: O(1) per peek(), next(), hasNext() +# Space: O(1) + +# Given an Iterator class interface with methods: next() and hasNext(), +# design and implement a PeekingIterator that support the peek() operation -- +# it essentially peek() at the element that will be returned by the next call to next(). +# +# Here is an example. Assume that the iterator is initialized to the beginning of +# the list: [1, 2, 3]. +# +# Call next() gets you 1, the first element in the list. +# +# Now you call peek() and it returns 2, the next element. Calling next() after that +# still return 2. +# +# You call next() the final time and it returns 3, the last element. Calling hasNext() +# after that should return false. +# + +# Below is the interface for Iterator, which is already defined for you. +# +# class Iterator(object): +# def __init__(self, nums): +# """ +# Initializes an iterator object to the beginning of a list. +# :type nums: List[int] +# """ +# +# def hasNext(self): +# """ +# Returns true if the iteration has more elements. +# :rtype: bool +# """ +# +# def next(self): +# """ +# Returns the next element in the iteration. +# :rtype: int +# """ + +class PeekingIterator(object): + def __init__(self, iterator): + """ + Initialize your data structure here. + :type iterator: Iterator + """ + self.iterator = iterator + self.val_ = None + self.has_next_ = iterator.hasNext() + self.has_peeked_ = False + + + def peek(self): + """ + Returns the next element in the iteration without advancing the iterator. + :rtype: int + """ + if not self.has_peeked_: + self.has_peeked_ = True + self.val_ = self.iterator.next() + return self.val_; + + def next(self): + """ + :rtype: int + """ + self.val_ = self.peek() + self.has_peeked_ = False + self.has_next_ = self.iterator.hasNext() + return self.val_; + + def hasNext(self): + """ + :rtype: bool + """ + return self.has_next_ + + +# Your PeekingIterator object will be instantiated and called as such: +# iter = PeekingIterator(Iterator(nums)) +# while iter.hasNext(): +# val = iter.peek() # Get the next element but not advance the iterator. +# iter.next() # Should return the same value as [val]. diff --git a/Python/perfect-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/populating-next-right-pointers-in-each-node.py b/Python/populating-next-right-pointers-in-each-node.py index 5223f28fb..79b50a7d8 100644 --- a/Python/populating-next-right-pointers-in-each-node.py +++ b/Python/populating-next-right-pointers-in-each-node.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(1) # # Given a binary tree # @@ -45,6 +45,23 @@ def __repr__(self): return "{} -> {}".format(self.val, repr(self.next)) class Solution: + # @param root, a tree node + # @return nothing + def connect(self, root): + head = root + while head: + prev, cur, next_head = None, head, None + while cur and cur.left: + cur.left.next = cur.right + if cur.next: + cur.right.next = cur.next.left + cur = cur.next + head = head.left + +# Time: O(n) +# Space: O(logn) +# recusion +class Solution2: # @param root, a tree node # @return nothing def connect(self, root): @@ -64,4 +81,4 @@ def connect(self, root): print root print root.left print root.left.left - \ No newline at end of file + diff --git a/Python/power-of-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 f6c6d2746..3101c52c7 100644 --- a/Python/regular-expression-matching.py +++ b/Python/regular-expression-matching.py @@ -40,7 +40,7 @@ def isMatch(self, s, p): if p[j-1] != '*': result[i % k][j] = result[(i-1) % k][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.') else: - result[i % k][j] = result[i % k][j-2] or (result[(i-1) % k][j] and (s[i-1] == p[j-2] or p[j-2]=='.')) + result[i % k][j] = result[i % k][j-2] or (result[(i-1) % k][j] and (s[i-1] == p[j-2] or p[j-2] == '.')) return result[len(s) % k][len(p)] @@ -62,19 +62,53 @@ def isMatch(self, s, p): if p[j-1] != '*': result[i][j] = result[i-1][j-1] and (s[i-1] == p[j-1] or p[j-1] == '.') else: - result[i][j] = result[i][j-2] or (result[i-1][j] and (s[i-1] == p[j-2] or p[j-2]=='.')) + result[i][j] = result[i][j-2] or (result[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.')) return result[len(s)][len(p)] -# recursive +# iteration class Solution3: # @return a boolean def isMatch(self, s, p): - if len(p) == 0: - return len(s) == 0 + p_ptr, s_ptr, last_s_ptr, last_p_ptr = 0, 0, -1, -1 + last_ptr = [] + while s_ptr < len(s): + if p_ptr < len(p) and (p_ptr == len(p) - 1 or p[p_ptr + 1] != '*') and \ + (s_ptr < len(s) and (p[p_ptr] == s[s_ptr] or p[p_ptr] == '.')): + s_ptr += 1 + p_ptr += 1 + elif p_ptr < len(p) - 1 and (p_ptr != len(p) - 1 and p[p_ptr + 1] == '*'): + p_ptr += 2 + last_ptr.append([s_ptr, p_ptr]) + elif last_ptr: + [last_s_ptr, last_p_ptr] = last_ptr.pop() + while last_ptr and p[last_p_ptr - 2] != s[last_s_ptr] and p[last_p_ptr - 2] != '.': + [last_s_ptr, last_p_ptr] = last_ptr.pop() + + if p[last_p_ptr - 2] == s[last_s_ptr] or p[last_p_ptr - 2] == '.': + last_s_ptr += 1 + s_ptr = last_s_ptr + p_ptr = last_p_ptr + last_ptr.append([s_ptr, p_ptr]) + else: + return False + else: + return False + + while p_ptr < len(p) - 1 and p[p_ptr] == '.' and p[p_ptr + 1] == '*': + p_ptr += 2 + + return p_ptr == len(p) + +# recursive +class Solution4: + # @return a boolean + def isMatch(self, s, p): + if not p: + return not s if len(p) == 1 or p[1] != '*': - if len(s) == 0 or (p[0] == s[0] or p[0] == '.'): + if len(s) > 0 and (p[0] == s[0] or p[0] == '.'): return self.isMatch(s[1:], p[1:]) else: return False @@ -86,7 +120,7 @@ def isMatch(self, s, p): return self.isMatch(s, p[2:]) if __name__ == "__main__": - print Solution().isMatch("abcd","d*") + print Solution3().isMatch("abab", "a*b*") print Solution().isMatch("aaaaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*c") print Solution().isMatch("aa","a") print Solution().isMatch("aa","aa") diff --git a/Python/remove-duplicate-letters.py b/Python/remove-duplicate-letters.py new file mode 100644 index 000000000..552643870 --- /dev/null +++ b/Python/remove-duplicate-letters.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(k), k is size of the alphabet + +# Given a string which contains only lowercase letters, +# remove duplicate letters so that every letter appear +# once and only once. You must make sure your result is +# the smallest in lexicographical order among all +# possible results. +# +# Example: +# Given "bcabc" +# Return "abc" +# +# Given "cbacdcbc" +# Return "acdb" + +class Solution(object): + def removeDuplicateLetters(self, s): + """ + :type s: str + :rtype: str + """ + remaining = collections.defaultdict(int) + for c in s: + remaining[c] += 1 + + in_stack, stk = set(), [] + for c in s: + if c not in in_stack: + while stk and stk[-1] > c and remaining[stk[-1]]: + in_stack.remove(stk.pop()) + stk += c + in_stack.add(c) + remaining[c] -= 1 + return "".join(stk) diff --git a/Python/remove-duplicates-from-sorted-array-ii.py b/Python/remove-duplicates-from-sorted-array-ii.py index 527416e7f..794b192ae 100644 --- a/Python/remove-duplicates-from-sorted-array-ii.py +++ b/Python/remove-duplicates-from-sorted-array-ii.py @@ -14,7 +14,7 @@ class Solution: # @param a list of integers # @return an integer def removeDuplicates(self, A): - if len(A) == 0: + if not A: return 0 last, i, same = 0, 1, False @@ -28,4 +28,4 @@ def removeDuplicates(self, A): return last + 1 if __name__ == "__main__": - print Solution().removeDuplicates([1, 1, 1, 2, 2, 3]) \ No newline at end of file + print Solution().removeDuplicates([1, 1, 1, 2, 2, 3]) diff --git a/Python/remove-duplicates-from-sorted-array.py b/Python/remove-duplicates-from-sorted-array.py index 473e645fc..7ea358680 100644 --- a/Python/remove-duplicates-from-sorted-array.py +++ b/Python/remove-duplicates-from-sorted-array.py @@ -15,7 +15,7 @@ class Solution: # @param a list of integers # @return an integer def removeDuplicates(self, A): - if len(A) == 0: + if not A: return 0 last, i = 0, 1 @@ -28,4 +28,4 @@ def removeDuplicates(self, A): return last + 1 if __name__ == "__main__": - print Solution().removeDuplicates([1, 1, 2]) \ No newline at end of file + print Solution().removeDuplicates([1, 1, 2]) diff --git a/Python/remove-duplicates-from-sorted-list-ii.py b/Python/remove-duplicates-from-sorted-list-ii.py index 5c8f44e14..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 new file mode 100644 index 000000000..e2727b908 --- /dev/null +++ b/Python/repeated-dna-sequences.py @@ -0,0 +1,35 @@ +# Time: O(n) +# Space: O(n) +# +# All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, +# for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA. +# +# Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule. +# +# For example, +# +# Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT", +# +# Return: +# ["AAAAACCCCC", "CCCCCAAAAA"]. +# + +class Solution: + # @param s, a string + # @return a list of strings + def findRepeatedDnaSequences(self, s): + dict, rolling_hash, res = {}, 0, [] + + for i in xrange(len(s)): + rolling_hash = rolling_hash << 3 & 0x3fffffff | ord(s[i]) & 7 + if rolling_hash not in dict: + dict[rolling_hash] = True + elif dict[rolling_hash]: + res.append(s[i - 9: i + 1]) + dict[rolling_hash] = False + return res + +if __name__ == "__main__": + print Solution().findRepeatedDnaSequences("AAAAAAAAAA") + print Solution().findRepeatedDnaSequences("") + print Solution().findRepeatedDnaSequences("AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT") 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 new file mode 100644 index 000000000..6656ae327 --- /dev/null +++ b/Python/reverse-words-in-a-string-ii.py @@ -0,0 +1,38 @@ +# Time: O(n) +# Space:O(1) +# +# Given an input string, reverse the string word by word. +# A word is defined as a sequence of non-space characters. +# +# The input string does not contain leading or trailing spaces +# and the words are always separated by a single space. +# +# For example, +# Given s = "the sky is blue", +# return "blue is sky the". +# +# Could you do it in-place without allocating extra space? +# + +class Solution(object): + def reverseWords(self, s): + """ + :type s: a list of 1 length strings (List[str]) + :rtype: nothing + """ + def reverse(s, begin, end): + for i in xrange((end - begin) / 2): + s[begin + i], s[end - 1 - i] = s[end - 1 - i], s[begin + i] + + reverse(s, 0, len(s)) + i = 0 + for j in xrange(len(s) + 1): + if j == len(s) or s[j] == ' ': + reverse(s, i, j) + i = j + 1 + + +if __name__ == '__main__': + s = ['h','e','l','l','o', ' ', 'w', 'o', 'r', 'l', 'd'] + Solution().reverseWords(s) + print s diff --git a/Python/rotate-array.py b/Python/rotate-array.py new file mode 100644 index 000000000..2041672a9 --- /dev/null +++ b/Python/rotate-array.py @@ -0,0 +1,50 @@ +# Time: O(n) +# Space: O(1) +# +# Rotate an array of n elements to the right by k steps. +# +# For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. +# +# Note: +# Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem. +# + +class Solution: + # @param nums, a list of integer + # @param k, num of steps + # @return nothing, please modify the nums list in-place. + def rotate(self, nums, k): + k %= len(nums) + self.reverse(nums, 0, len(nums)) + self.reverse(nums, 0, k) + self.reverse(nums, k, len(nums)) + + def reverse(self, nums, start, end): + while start < end: + nums[start], nums[end-1] = nums[end-1], nums[start] + start += 1 + end -= 1 + +from fractions import gcd + +class Solution2: + # @param nums, a list of integer + # @param k, num of steps + # @return nothing, please modify the nums list in-place. + def rotate(self, nums, k): + k %= len(nums) + num_cycles = gcd(len(nums), k) + cycle_len = len(nums) / num_cycles + for i in xrange(num_cycles): + self.apply_cycle_permutation(k, i, cycle_len, nums) + + def apply_cycle_permutation(self, k, offset, cycle_len, nums): + tmp = nums[offset] + for i in xrange(1, cycle_len): + nums[(offset+i*k) % len(nums)], tmp = tmp, nums[(offset+i*k) % len(nums)] + nums[offset] = tmp + +if __name__ == '__main__': + nums = [1,2,3,4,5,6,7] + Solution().rotate(nums, 3) + print nums diff --git a/Python/rotate-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/same-tree.py b/Python/same-tree.py index b73333130..c7e799c94 100644 --- a/Python/same-tree.py +++ b/Python/same-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given two binary trees, write a function to check if they are equal or not. # @@ -29,4 +29,4 @@ def isSameTree(self, p, q): if __name__ == "__main__": root1, root1.left, root1.right = TreeNode(1), TreeNode(2), TreeNode(3) root2, root2.left, root2.right = TreeNode(1), TreeNode(2), TreeNode(3) - print Solution().isSameTree(root1, root2) \ No newline at end of file + print Solution().isSameTree(root1, root2) diff --git a/Python/scramble-string.py b/Python/scramble-string.py index f75325daf..7969954b0 100644 --- a/Python/scramble-string.py +++ b/Python/scramble-string.py @@ -47,7 +47,7 @@ class Solution: def isScramble(self, s1, s2): if not s1 or not s2 or len(s1) != len(s2): return False - if len(s1) == 0: + if s1 == s2: return True result = [[[False for j in xrange(len(s2))] for i in xrange(len(s1))] for n in xrange(len(s1) + 1)] for i in xrange(len(s1)): @@ -67,4 +67,4 @@ def isScramble(self, s1, s2): return result[n][0][0] if __name__ == "__main__": - print Solution().isScramble("rgtae", "great") \ No newline at end of file + print Solution().isScramble("rgtae", "great") diff --git a/Python/search-a-2d-matrix-ii.py b/Python/search-a-2d-matrix-ii.py new file mode 100644 index 000000000..520f7030a --- /dev/null +++ b/Python/search-a-2d-matrix-ii.py @@ -0,0 +1,47 @@ +# Time: O(m + n) +# Space: O(1) +# +# Write an efficient algorithm that searches for a value in an m x n matrix. +# This matrix has the following properties: +# +# Integers in each row are sorted in ascending from left to right. +# Integers in each column are sorted in ascending from top to bottom. +# For example, +# +# Consider the following matrix: +# +# [ +# [1, 4, 7, 11, 15], +# [2, 5, 8, 12, 19], +# [3, 6, 9, 16, 22], +# [10, 13, 14, 17, 24], +# [18, 21, 23, 26, 30] +# ] +# Given target = 5, return true. +# +# Given target = 20, return false. +# + +class Solution: + # @param {integer[][]} matrix + # @param {integer} target + # @return {boolean} + def searchMatrix(self, matrix, target): + m = len(matrix) + if m == 0: + return False + + n = len(matrix[0]) + if n == 0: + return False + + count, i, j = 0, 0, n - 1 + while i < m and j >= 0: + if matrix[i][j] == target: + return True + elif matrix[i][j] > target: + j -= 1 + else: + i += 1 + + return False diff --git a/Python/search-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-ii.py b/Python/single-number-ii.py index e725ccf8a..0e97ce970 100644 --- a/Python/single-number-ii.py +++ b/Python/single-number-ii.py @@ -8,6 +8,15 @@ # class Solution: + # @param A, a list of integer + # @return an integer + def singleNumber(self, A): + one, two = 0, 0 + for x in A: + one, two = (~x & one) | (x & ~one & ~two), (~x & two) | (x & one) + return one + +class Solution2: # @param A, a list of integer # @return an integer def singleNumber(self, A): @@ -20,5 +29,16 @@ def singleNumber(self, A): two &= ~carry return one +# every element appears 4 times except for one with 2 times +class SolutionEX: + # @param A, a list of integer + # @return an integer + # [1, 1, 1, 1, 2, 2, 2, 2, 3, 3] + def singleNumber(self, A): + one, two, three = 0, 0, 0 + for x in A: + one, two, three = (~x & one) | (x & ~one & ~two & ~three), (~x & two) | (x & one), (~x & three) | (x & two) + return two + if __name__ == "__main__": - print Solution().singleNumber([1, 1, 1, 2, 2, 2, 3]) \ No newline at end of file + print Solution().singleNumber([1, 1, 1, 2, 2, 2, 3]) diff --git a/Python/single-number-iii.py b/Python/single-number-iii.py new file mode 100644 index 000000000..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/sort-list.py b/Python/sort-list.py index bd56db074..5427a88bd 100644 --- a/Python/sort-list.py +++ b/Python/sort-list.py @@ -1,5 +1,5 @@ # Time: O(nlogn) -# Space: O(1) +# Space: O(logn) for stack call # # Sort a linked list in O(n log n) time using constant space complexity. # @@ -53,4 +53,4 @@ def mergeTwoLists(self, l1, l2): head.next = ListNode(4) head.next.next = ListNode(1) head.next.next.next= ListNode(2) - print Solution().sortList(head) \ No newline at end of file + print Solution().sortList(head) diff --git a/Python/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 b10431638..970fd09b6 100644 --- a/Python/string-to-integer-atoi.py +++ b/Python/string-to-integer-atoi.py @@ -26,14 +26,17 @@ # If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned. # -class Solution: - # @return an integer - def atoi(self, str): +class Solution(object): + def myAtoi(self, str): + """ + :type str: str + :rtype: int + """ INT_MAX = 2147483647 INT_MIN = -2147483648 result = 0 - if len(str) == 0: + if not str: return result i = 0 @@ -48,12 +51,8 @@ def atoi(self, str): i += 1 while i < len(str) and str[i] >= '0' and str[i] <= '9': - if result > INT_MAX / 10 or (result == INT_MAX / 10 and ord(str[i]) - ord('0') > INT_MAX % 10): - if sign > 0: - return INT_MAX - else: - return INT_MIN - + if result > (INT_MAX - (ord(str[i]) - ord('0'))) / 10: + return INT_MAX if sign > 0 else INT_MIN result = result * 10 + ord(str[i]) - ord('0') i += 1 @@ -65,4 +64,4 @@ def atoi(self, str): print Solution().atoi("2147483647") print Solution().atoi("2147483648") print Solution().atoi("-2147483648") - print Solution().atoi("-2147483649") \ No newline at end of file + print Solution().atoi("-2147483649") diff --git a/Python/strobogrammatic-number-ii.py b/Python/strobogrammatic-number-ii.py new file mode 100644 index 000000000..da089c481 --- /dev/null +++ b/Python/strobogrammatic-number-ii.py @@ -0,0 +1,24 @@ +# Time: O(n^2 * 5^(n/2)) +# Space: O(n) + +class Solution: + lookup = {'0':'0', '1':'1', '6':'9', '8':'8', '9':'6'} + + # @param {integer} n + # @return {string[]} + def findStrobogrammatic(self, n): + return self.findStrobogrammaticRecu(n, n) + + def findStrobogrammaticRecu(self, n, k): + if k == 0: + return [''] + elif k == 1: + return ['0', '1', '8'] + + result = [] + for num in self.findStrobogrammaticRecu(n, k - 2): + for key, val in self.lookup.iteritems(): + if n != k or key != '0': + result.append(key + num + val) + + return result diff --git a/Python/strobogrammatic-number-iii.py b/Python/strobogrammatic-number-iii.py new file mode 100644 index 000000000..d45aa3d49 --- /dev/null +++ b/Python/strobogrammatic-number-iii.py @@ -0,0 +1,74 @@ +# Time: O(5^(n/2)) +# Space: O(n) + +class Solution: + lookup = {'0':'0', '1':'1', '6':'9', '8':'8', '9':'6'} + cache = {} + + # @param {string} low + # @param {string} high + # @return {integer} + def strobogrammaticInRange(self, low, high): + count = self.countStrobogrammaticUntil(high, False) - \ + self.countStrobogrammaticUntil(low, False) + \ + self.isStrobogrammatic(low) + return count if count >= 0 else 0 + + def countStrobogrammaticUntil(self, num, can_start_with_0): + if can_start_with_0 and num in self.cache: + return self.cache[num] + + count = 0 + if len(num) == 1: + for c in ['0', '1', '8']: + if num[0] >= c: + count += 1 + self.cache[num] = count + return count + + for key, val in self.lookup.iteritems(): + if can_start_with_0 or key != '0': + if num[0] > key: + if len(num) == 2: # num is like "21" + count += 1 + else: # num is like "201" + count += self.countStrobogrammaticUntil('9' * (len(num) - 2), True) + elif num[0] == key: + if len(num) == 2: # num is like 12". + if num[-1] >= val: + count += 1 + else: + if num[-1] >= val: # num is like "102". + count += self.countStrobogrammaticUntil(self.getMid(num), True); + elif (self.getMid(num) != '0' * (len(num) - 2)): # num is like "110". + count += self.countStrobogrammaticUntil(self.getMid(num), True) - \ + self.isStrobogrammatic(self.getMid(num)) + + if not can_start_with_0: # Sum up each length. + for i in xrange(len(num) - 1, 0, -1): + count += self.countStrobogrammaticByLength(i) + else: + self.cache[num] = count + + return count + + def getMid(self, num): + return num[1:len(num) - 1] + + def countStrobogrammaticByLength(self, n): + if n == 1: + return 3 + elif n == 2: + return 4 + elif n == 3: + return 4 * 3 + else: + return 5 * self.countStrobogrammaticByLength(n - 2) + + def isStrobogrammatic(self, num): + n = len(num) + for i in xrange((n+1) / 2): + if num[n-1-i] not in self.lookup or \ + num[i] != self.lookup[num[n-1-i]]: + return False + return True diff --git a/Python/strobogrammatic-number.py b/Python/strobogrammatic-number.py new file mode 100644 index 000000000..37a542b93 --- /dev/null +++ b/Python/strobogrammatic-number.py @@ -0,0 +1,16 @@ +# Time: O(n) +# Space: O(1) + +class Solution: + lookup = {'0':'0', '1':'1', '6':'9', '8':'8', '9':'6'} + + # @param {string} num + # @return {boolean} + def isStrobogrammatic(self, num): + n = len(num) + for i in xrange((n+1) / 2): + if num[n-1-i] not in self.lookup or \ + num[i] != self.lookup[num[n-1-i]]: + return False + i += 1 + return True diff --git a/Python/subsets-ii.py b/Python/subsets-ii.py index a22bedb27..7690e96a8 100644 --- a/Python/subsets-ii.py +++ b/Python/subsets-ii.py @@ -1,4 +1,4 @@ -# Time: O(2^n) +# Time: O(n * 2^n) # Space: O(1) # # Given a collection of integers that might contain duplicates, S, return all possible subsets. @@ -54,4 +54,4 @@ def subsetsWithDupRecu(self, result, cur, S): self.subsetsWithDupRecu(result, cur + [S[0]], S[1:]) if __name__ == "__main__": - print Solution().subsetsWithDup([1, 2, 2]) \ No newline at end of file + print Solution().subsetsWithDup([1, 2, 2]) diff --git a/Python/subsets.py b/Python/subsets.py index 5143a2d62..eefdb0a55 100644 --- a/Python/subsets.py +++ b/Python/subsets.py @@ -1,4 +1,4 @@ -# Time: O(2^n) +# Time: O(n * 2^n) # Space: O(1) # # Given a set of distinct integers, S, return all possible subsets. @@ -46,10 +46,10 @@ def subsets(self, S): return self.subsetsRecu([], sorted(S)) def subsetsRecu(self, cur, S): - if len(S) == 0: + if not S: return [cur] return self.subsetsRecu(cur, S[1:]) + self.subsetsRecu(cur + [S[0]], S[1:]) if __name__ == "__main__": - print Solution().subsets([1, 2, 3]) \ No newline at end of file + print Solution().subsets([1, 2, 3]) diff --git a/Python/substring-with-concatenation-of-all-words.py b/Python/substring-with-concatenation-of-all-words.py index a6aeb0d27..03e5fa7f3 100644 --- a/Python/substring-with-concatenation-of-all-words.py +++ b/Python/substring-with-concatenation-of-all-words.py @@ -19,23 +19,18 @@ class Solution: # @param L, a list of string # @return a list of integer def findSubstring(self, S, L): - result, words, word_num, word_len = [], {}, len(L), len(L[0]) + result, word_num, word_len = [], len(L), len(L[0]) + words = collections.defaultdict(int) for i in L: - if i not in words: - words[i] = 1 - else: - words[i] += 1 + words[i] += 1 for i in xrange(len(S) + 1 - word_len * word_num): - cur, j = {}, 0 + cur, j = collections.defaultdict(int), 0 while j < word_num: word = S[i + j * word_len:i + j * word_len + word_len] if word not in words: break - if word not in cur: - cur[word] = 1 - else: - cur[word] += 1 + cur[word] += 1 if cur[word] > words[word]: break j += 1 diff --git a/Python/sudoku-solver.py b/Python/sudoku-solver.py index ed997c11f..fff654616 100644 --- a/Python/sudoku-solver.py +++ b/Python/sudoku-solver.py @@ -13,46 +13,33 @@ class Solution: # Solve the Sudoku by modifying the input board in-place. # Do not return any value. def solveSudoku(self, board): - for i in xrange(len(board)): - for j in xrange(len(board[0])): - if(board[i][j] == '.'): - for k in xrange(9): - board[i][j] = chr(ord('1') + k) - if self.isValid(board, i, j) and self.solveSudoku(board): - return True - board[i][j] = '.' + def isValid(board, x, y): + for i in xrange(9): + if i != x and board[i][y] == board[x][y]: return False - return True - - def isValid(self, board, x, y): - for i in xrange(9): - if i != x and board[i][y] == board[x][y]: - return False - - for j in xrange(9): - if j != y and board[x][j] == board[x][y]: - return False - - i = 3 * (x / 3) - while i < 3 * (x / 3 + 1): - j = 3 * (y / 3) - while j < 3 * (y / 3 + 1): - if (i != x or j != y) and board[i][j] == board[x][y]: + for j in xrange(9): + if j != y and board[x][j] == board[x][y]: return False - j += 1 - i += 1 - - return True + i = 3 * (x / 3) + while i < 3 * (x / 3 + 1): + j = 3 * (y / 3) + while j < 3 * (y / 3 + 1): + if (i != x or j != y) and board[i][j] == board[x][y]: + return False + j += 1 + i += 1 + return True + + def solver(board): + for i in xrange(len(board)): + for j in xrange(len(board[0])): + if(board[i][j] == '.'): + for k in xrange(9): + board[i][j] = chr(ord('1') + k) + if isValid(board, i, j) and solver(board): + return True + board[i][j] = '.' + return False + return True - -if __name__ == "__main__": - board = [['5', '3', '.', '.', '7', '.', '.', '.', '.'], - ['6', '.', '.', '1', '9', '5', '.', '.', '.'], - ['.', '9', '8', '.', '.', '.', '.', '6', '.'], - ['8', '.', '.', '.', '6', '.', '.', '.', '3'], - ['4', '.', '.', '8', '.', '3', '.', '.', '1'], - ['7', '.', '.', '.', '2', '.', '.', '.', '6'], - ['.', '6', '.', '.', '.', '.', '2', '8', '.'], - ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9']] - print Solution().solveSudoku(board) + solver(board) diff --git a/Python/sum-root-to-leaf-numbers.py b/Python/sum-root-to-leaf-numbers.py index 763a9faba..775c1920b 100644 --- a/Python/sum-root-to-leaf-numbers.py +++ b/Python/sum-root-to-leaf-numbers.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # # Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. # @@ -44,4 +44,4 @@ def sumNumbersRecu(self, root, num): root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) - print Solution().sumNumbers(root) \ No newline at end of file + print Solution().sumNumbers(root) diff --git a/Python/summary-ranges.py b/Python/summary-ranges.py new file mode 100644 index 000000000..f602a5282 --- /dev/null +++ b/Python/summary-ranges.py @@ -0,0 +1,40 @@ +# Time: O(n) +# Space: O(1) +# +# Given a sorted integer array without duplicates, +# return the summary of its ranges. +# +# For example, given [0,1,2,4,5,7], +# return ["0->2","4->5","7"]. +# + +class Solution: + # @param {integer[]} nums + # @return {string[]} + def summaryRanges(self, nums): + ranges = [] + if not nums: + return ranges + + start, end = nums[0], nums[0] + for i in xrange(1, len(nums) + 1): + if i < len(nums) and nums[i] == end + 1: + end = nums[i] + else: + interval = str(start) + if start != end: + interval += "->" + str(end) + ranges.append(interval) + if i < len(nums): + start = end = nums[i] + + return ranges + +# Time: O(n) +# Space: O(n) +class Solution2: + # @param {integer[]} nums + # @return {string[]} + def summaryRanges(self, nums): + return [re.sub('->.*>', '->', '->'.join(`n` for _, n in g)) + for _, g in itertools.groupby(enumerate(nums), lambda (i, n): n-i)] diff --git a/Python/super-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-region.py b/Python/surrounded-regions.py similarity index 73% rename from Python/surrounded-region.py rename to Python/surrounded-regions.py index a16bbee0b..98e7a65ad 100644 --- a/Python/surrounded-region.py +++ b/Python/surrounded-regions.py @@ -23,29 +23,30 @@ class Solution: # Capture all regions by modifying the input board in-place. # Do not return any value. def solve(self, board): - if len(board) == 0: + if not board: return - current = [] + q = collections.deque([]) for i in xrange(len(board)): - current.append((i, 0)) - current.append((i, len(board[0]) - 1)) + q.append((i, 0)) + q.append((i, len(board[0]) - 1)) - for i in xrange(len(board[0])): - current.append((0, i)) - current.append((len(board) - 1, i)) + for j in xrange(len(board[0])): + q.append((0, j)) + q.append((len(board) - 1, j)) - while current: - i, j = current.pop() + while q: + i, j = q.popleft() if board[i][j] in ['O', 'V']: board[i][j] = 'V' for x, y in [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]: - if 0 <= x < len(board) and 0 <= y < len(board[0]) and board[x][y] == 'O': + if 0 <= x < len(board) and 0 <= y < len(board[0]) and \ + board[x][y] == 'O': board[x][y] = 'V' - current.append((x, y)) + q.append((x, y)) for i in xrange(len(board)): - for j in range(len(board[0])): + for j in xrange(len(board[0])): if board[i][j] != 'V': board[i][j] = 'X' else: @@ -57,4 +58,4 @@ def solve(self, board): ['X', 'X', 'O', 'X'], ['X', 'O', 'X', 'X']] Solution().solve(board) - print board \ No newline at end of file + print board diff --git a/Python/symmetric-tree.py b/Python/symmetric-tree.py index 6b2a1c991..709864217 100644 --- a/Python/symmetric-tree.py +++ b/Python/symmetric-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(h), h is height of binary tree # Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). # # For example, this binary tree is symmetric: @@ -77,4 +77,4 @@ def isSymmetricRecu(self, left, right): root.left.left, root.right.right = TreeNode(3), TreeNode(3) root.left.right, root.right.left = TreeNode(4), TreeNode(4) print Solution().isSymmetric(root) - \ No newline at end of file + diff --git a/Python/text-justification.py b/Python/text-justification.py index c1a18d1e9..b292c30f7 100644 --- a/Python/text-justification.py +++ b/Python/text-justification.py @@ -1,15 +1,19 @@ # Time: O(n) -# Space: O(1) +# Space: O(k), k is maxWidth. # -# Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified. +# Given an array of words and a length L, format the text such that +# each line has exactly L characters and is fully (left and right) justified. # -# You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' +# You should pack your words in a greedy approach; that is, pack +# as many words as you can in each line. Pad extra spaces ' ' # when necessary so that each line has exactly L characters. # # Extra spaces between words should be distributed as evenly as possible. -# If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right. +# If the number of spaces on a line do not divide evenly between words, +# the empty slots on the left will be assigned more spaces than the slots on the right. # -# For the last line of text, it should be left justified and no extra space is inserted between words. +# For the last line of text, it should be left justified and no extra space +# is inserted between words. # # For example, # words: ["This", "is", "an", "example", "of", "text", "justification."] @@ -23,52 +27,44 @@ # ] # Note: Each word is guaranteed not to exceed L in length. -class Solution: - # @param words, a list of strings - # @param L, an integer - # @return a list of strings - def fullJustify(self, words, L): - result = [] - - i = 0 - while i < len(words): - # count words in one line - size, begin = 0, i - while i < len(words): - if size == 0: - newsize = len(words[i]) - else: - newsize = size + len(words[i]) + 1 - if newsize <= L: - size = newsize - else: - break - i += 1 - - # count space number - spaceCount = L - size - if i - begin - 1 > 0 and i < len(words): - everyCount = spaceCount / (i - begin - 1) - spaceCount %= i - begin - 1 - else: - everyCount = 0 - - # add space - j = begin - while j < i: - if j == begin: - s = words[j] - else: - s += ' ' * (everyCount + 1) - if spaceCount > 0 and i < len(words): - s += ' ' - spaceCount -= 1 - s += words[j] - j += 1 - s += ' ' * spaceCount - result.append(s) - - return result +class Solution(object): + def fullJustify(self, words, maxWidth): + """ + :type words: List[str] + :type maxWidth: int + :rtype: List[str] + """ + def addSpaces(i, spaceCnt, maxWidth, is_last): + if i < spaceCnt: + # For the last line of text, it should be left justified, + # and no extra space is inserted between words. + return 1 if is_last else (maxWidth // spaceCnt) + int(i < maxWidth % spaceCnt) + return 0 + + def connect(words, maxWidth, begin, end, length, is_last): + s = [] # The extra space O(k) is spent here. + n = end - begin + for i in xrange(n): + s += words[begin + i], + s += ' ' * addSpaces(i, n - 1, maxWidth - length, is_last), + # For only one word in a line. + line = "".join(s) + if len(line) < maxWidth: + line += ' ' * (maxWidth - len(line)) + return line + + res = [] + begin, length = 0, 0 + for i in xrange(len(words)): + if length + len(words[i]) + (i - begin) > maxWidth: + res += connect(words, maxWidth, begin, i, length, False), + begin, length = i, 0 + length += len(words[i]) + + # Last line. + res += connect(words, maxWidth, begin, len(words), length, True), + return res + if __name__ == "__main__": print Solution().fullJustify(["This", "is", "an", "example", "of", "text", "justification."], 16) diff --git a/Python/the-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/triangle.py b/Python/triangle.py index 40cf9c627..e05906104 100644 --- a/Python/triangle.py +++ b/Python/triangle.py @@ -20,7 +20,7 @@ class Solution: # @param triangle, a list of lists of integers # @return an integer def minimumTotal(self, triangle): - if len(triangle) == 0: + if not triangle: return 0 cur = triangle[0] + [float("inf")] @@ -35,4 +35,4 @@ def minimumTotal(self, triangle): if __name__ == "__main__": print Solution().minimumTotal([[-1], [2, 3], [1, -1, -3]]) - \ No newline at end of file + diff --git a/Python/two-sum-iii-data-structure-design.py b/Python/two-sum-iii-data-structure-design.py index 0bcaf917e..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/validate-binary-search-tree.py b/Python/validate-binary-search-tree.py index 9af8db35d..7e329c4cf 100644 --- a/Python/validate-binary-search-tree.py +++ b/Python/validate-binary-search-tree.py @@ -1,5 +1,5 @@ # Time: O(n) -# Space: O(logn) +# Space: O(1) # # Given a binary tree, determine if it is a valid binary search tree (BST). # @@ -17,7 +17,38 @@ def __init__(self, x): self.left = None self.right = None +# Morris Traversal Solution class Solution: + # @param root, a tree node + # @return a list of integers + def isValidBST(self, root): + prev, cur = None, root + while cur: + if cur.left is None: + if prev and prev.val >= cur.val: + return False + prev = cur + cur = cur.right + else: + node = cur.left + while node.right and node.right != cur: + node = node.right + + if node.right is None: + node.right = cur + cur = cur.left + else: + if prev and prev.val >= cur.val: + return False + node.right = None + prev = cur + cur = cur.right + + return True + +# Time: O(n) +# Space: O(logn) +class Solution2: # @param root, a tree node # @return a boolean def isValidBST(self, root): @@ -35,4 +66,4 @@ def isValidBSTRecu(self, root, low, high): root = TreeNode(2) root.left = TreeNode(1) root.right = TreeNode(3) - print Solution().isValidBST(root) \ No newline at end of file + print Solution().isValidBST(root) diff --git a/Python/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 ebd9f1c49..7965368aa 100644 --- a/Python/wildcard-matching.py +++ b/Python/wildcard-matching.py @@ -48,7 +48,9 @@ def isMatch(self, s, p): return p_ptr == len(p) -# dp +# dp with rolling window +# Time: O(m * n) +# Space: O(m + n) class Solution2: # @return a boolean def isMatch(self, s, p): @@ -92,15 +94,15 @@ def isMatch(self, s, p): return result[len(s)][len(p)] -# recursive, slowest +# recursive, slowest, TLE class Solution4: # @return a boolean def isMatch(self, s, p): - if len(p) == 0: - return len(s) == 0 + if not p or not s: + return not s and not p if p[0] != '*': - if len(s) == 0 or (p[0] == s[0] or p[0] == '?'): + if p[0] == s[0] or p[0] == '?': return self.isMatch(s[1:], p[1:]) else: return False @@ -120,4 +122,4 @@ def isMatch(self, s, p): print Solution().isMatch("aa", "a*") print Solution().isMatch("aa", "?*") print Solution().isMatch("ab", "?*") - print Solution().isMatch("aab", "c*a*b") \ No newline at end of file + print Solution().isMatch("aab", "c*a*b") diff --git a/Python/word-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 501fd94fa..b7ffb1180 100644 --- a/Python/word-ladder-ii.py +++ b/Python/word-ladder-ii.py @@ -1,5 +1,5 @@ -# Time: O((25n)^n) -# Space: O((25n)^n) +# Time: O(n * d), n is length of string, d is size of dictionary +# Space: O(d) # # Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that: # @@ -37,7 +37,7 @@ def findLadders(self, start, end, dict): for word in cur: visited.add(word) - next = set([]) + next = set() for word in cur: for i in xrange(len(word)): for j in 'abcdefghijklmnopqrstuvwxyz': @@ -55,7 +55,7 @@ def findLadders(self, start, end, dict): return result def backtrack(self, result, trace, path, word): - if len(trace[word]) == 0: + if not trace[word]: result.append([word] + path) else: for prev in trace[word]: diff --git a/Python/word-ladder.py b/Python/word-ladder.py index 8ed2f6c97..17cdb9a77 100644 --- a/Python/word-ladder.py +++ b/Python/word-ladder.py @@ -1,5 +1,5 @@ -# Time: O((25n)^n) -# Space: O((25n)^n) +# Time: O(n * d), n is length of string, d is size of dictionary +# Space: O(d) # # Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that: # diff --git a/Python/word-pattern-ii.py b/Python/word-pattern-ii.py new file mode 100644 index 000000000..2d12cd67c --- /dev/null +++ b/Python/word-pattern-ii.py @@ -0,0 +1,39 @@ +# Time: O(n * C(n - 1, c - 1)), n is length of str, c is unique count of pattern, +# there are H(n - c, c - 1) = C(n - 1, c - 1) possible splits of string, +# and each one costs O(n) to check if it matches the word pattern. +# Space: O(n + c) + +class Solution(object): + def wordPatternMatch(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + w2p, p2w = {}, {} + return self.match(pattern, str, 0, 0, w2p, p2w) + + + def match(self, pattern, str, i, j, w2p, p2w): + is_match = False + if i == len(pattern) and j == len(str): + is_match = True + elif i < len(pattern) and j < len(str): + p = pattern[i] + if p in p2w: + w = p2w[p] + if w == str[j:j+len(w)]: # Match pattern. + is_match = self.match(pattern, str, i + 1, j + len(w), w2p, p2w) + # Else return false. + else: + for k in xrange(j, len(str)): # Try any possible word + w = str[j:k+1] + if w not in w2p: + # Build mapping. Space: O(n + c) + w2p[w], p2w[p] = p, w; + is_match = self.match(pattern, str, i + 1, k + 1, w2p, p2w) + w2p.pop(w), p2w.pop(p); + if is_match: + break + return is_match + diff --git a/Python/word-pattern.py b/Python/word-pattern.py new file mode 100644 index 000000000..7bace4ebd --- /dev/null +++ b/Python/word-pattern.py @@ -0,0 +1,82 @@ +# Time: O(n) +# Space: O(c), c is unique count of pattern + +# Given a pattern and a string str, find if str follows the same pattern. +# +# Examples: +# 1. pattern = "abba", str = "dog cat cat dog" should return true. +# 2. pattern = "abba", str = "dog cat cat fish" should return false. +# 3. pattern = "aaaa", str = "dog cat cat dog" should return false. +# 4. pattern = "abba", str = "dog dog dog dog" should return false. +# +# Notes: +# 1. Both pattern and str contains only lowercase alphabetical letters. +# 2. Both pattern and str do not have leading or trailing spaces. +# 3. Each word in str is separated by a single space. +# 4. Each letter in pattern must map to a word with length that is at least 1. + +from itertools import izip # Generator version of zip. + +class Solution(object): + def wordPattern(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + if len(pattern) != self.wordCount(str): + return False + + w2p, p2w = {}, {} + for p, w in izip(pattern, self.wordGenerator(str)): + if w not in w2p and p not in p2w: + # Build mapping. Space: O(c) + w2p[w] = p + p2w[p] = w + elif w not in w2p or w2p[w] != p: + # Contradict mapping. + return False + return True + + def wordCount(self, str): + cnt = 1 if str else 0 + for c in str: + if c == ' ': + cnt += 1 + return cnt + + # Generate a word at a time without saving all the words. + def wordGenerator(self, str): + w = "" + for c in str: + if c == ' ': + yield w + w = "" + else: + w += c + yield w + + +# Time: O(n) +# Space: O(n) +class Solution2(object): + def wordPattern(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + words = str.split() # Space: O(n) + if len(pattern) != len(words): + return False + + w2p, p2w = {}, {} + for p, w in izip(pattern, words): + if w not in w2p and p not in p2w: + # Build mapping. Space: O(c) + w2p[w] = p + p2w[p] = w + elif w not in w2p or w2p[w] != p: + # Contradict mapping. + return False + return True diff --git a/Python/word-search-ii.py b/Python/word-search-ii.py new file mode 100644 index 000000000..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 c7c3ea16e..5c1e3341c 100644 --- a/README.md +++ b/README.md @@ -1,734 +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-01-13), there are total `180` problems on [LeetCode Online Judge](https://oj.leetcode.com/). -The number of problems is increasing recently. -Here is the classification of all `180` problems. +Up to date (2016-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 Image] | [rotate-image.py] | _O(n^2)_ | _O(1)_ | Medium | -[Set Matrix Zeroes] | [set-matrix-zeroes.py] | _O(m * n)_ | _O(1)_ | Medium | -[Spiral Matrix] | [spiral-matrix.py] | _O(m * n)_ | _O(1)_ | Medium | -[Spiral Matrix II] | [spiral-matrix-ii.py] | _O(m * n)_ | _O(1)_ | Medium | - - -[3 Sum]: https://oj.leetcode.com/problems/3sum/ -[3sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/3sum.py -[3 Sum Closest]: https://oj.leetcode.com/problems/3sum-closest/ -[3sum-closest.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/3sum-closest.py -[Best Time to Buy and Sell Stock]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock/ -[best-time-to-buy-and-sell-stock.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock.py -[First Missing Positive]:https://oj.leetcode.com/problems/first-missing-positive/ -[first-missing-positive.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/first-missing-positive.py -[Longest Consecutive Sequence]:https://oj.leetcode.com/problems/longest-consecutive-sequence/ -[longest-consecutive-sequence.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-consecutive-sequence.py -[Majority Element]: https://oj.leetcode.com/problems/majority-element/ -[majority-element.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/majority-element.py -[Missing Ranges]:https://oj.leetcode.com/problems/missing-ranges/ -[missing-ranges.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/missing-ranges.py -[Next Permutation]:https://oj.leetcode.com/problems/next-permutation/ -[next-permutation.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/next-permutation.py -[Pascal's Triangle]:https://oj.leetcode.com/problems/pascals-triangle/ -[pascals-triangle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/pascals-triangle.py -[Pascal's Triangle II]:https://oj.leetcode.com/problems/pascals-triangle-ii/ -[pascals-triangle-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/pascals-triangle-ii.py -[Plus One]:https://oj.leetcode.com/problems/plus-one/ -[plus-one.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/plus-one.py -[Read N Characters Given Read4]:https://oj.leetcode.com/problems/read-n-characters-given-read4/ -[read-n-characters-given-read4.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/read-n-characters-given-read4.py -[Read N Characters Given Read4 II - Call multiple times]:https://oj.leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/ -[read-n-characters-given-read4-ii-call-multiple-times.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/read-n-characters-given-read4-ii-call-multiple-times.py -[Remove Duplicates from Sorted Array]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-array/ -[remove-duplicates-from-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-array.py -[Remove Duplicates from Sorted Array II]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-array-ii/ -[remove-duplicates-from-sorted-array-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-array-ii.py -[Remove Element]:https://oj.leetcode.com/problems/remove-element/ -[remove-element.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-element.py -[Rotate Image]:https://oj.leetcode.com/problems/rotate-image/ -[rotate-image.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/rotate-image.py -[Set Matrix Zeroes]:https://oj.leetcode.com/problems/set-matrix-zeroes/ -[set-matrix-zeroes.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/set-matrix-zeroes.py -[Spiral Matrix]:https://oj.leetcode.com/problems/spiral-matrix/ -[spiral-matrix.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/spiral-matrix.py -[Spiral Matrix II]:https://oj.leetcode.com/problems/spiral-matrix-ii/ -[spiral-matrix-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/spiral-matrix-ii.py - - ---- - -##String -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Add Binary] | [add-binary.py] | _O(n)_ | _O(1)_ | Easy | -[Anagrams] | [anagrams.py] | _O(n)_ | _O(n)_ | Medium | -[Compare Version Numbers] | [compare-version-numbers.py] | _O(n)_ | _O(1)_ | Easy | -[Count and Say] | [count-and-say.py]| _O(n^2)_ | _O(n)_ | Easy | -[Implement strStr()] | [implement-strstr.py] | _O(n + m)_ | _O(m)_ | Easy | `KMP Algorithm` -[Length of Last Word] | [length-of-last-word.py] | _O(n)_ | _O(1)_ | Easy | -[Longest Common Prefix] | [longest-common-prefix.py] | _O(n1 + n2 + ...)_ | _O(1)_ | Easy | -[Longest Palindromic Substring] | [longest-palindromic-substring.py] | _O(n)_ | _O(n)_ | Medium | `Manacher's Algorithm` -[Multiply Strings] | [multiply-strings.py] | _O(m * n)_ | _O(m + n)_ | Medium | -[One Edit Distance] | [one-edit-distance.py] | _O(m + n)_ | _O(1)_ | Medium | -[Reverse Words in a String] | [reverse-words-in-a-string.py] | _O(n)_ | _O(n)_ | Medium | -[String to Integer (atoi)] | [string-to-integer-atoi.py] | _O(n)_ | _O(1)_ | Easy | -[Text Justification] | [text-justification.py] | _O(n)_ | _O(1)_ | Hard | -[Valid Palindrome] | [valid-palindrome.py] | _O(n)_ | _O(1)_ | Easy | -[ZigZag Conversion] | [zigzag-conversion.py] | _O(n)_ | _O(1)_ | Easy | - -[Add Binary]:https://oj.leetcode.com/problems/add-binary/ -[add-binary.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/add-binary.py -[Anagrams]:https://oj.leetcode.com/problems/anagrams/ -[anagrams.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/anagrams.py -[Count and Say]:https://oj.leetcode.com/problems/count-and-say/ -[count-and-say.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/count-and-say.py -[Compare Version Numbers]:https://oj.leetcode.com/problems/compare-version-numbers/ -[compare-version-numbers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/compare-version-numbers.py -[Implement strStr()]:https://oj.leetcode.com/problems/implement-strstr/ -[implement-strstr.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/implement-strstr.py -[Length of Last Word]:https://oj.leetcode.com/problems/length-of-last-word/ -[length-of-last-word.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/length-of-last-word.py -[Longest Common Prefix]:https://oj.leetcode.com/problems/longest-common-prefix/ -[longest-common-prefix.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-common-prefix.py -[Longest Palindromic Substring]:https://oj.leetcode.com/problems/longest-palindromic-substring/ -[longest-palindromic-substring.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-palindromic-substring.py -[Multiply Strings]:https://oj.leetcode.com/problems/multiply-strings/ -[multiply-strings.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/multiply-strings.py - -[One Edit Distance]:https://oj.leetcode.com/problems/one-edit-distance/ -[one-edit-distance.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/one-edit-distance.py -[Reverse Words in a String]:https://oj.leetcode.com/problems/reverse-words-in-a-string/ -[reverse-words-in-a-string.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-words-in-a-string.py -[String to Integer (atoi)]:https://oj.leetcode.com/problems/string-to-integer-atoi/ -[string-to-integer-atoi.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/string-to-integer-atoi.py -[Text Justification]:https://oj.leetcode.com/problems/text-justification/ -[text-justification.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/text-justification.py -[Valid Palindrome]:https://oj.leetcode.com/problems/valid-palindrome/ -[valid-palindrome.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-palindrome.py -[ZigZag Conversion]:https://oj.leetcode.com/problems/zigzag-conversion/ -[zigzag-conversion.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/zigzag-conversion.py - ---- - -##Linked List -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Add Two Numbers] | [add-two-numbers.py] | _O(n)_ | _O(1)_ | Medium | -[Copy List with Random Pointer] | [copy-list-with-random-pointer.py] | _O(n)_ | _O(1)_ | Hard | -[Intersection of Two Linked Lists]| [intersection-of-two-linked-lists.py] | _O(m + n)_ | _O(1)_ | Easy | -[Remove Duplicates from Sorted List]| [remove-duplicates-from-sorted-list.py] | _O(n)_ | _O(1)_ | Easy | -[Remove Duplicates from Sorted List II]| [remove-duplicates-from-sorted-list-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Reverse Linked List II]| [reverse-linked-list-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Reverse Nodes in k-Group]| [reverse-nodes-in-k-group.py] | _O(n)_ | _O(1)_ | Hard | -[Rotate List]| [rotate-list.py] | _O(n)_ | _O(1)_ | Medium | -[Swap Nodes in Pairs]| [swap-nodes-in-pairs.py] | _O(n)_ | _O(1)_ | Medium | - -[Add Two Numbers]:https://oj.leetcode.com/problems/add-two-numbers/ -[add-two-numbers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/add-two-numbers.py -[Copy List with Random Pointer]:https://oj.leetcode.com/problems/copy-list-with-random-pointer/ -[copy-list-with-random-pointer.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/copy-list-with-random-pointer.py -[Intersection of Two Linked Lists]:https://oj.leetcode.com/problems/intersection-of-two-linked-lists/ -[intersection-of-two-linked-lists.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/intersection-of-two-linked-lists.py -[Remove Duplicates from Sorted List]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-list/ -[remove-duplicates-from-sorted-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-list.py -[Remove Duplicates from Sorted List II]:https://oj.leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ -[remove-duplicates-from-sorted-list-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-duplicates-from-sorted-list-ii.py -[Reverse Linked List II]:https://oj.leetcode.com/problems/reverse-linked-list-ii/ -[reverse-linked-list-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-linked-list-ii.py -[Reverse Nodes in k-Group]:https://oj.leetcode.com/problems/reverse-nodes-in-k-group/ -[reverse-nodes-in-k-group.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-nodes-in-k-group.py -[Rotate List]:https://oj.leetcode.com/problems/rotate-list/ -[rotate-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/rotate-list.py -[Swap Nodes in Pairs]:https://oj.leetcode.com/problems/swap-nodes-in-pairs/ -[swap-nodes-in-pairs.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/swap-nodes-in-pairs.py - ---- - -##Stack -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Binary Search Tree Iterator] | [binary-search-tree-iterator.py] | _O(1)_| _O(logn)_| Medium -[Evaluate Reverse Polish Notation]| [evaluate-reverse-polish-notation.py]| _O(n)_| _O(n)_| Medium | -[Longest Valid Parentheses]| [longest-valid-parentheses.py] | _O(n)_ | _O(1)_ | Hard | -[Min Stack] | [min-stack.py] | _O(n)_ | _O(1)_ | Easy | -[Simplify Path]| [simplify-path.py] | _O(n)_ | _O(n)_ | Medium | -[Symmetric Tree]| [symmetric-tree.py] | _O(n)_ | _O(logn)_ | Easy | -[Valid Parentheses]| [valid-parentheses.py] | _O(n)_ | _O(n)_ | Easy | - -[Binary Search Tree Iterator]:https://oj.leetcode.com/problems/binary-search-tree-iterator/ -[binary-search-tree-iterator.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-search-tree-iterator.py -[Evaluate Reverse Polish Notation]:https://oj.leetcode.com/problems/evaluate-reverse-polish-notation/ -[evaluate-reverse-polish-notation.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/evaluate-reverse-polish-notation.py -[Longest Valid Parentheses]:https://oj.leetcode.com/problems/longest-valid-parentheses/ -[longest-valid-parentheses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-valid-parentheses.py -[Min Stack]:https://oj.leetcode.com/problems/min-stack/ -[min-stack.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/min-stack.py -[Simplify Path]:https://oj.leetcode.com/problems/simplify-path/ -[simplify-path.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/simplify-path.py -[Symmetric Tree]:https://oj.leetcode.com/problems/symmetric-tree/ -[symmetric-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/symmetric-tree.py -[Valid Parentheses]:https://oj.leetcode.com/problems/valid-parentheses/ -[valid-parentheses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-parentheses.py - ---- - -##Heap -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Merge k Sorted Lists] | [merge-k-sorted-lists.py] | _O(nlogk)_| _O(1)_| Hard | - -[Merge k Sorted Lists]:https://oj.leetcode.com/problems/merge-k-sorted-lists/ -[merge-k-sorted-lists.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-k-sorted-lists.py - ---- - -##Tree -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Binary Tree Preorder Traversal] | [binary-tree-preorder-traversal.py] | _O(n)_| _O(1)_| Medium | `Morris Traversal` -[Binary Tree Inorder Traversal] | [binary-tree-inorder-traversal.py] | _O(n)_| _O(1)_| Medium | `Morris Traversal` -[Binary Tree Postorder Traversal]| [binary-tree-postorder-traversal.py] | _O(n)_| _O(1)_| Hard | `Morris Traversal` -[Recover Binary Search Tree]| [recover-binary-search-tree.py] | _O(n)_| _O(1)_| Hard | `Morris Traversal` - -[Binary Tree Preorder Traversal]:https://oj.leetcode.com/problems/binary-tree-preorder-traversal/ -[binary-tree-preorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-preorder-traversal.py -[Binary Tree Inorder Traversal]:https://oj.leetcode.com/problems/binary-tree-inorder-traversal/ -[binary-tree-inorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-inorder-traversal.py -[Binary Tree Postorder Traversal]:https://oj.leetcode.com/problems/binary-tree-postorder-traversal/ -[binary-tree-postorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-postorder-traversal.py -[Recover Binary Search Tree]:https://oj.leetcode.com/problems/recover-binary-search-tree/ -[recover-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/recover-binary-search-tree.py - ---- - -##Hash Table -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[4 Sum] |[4sum.py] | _O(n^2)_ ~ _O(n^4)_ | _O(n^2)_ | Medium | -[Longest Substring with At Most Two Distinct Characters]| [longest-substring-with-at-most-two-distinct-characters.py] | _O(n^2)_ | _O(1)_ | Hard | -[Longest Substring Without Repeating Characters] | [longest-substring-without-repeating-characters.py] | _O(n)_ | _O(1)_ | Medium | -[Max Points on a Line] | [max-points-on-a-line.py] | _O(n^2)_ | _O(n)_ | Hard | -[Minimum Window Substring] | [minimum-window-substring.py] | _O(n^2)_ | _O(n)_ | Hard | -[Substring with Concatenation of All Words] | [substring-with-concatenation-of-all-words.py] | _O(m * n * k)_ | _O(n * k)_ | Hard | -[Two Sum] | [two-sum.py] | _O(n)_ | _O(n)_ | Medium | -[Two Sum III - Data structure design] | [two-sum-iii-data-structure-design.py] | _O(n)_ | _O(n)_ | Easy | -[Valid Sudoku] | [valid-sudoku.py] | _O(n)_ | _O(n)_ | Easy | - -[4 Sum]: https://oj.leetcode.com/problems/4sum/ -[4sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/4sum.py -[Longest Substring with At Most Two Distinct Characters]:https://oj.leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/ -[longest-substring-with-at-most-two-distinct-characters.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-substring-with-at-most-two-distinct-characters.py -[Longest Substring Without Repeating Characters]:https://oj.leetcode.com/problems/longest-substring-without-repeating-characters/ -[longest-substring-without-repeating-characters.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/longest-substring-without-repeating-characters.py -[Max Points on a Line]:https://oj.leetcode.com/problems/max-points-on-a-line/ -[max-points-on-a-line.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/max-points-on-a-line.py -[Minimum Window Substring]:https://oj.leetcode.com/problems/minimum-window-substring/ -[minimum-window-substring.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/minimum-window-substring.py -[Substring with Concatenation of All Words]:https://oj.leetcode.com/problems/substring-with-concatenation-of-all-words/ -[substring-with-concatenation-of-all-words.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/substring-with-concatenation-of-all-words.py -[Two Sum]:https://oj.leetcode.com/problems/two-sum/ -[two-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/two-sum.py -[Two Sum III - Data structure design]:https://oj.leetcode.com/problems/two-sum-iii-data-structure-design/ -[two-sum-iii-data-structure-design.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/two-sum-iii-data-structure-design.py -[Valid Sudoku]:https://oj.leetcode.com/problems/valid-sudoku/ -[valid-sudoku.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-sudoku.py - ---- - -##Data Structure -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[LRU Cache] | [lru-cache.py] | _O(1)_ | _O(n)_ | Hard | - - -[LRU Cache]:https://oj.leetcode.com/problems/lru-cache/ -[lru-cache.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/lru-cache.py - ---- - -##Math -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Divide Two Integers] | [divide-two-integers.py] | _O(logn)_ | _O(1)_ | Medium | -[Excel Sheet Column Title] | [excel-sheet-column-title.py] | _O(logn)_ | _O(1)_ | Easy | -[Excel Sheet Column Number] | [excel-sheet-column-number.py] | _O(n)_ | _O(1)_ | Easy | -[Factorial Trailing Zeroes] | [factorial-trailing-zeroes.py] | _O(logn)_ | _O(1)_ | Easy | -[Fraction to Recurring Decimal] | [fraction-to-recurring-decimal.py] | _O(logn)_ | _O(1)_ | Medium | -[Gray Code] | [gray-code.py] | _O(2^n)_ | _O(1)_ | Medium | -[Integer to Roman] | [integer-to-roman.py] | _O(n)_ | _O(1)_ | Medium | -[Palindrome Number] | [palindrome-number.py] | _O(1)_ | _O(1)_ | Easy | -[Permutation Sequence] | [permutation-sequence.py] | _O(n)_ | _O(1)_ | Medium | `Cantor Ordering` -[Reverse Integer] | [reverse-integer.py] | _O(logn)_ | _O(1)_ | Easy | -[Roman to Integer] | [roman-to-integer.py] | _O(n)_ | _O(1)_ | Easy | -[Valid Number] | [valid-number.py] | _O(n)_ | _O(1)_ | Hard | `Automata` - -[Divide Two Integers]:https://oj.leetcode.com/problems/divide-two-integers/ -[divide-two-integers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/divide-two-integers.py -[Excel Sheet Column Title]:https://oj.leetcode.com/problems/excel-sheet-column-title/ -[excel-sheet-column-title.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/excel-sheet-column-title.py -[Excel Sheet Column Number]:https://oj.leetcode.com/problems/excel-sheet-column-number/ -[excel-sheet-column-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/excel-sheet-column-number.py -[Factorial Trailing Zeroes]:https://oj.leetcode.com/problems/factorial-trailing-zeroes/ -[factorial-trailing-zeroes.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/factorial-trailing-zeroes.py -[Fraction to Recurring Decimal]:https://oj.leetcode.com/problems/fraction-to-recurring-decimal/ -[fraction-to-recurring-decimal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/fraction-to-recurring-decimal.py -[Gray Code]:https://oj.leetcode.com/problems/gray-code/ -[gray-code.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/gray-code.py -[Integer to Roman]:https://oj.leetcode.com/problems/integer-to-roman/ -[integer-to-roman.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/integer-to-roman.py -[Palindrome Number]:https://oj.leetcode.com/problems/palindrome-number/ -[palindrome-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/palindrome-number.py -[Permutation Sequence]:https://oj.leetcode.com/problems/permutation-sequence/ -[permutation-sequence.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/permutation-sequence.py -[Reverse Integer]:https://oj.leetcode.com/problems/reverse-integer/ -[reverse-integer.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reverse-integer.py -[Roman to Integer]:https://oj.leetcode.com/problems/roman-to-integer/ -[roman-to-integer.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/roman-to-integer.py -[Valid Number]:https://oj.leetcode.com/problems/valid-number/ -[valid-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/valid-number.py - - ---- - -##Sort -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Insert Interval]| [insert-interval.py] | _O(n)_ | _O(1)_ | Hard | -[Insertion Sort List]|[insertion-sort-list.py] | _O(n^2)_ | _O(1)_ | Medium | -[Largest Number] | [largest-number.py] | _O(n^2)_ | _O(n)_ | Medium | -[Maximum Gap] | [maximum-gap.py]| _O(n)_ | _O(n)_ | Hard | Tricky -[Merge Intervals]| [merge-intervals.py] | _O(n^2)_ | _O(1)_ | Hard | -[Merge Sorted Array]| [merge-sorted-array.py] | _O(n)_ | _O(1)_ | Easy | -[Merge Two Sorted Lists]| [merge-two-sorted-lists.py] | _O(n)_ | _O(1)_ | Easy | -[Sort Colors] | [sort-colors.py] | _O(n)_ | _O(1)_ | Medium | -[Sort List] | [sort-list.py] | _O(nlogn)_ | _O(1)_ | Medium | - -[Insert Interval]:https://oj.leetcode.com/problems/insert-interval/ -[insert-interval.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/insert-interval.py -[Insertion Sort List]:https://oj.leetcode.com/problems/insertion-sort-list/ -[insertion-sort-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/insertion-sort-list.py -[Largest Number]:https://oj.leetcode.com/problems/largest-number/ -[largest-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/largest-number.py -[Maximum Gap]:https://oj.leetcode.com/problems/maximum-gap/ -[maximum-gap.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-gap.py -[Merge Intervals]:https://oj.leetcode.com/problems/merge-intervals/ -[merge-intervals.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-intervals.py -[Merge Sorted Array]:https://oj.leetcode.com/problems/merge-sorted-array/ -[merge-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-sorted-array.py -[Merge Two Sorted Lists]:https://oj.leetcode.com/problems/merge-two-sorted-lists/ -[merge-two-sorted-lists.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/merge-two-sorted-lists.py -[Sort Colors]:https://oj.leetcode.com/problems/sort-colors/ -[sort-colors.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sort-colors.py -[Sort List]:https://oj.leetcode.com/problems/sort-list/ -[sort-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sort-list.py - ---- -##Two Pointer -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Linked List Cycle]| [linked-list-cycle.py] | _O(n)_ | _O(1)_ | Medium | -[Linked List Cycle II]| [linked-list-cycle-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Partition List]| [partition-list.py] | _O(n)_ | _O(1)_ | Medium | -[Remove Nth Node From End of List]| [remove-nth-node-from-end-of-list.py] | _O(n)_ | _O(1)_ | Easy | -[Reorder List]| [reorder-list.py] | _O(n)_ | _O(1)_ | Medium | -[Two Sum II - Input array is sorted] | [two-sum-ii-input-array-is-sorted.py] | _O(n)_ | _O(1)_ | Medium | - -[Linked List Cycle]:https://oj.leetcode.com/problems/linked-list-cycle/ -[linked-list-cycle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/linked-list-cycle.py -[Linked List Cycle II]:https://oj.leetcode.com/problems/linked-list-cycle-ii/ -[linked-list-cycle-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/linked-list-cycle-ii.py -[Partition List]:https://oj.leetcode.com/problems/partition-list/ -[partition-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/partition-list.py -[Remove Nth Node From End of List]:https://oj.leetcode.com/problems/remove-nth-node-from-end-of-list/ -[remove-nth-node-from-end-of-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/remove-nth-node-from-end-of-list.py -[Reorder List]:https://oj.leetcode.com/problems/reorder-list/ -[reorder-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/reorder-list.py -[Two Sum II - Input array is sorted]:https://oj.leetcode.com/problems/two-sum-ii-input-array-is-sorted/ -[two-sum-ii-input-array-is-sorted.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/two-sum-ii-input-array-is-sorted.py +## Shell + +* [Shell Script](https://github.com/kamyu104/LeetCode#shell-script) + +## Bit Manipulation + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +136 | [Single Number](https://leetcode.com/problems/single-number/) | [C++](./C++/single-number.cpp) [Python](./Python/single-number.py) | _O(n)_ | _O(1)_ | 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(4^n)_ | _O(1)_ | Medium | -[Permutations]| [permutations.py] | _O(n!)_ | _O(n)_ | Medium | -[Permutations II]| [permutations-ii.py] | _O(n!)_ | _O(n)_ | Hard | -[Subsets] | [subsets.py] | _O(2^n)_ | _O(1)_ | Medium | -[Subsets II] | [subsets-ii.py] | _O(2^n)_ | _O(1)_ | Medium | - -[Letter Combinations of a Phone Number]:https://oj.leetcode.com/problems/letter-combinations-of-a-phone-number/ -[letter-combinations-of-a-phone-number.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/letter-combinations-of-a-phone-number.py -[Permutations]:https://oj.leetcode.com/problems/permutations/ -[permutations.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/permutations.py -[Permutations II]:https://oj.leetcode.com/problems/permutations-ii/ -[permutations-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/permutations-ii.py -[Subsets]:https://oj.leetcode.com/problems/subsets/ -[subsets.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/subsets.py -[Subsets II]:https://oj.leetcode.com/problems/subsets-ii/ -[subsets-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/subsets-ii.py - ---- - -##Divide and Conquer -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Balanced Binary Tree] | [balanced-binary-tree.py] | _O(n)_| _O(logn)_| Easy | -[Binary Tree Maximum Path Sum]| [binary-tree-maximum-path-sum.py] | _O(n)_| _O(logn)_| Hard | -[Binary Tree Upside Down] | [binary-tree-upside-down.py] | _O(n)_ | _O(1)_ | Medium | -[Construct Binary Tree from Inorder and Postorder Traversal] | [construct-binary-tree-from-inorder-and-postorder-traversal.py] | _O(n)_ | _O(n)_ | Medium | -[Construct Binary Tree from Preorder and Inorder Traversal] | [construct-binary-tree-from-preorder-and-inorder-traversal.py] | _O(n)_ | _O(n)_ | Medium -[Convert Sorted Array to Binary Search Tree] | [convert-sorted-array-to-binary-search-tree.py] | _O(n)_ | _O(logn)_ | Medium | -[Convert Sorted List to Binary Search Tree] | [convert-sorted-list-to-binary-search-tree.py] | _O(n)_ | _O(logn)_ | Medium | -[Flatten Binary Tree to Linked List]|[flatten-binary-tree-to-linked-list.py]| _O(n)_ | _O(logn)_ | Medium | -[Maximum Depth of Binary Tree]|[maximum-depth-of-binary-tree.py]| _O(n)_ | _O(logn)_ | Easy | -[Minimum Depth of Binary Tree]|[minimum-depth-of-binary-tree.py]| _O(n)_ | _O(logn)_ | Easy | -[Populating Next Right Pointers in Each Node]|[populating-next-right-pointers-in-each-node.py]| _O(n)_ | _O(logn)_ | Medium | -[Same Tree] |[same-tree.py] | _O(n)_ | _O(logn)_ | Easy | -[Sum Root to Leaf Numbers] | [sum-root-to-leaf-numbers.py] | _O(n)_ | _O(logn)_ | Medium | -[Unique Binary Search Trees II] | [unique-binary-search-trees-ii.py] | _O(4^n / n^(3/2)_ | _O(4^n / n^(3/2)_ | Medium | -[Validate Binary Search Tree]|[validate-binary-search-tree.py]| _O(n)_ | _O(logn)_ | Medium | - -[Balanced Binary Tree]:https://oj.leetcode.com/problems/balanced-binary-tree/ -[balanced-binary-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/balanced-binary-tree.py -[Binary Tree Maximum Path Sum]:https://oj.leetcode.com/problems/binary-tree-maximum-path-sum/ -[binary-tree-maximum-path-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-maximum-path-sum.py -[Binary Tree Upside Down]:https://oj.leetcode.com/problems/binary-tree-upside-down/ -[binary-tree-upside-down.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-upside-down.py -[Construct Binary Tree from Inorder and Postorder Traversal]:https://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/ -[construct-binary-tree-from-inorder-and-postorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/construct-binary-tree-from-inorder-and-postorder-traversal.py -[Construct Binary Tree from Preorder and Inorder Traversal]:https://oj.leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ -[construct-binary-tree-from-preorder-and-inorder-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/construct-binary-tree-from-preorder-and-inorder-traversal.py -[Convert Sorted Array to Binary Search Tree]:https://oj.leetcode.com/problems/convert-sorted-array-to-binary-search-tree/ -[convert-sorted-array-to-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/convert-sorted-array-to-binary-search-tree.py -[Convert Sorted List to Binary Search Tree]:https://oj.leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ -[convert-sorted-list-to-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/convert-sorted-list-to-binary-search-tree.py -[Flatten Binary Tree to Linked List]:https://oj.leetcode.com/problems/flatten-binary-tree-to-linked-list/ -[flatten-binary-tree-to-linked-list.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/flatten-binary-tree-to-linked-list.py -[Maximum Depth of Binary Tree]:https://oj.leetcode.com/problems/maximum-depth-of-binary-tree/ -[maximum-depth-of-binary-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-depth-of-binary-tree.py -[Minimum Depth of Binary Tree]:https://oj.leetcode.com/problems/minimum-depth-of-binary-tree/ -[minimum-depth-of-binary-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/minimum-depth-of-binary-tree.py -[Populating Next Right Pointers in Each Node]:https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node/ -[populating-next-right-pointers-in-each-node.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/populating-next-right-pointers-in-each-node.py -[Same Tree]:https://oj.leetcode.com/problems/same-tree/ -[same-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/same-tree.py -[Sum Root to Leaf Numbers]:https://oj.leetcode.com/problems/sum-root-to-leaf-numbers/ -[sum-root-to-leaf-numbers.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sum-root-to-leaf-numbers.py -[Unique Binary Search Trees II]:https://oj.leetcode.com/problems/unique-binary-search-trees-ii/ -[unique-binary-search-trees-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-binary-search-trees-ii.py -[Validate Binary Search Tree]:https://oj.leetcode.com/problems/validate-binary-search-tree.py/ -[validate-binary-search-tree.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/validate-binary-search-tree.py - - ---- - -##Binary Search - -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Find Minimum in Rotated Sorted Array] | [find-minimum-in-rotated-sorted-array.py] | _O(logn)_ | _O(1)_ | Medium | -[Find Minimum in Rotated Sorted Array II] | [find-minimum-in-rotated-sorted-array-ii.py] | _O(logn)_ ~ _O(n)_ | _O(1)_ | Hard | -[Find Peak Element] | [find-peak-element.py] | _O(logn)_ | _O(1)_ | Medium | -[Median of Two Sorted Arrays] | [median-of-two-sorted-arrays.py] | _O(log(m + n)_ | _O(log(m + n)_ | Hard | -[Pow(x, n)] | [powx-n.py] | _O(logn)_ | _O(logn)_ | Medium | -[Search a 2D Matrix] | [search-a-2d-matrix.py] | _O(log m + logn)_ | _O(1)_ | Medium | -[Search for a Range] | [search-for-a-range.py] | _O(logn)_ | _O(1)_ | Medium | -[Search in Rotated Sorted Array] | [search-in-rotated-sorted-array.py] | _O(logn)_ | _O(1)_ | Hard | -[Search in Rotated Sorted Array II] | [search-in-rotated-sorted-array-ii.py] | _O(logn)_ | _O(1)_ | Medium | -[Search Insert Position] | [search-insert-position.py] | _O(logn)_ | _O(1)_ | Medium | -[Sqrt(x)] | [sqrtx.py] | _O(logn)_ | _O(1)_ | Medium | - -[Find Minimum in Rotated Sorted Array]:https://oj.leetcode.com/problems/find-minimum-in-rotated-sorted-array/ -[find-minimum-in-rotated-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/find-minimum-in-rotated-sorted-array.py -[Find Minimum in Rotated Sorted Array II]:https://oj.leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/ -[find-minimum-in-rotated-sorted-array-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/find-minimum-in-rotated-sorted-array-ii.py -[Find Peak Element]:https://oj.leetcode.com/problems/find-peak-element/ -[find-peak-element.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/find-peak-element.py -[Median of Two Sorted Arrays]:https://oj.leetcode.com/problems/median-of-two-sorted-arrays/ -[median-of-two-sorted-arrays.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/median-of-two-sorted-arrays.py -[Pow(x, n)]:https://oj.leetcode.com/problems/powx-n/ -[powx-n.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/powx-n.py -[Search a 2D Matrix]:https://oj.leetcode.com/problems/search-a-2d-matrix/ -[search-a-2d-matrix.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-a-2d-matrix.py -[Search for a Range]:https://oj.leetcode.com/problems/search-for-a-range/ -[search-for-a-range.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-for-a-range.py -[Search in Rotated Sorted Array]:https://oj.leetcode.com/problems/search-in-rotated-sorted-array/ -[search-in-rotated-sorted-array.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-in-rotated-sorted-array.py -[Search in Rotated Sorted Array II]:https://oj.leetcode.com/problems/search-in-rotated-sorted-array-ii/ -[search-in-rotated-sorted-array-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-in-rotated-sorted-array-ii.py -[Search Insert Position]:https://oj.leetcode.com/problems/search-insert-position/ -[search-insert-position.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/search-insert-position.py -[Sqrt(x)]:https://oj.leetcode.com/problems/sqrtx/ -[sqrtx.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sqrtx.py - ---- - -##Breadth-First Search -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Binary Tree Level Order Traversal]| [binary-tree-level-order-traversal.py] | _O(n)_| _O(n)_| Easy | -[Binary Tree Level Order Traversal II]| [binary-tree-level-order-traversal-ii.py] | _O(n)_| _O(n)_| Easy | -[Binary Tree Zigzag Level Order Traversal]| [binary-tree-zigzag-level-order-traversal.py] | _O(n)_| _O(n)_| Medium | -[Clone Graph]| [clone-graph.py] | _O(n)_ | _O(n)_ | Medium | -[Populating Next Right Pointers in Each Node II]|[populating-next-right-pointers-in-each-node-ii.py]| _O(n)_ | _O(1)_ | Hard | -[Surrounded Regions]|[surrounded-regions.py]| _O(m * n)_ | _O(m + n)_ | Medium | -[Word Ladder] |[word-ladder.py] | _O((25n)^n)_ | _O((25n)^n)_ | Medium | - -[Binary Tree Level Order Traversal]:https://oj.leetcode.com/problems/binary-tree-level-order-traversal/ -[binary-tree-level-order-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-level-order-traversal.py -[Binary Tree Level Order Traversal II]:https://oj.leetcode.com/problems/binary-tree-level-order-traversal-ii/ -[binary-tree-level-order-traversal-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-level-order-traversal-ii.py -[Binary Tree Zigzag Level Order Traversal]:https://oj.leetcode.com/problems/binary-tree-zigzag-level-order-traversal/ -[binary-tree-zigzag-level-order-traversal.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/binary-tree-zigzag-level-order-traversal.py -[Clone Graph]:https://oj.leetcode.com/problems/clone-graph/ -[clone-graph.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/clone-graph.py -[Populating Next Right Pointers in Each Node II]:https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ -[populating-next-right-pointers-in-each-node-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/populating-next-right-pointers-in-each-node-ii.py -[Surrounded Regions]:https://oj.leetcode.com/problems/surrounded-regions/ -[surrounded-regions.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/surrounded-regions.py -[Word Ladder]:https://oj.leetcode.com/problems/word-ladder/ -[word-ladder.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-ladder.py - ---- - -##Depth-First Search -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Combination Sum]| [combination-sum.py] | _O(n^m)_ | _O(m)_ | Medium | -[Combination Sum II]| [combination-sum-ii.py]| _O(n! / m!(n-m)!)_| _O(m)_ | Medium | -[Combinations] | [combinations.py] | _O(n!)_ | _O(n)_ | Medium | -[Generate Parentheses]| [generate-parentheses.py]| _O(4^n / n^(3/2)_ | _O(n)_ | Medium | -[N-Queens] | [n-queens.py] | _O(n!)_ | _O(n)_ | Hard | -[N-Queens-II] | [n-queens-ii.py] | _O(n!)_ | _O(n)_ | Hard | -[Palindrome Partitioning] | [palindrome-partitioning.py] | _O(n^2)_ ~ _O(2^n)_ | _O(n^2)_ | Medium | -[Path Sum] | [path-sum.py] | _O(n)_ | _O(logn)_ | Easy | -[Path Sum II] | [path-sum-ii.py] | _O(n)_ | _O(logn)_ | Medium | -[Restore IP Addresses] | [restore-ip-addresses.py] | _O(n^m)_ ~ _O(3^4)_ | _O(n * m)_ ~ _O(3 * 4)_ | Medium | -[Sudoku Solver] | [sudoku-solver.py] | _O((9!)^9)_ | _O(1)_ | Hard | -[Word Search] | [word-search.py] | _O(m * n * 3^p)_ | _O(m * n * p)_ | Medium | - -[Combination Sum]:https://oj.leetcode.com/problems/combination-sum/ -[combination-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/combination-sum.py -[Combination Sum II]:https://oj.leetcode.com/problems/combination-sum-ii/ -[combination-sum-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/combination-sum-ii.py -[Combinations]:https://oj.leetcode.com/problems/combinations/ -[combinations.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/combinations.py -[Generate Parentheses]:https://oj.leetcode.com/problems/generate-parentheses/ -[generate-parentheses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/generate-parentheses.py -[N-Queens]:https://oj.leetcode.com/problems/n-queens/ -[n-queens.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/n-queens.py -[N-Queens-II]:https://oj.leetcode.com/problems/n-queens-ii/ -[n-queens-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/n-queens-ii.py -[Palindrome Partitioning]:https://oj.leetcode.com/problems/palindrome-partitioning/ -[palindrome-partitioning.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/palindrome-partitioning.py -[Path Sum]:https://oj.leetcode.com/problems/path-sum/ -[path-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/path-sum.py -[Path Sum II]:https://oj.leetcode.com/problems/path-sum-ii/ -[path-sum-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/path-sum-ii.py -[Restore IP Addresses]:https://oj.leetcode.com/problems/restore-ip-addresses/ -[restore-ip-addresses.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/restore-ip-addresses.py -[Sudoku Solver]:https://oj.leetcode.com/problems/sudoku-solver/ -[sudoku-solver.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/sudoku-solver.py -[Word Search]:https://oj.leetcode.com/problems/word-search/ -[word-search.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-search.py - ---- - -##Dynamic Programming -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Best Time to Buy and Sell Stock III]| [best-time-to-buy-and-sell-stock-iii.py] | _O(n)_ | _O(1)_ | Hard | -[Climbing Stairs]| [climbing-stairs.py] | _O(n)_ | _O(1)_ | Easy | -[Decode Ways] | [decode-ways.py]| _O(n)_ | _O(1)_ | Medium | -[Distinct Subsequences]|[distinct-subsequences.py]| _O(n^2)_ | _O(n)_ | Hard | -[Dungeon Game] | [dungeon-game.py]| _O(m * n)_ | _O(m + n)_ | Hard | -[Edit Distance]|[edit-distance.py]| _O(m * n)_ | _O(m + n)_ | Hard | -[Interleaving String]|[interleaving-string.py]| _O(m * n)_ | _O(m + n)_ | Hard | -[Maximal Rectangle]|[maximal-rectangle.py]| _O(n^2)_ | _O(n)_ | Hard | -[Maximum Product Subarray]|[maximum-product-subarray.py]| _O(n)_ | _O(1)_ | Medium | -[Maximum Subarray]|[maximum-subarray.py]| _O(n)_ | _O(1)_ | Medium | -[Minimum Path Sum]|[minimum-path-sum.py]| _O(m * n)_ | _O(m + n)_ | Medium | -[Palindrome Partitioning II] | [palindrome-partitioning-ii.py] | _O(n^2)_ | _O(n^2)_ | Hard | -[Regular Expression Matching] | [regular-expression-matching.py] | _O(m * n)_ | _O(n)_ | Hard | -[Scramble String] | [scramble-string.py] | _O(n^4)_ | _O(n^3)_ | Hard | -[Triangle] | [triangle.py] | _O(m * n)_ | _O(n)_ | Medium | -[Unique Binary Search Trees] | [unique-binary-search-trees.py] | _O(n^2)_ | _O(n)_ | Medium | -[Unique Paths] | [unique-paths.py]| _O(m * n)_ | _O(m + n)_ | Medium | -[Unique Paths II] | [unique-paths-ii.py] | _O(m * n)_ | _O(m + n)_ | Medium | -[Word Break] | [word-break.py] | _O(n^2)_ | _O(n)_ | Medium | -[Word Break II] | [word-break-ii.py] | _O(n^2)_ | _O(n)_ | Hard | - -[Best Time to Buy and Sell Stock III]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ -[best-time-to-buy-and-sell-stock-iii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock-iii.py -[Climbing Stairs]:https://oj.leetcode.com/problems/climbing-stairs/ -[climbing-stairs.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/climbing-stairs.py -[Decode Ways]:https://oj.leetcode.com/problems/decode-ways/ -[decode-ways.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/decode-ways.py -[Distinct Subsequences]:https://oj.leetcode.com/problems/distinct-subsequences/ -[distinct-subsequences.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/distinct-subsequences.py -[Dungeon Game]:https://oj.leetcode.com/problems/dungeon-game/ -[dungeon-game.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/dungeon-game.py -[Edit Distance]:https://oj.leetcode.com/problems/edit-distance/ -[edit-distance.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/edit-distance.py -[Interleaving String]:https://oj.leetcode.com/problems/interleaving-string/ -[interleaving-string.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/interleaving-string.py -[Maximal Rectangle]:https://oj.leetcode.com/problems/maximal-rectangle/ -[maximal-rectangle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximal-rectangle.py -[Maximum Product Subarray]:https://oj.leetcode.com/problems/maximum-product-subarray/ -[maximum-product-subarray.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-product-subarray.py -[Maximum Subarray]:https://oj.leetcode.com/problems/maximum-subarray/ -[maximum-subarray.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/maximum-subarray.py -[Minimum Path Sum]:https://oj.leetcode.com/problems/minimum-path-sum/ -[minimum-path-sum.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/minimum-path-sum.py -[Palindrome Partitioning II]:https://oj.leetcode.com/problems/palindrome-partitioning-ii/ -[palindrome-partitioning-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/palindrome-partitioning-ii.py -[Regular Expression Matching]:https://oj.leetcode.com/problems/regular-expression-matching/ -[regular-expression-matching.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/regular-expression-matching.py -[Scramble String]:https://oj.leetcode.com/problems/scramble-string/ -[scramble-string.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/scramble-string.py -[Triangle]:https://oj.leetcode.com/problems/triangle/ -[triangle.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/triangle.py -[Unique Binary Search Trees]:https://oj.leetcode.com/problems/unique-binary-search-trees/ -[unique-binary-search-trees.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-binary-search-trees.py -[Unique Paths]:https://oj.leetcode.com/problems/unique-paths/ -[unique-paths.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-paths.py -[Unique Paths II]:https://oj.leetcode.com/problems/unique-paths-ii/ -[unique-paths-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/unique-paths-ii.py -[Word Break]:https://oj.leetcode.com/problems/word-break/ -[word-break.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-break.py -[Word Break II]:https://oj.leetcode.com/problems/word-break-ii/ -[word-break-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-break-ii.py - ---- - -##Backtracking -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Word Ladder II] |[word-ladder-ii.py] | _O((25n)^n)_ | _O((25n)^n)_ | Hard | - -[Word Ladder II]:https://oj.leetcode.com/problems/word-ladder-ii/ -[word-ladder-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/word-ladder-ii.py - ---- - -##Greedy -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Best Time to Buy and Sell Stock II]| [best-time-to-buy-and-sell-stock-ii.py] | _O(n)_ | _O(1)_ | Medium | -[Candy]| [candy.py] | _O(n)_ | _O(n)_ | Hard | -[Container With Most Water]| [container-with-most-water.py] | _O(n)_ | _O(1)_ | Medium | -[Gas Station]| [gas-station.py] | _O(n)_ | _O(1)_ | Medium | -[Jump Game] | [jump-game.py] | _O(n)_ | _O(1)_ | Medium | -[Jump Game II] | [jump-game-ii.py] | _O(n^2)_ | _O(1)_ | Hard | -[Largest Rectangle in Histogram] | [largest-rectangle-in-histogram.py] | _O(n)_ | _O(n)_ | Hard | Tricky -[Trapping Rain Water] | [trapping-rain-water.py] | _O(n)_ | _O(1)_ | Hard | Tricky -[Wildcard Matching] | [wildcard-matching.py] | _O(m + n)_ | _O(1)_ | Hard | Tricky - -[Best Time to Buy and Sell Stock II]:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ -[best-time-to-buy-and-sell-stock-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/best-time-to-buy-and-sell-stock-ii.py -[Candy]:https://oj.leetcode.com/problems/candy/ -[candy.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/candy.py -[Container With Most Water]:https://oj.leetcode.com/problems/container-with-most-water/ -[container-with-most-water.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/container-with-most-water.py -[Gas Station]:https://oj.leetcode.com/problems/gas-station/ -[gas-station.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/gas-station.py -[Jump Game]:https://oj.leetcode.com/problems/jump-game/ -[jump-game.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/jump-game.py -[Jump Game II]:https://oj.leetcode.com/problems/jump-game-ii/ -[jump-game-ii.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/jump-game-ii.py -[Largest Rectangle in Histogram]:https://oj.leetcode.com/problems/largest-rectangle-in-histogram/ -[largest-rectangle-in-histogram.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/largest-rectangle-in-histogram.py -[Trapping Rain Water]:https://oj.leetcode.com/problems/trapping-rain-water/ -[trapping-rain-water.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/trapping-rain-water.py -[Wildcard Matching]:https://oj.leetcode.com/problems/wildcard-matching/ -[wildcard-matching.py]:https://github.com/kamyu104/LeetCode/blob/master/Python/wildcard-matching.py - ---- - -##SQL -Problem | Solution | Time | Space | Difficulty | Notes ---------------- | --------------- | --------------- | --------------- | -------------- | ----- -[Combine Two Tables] | [combine-two-tables.sql] | _O(m + n)_ | _O(m + n)_ | Easy | -[Consecutive Numbers] | [consecutive-numbers.sql] | _O(n)_ | _O(n)_ | Medium | -[Nth Highest Salary] | [nth-highest-salary.sql] | _O(n^2)_ | _O(n)_ | Medium | -[Rank Scores] | [rank-scores.sql] | _O(n^2)_ | _O(n)_ | Medium | -[Second Highest Salary] | [second-highest-salary.sql] | _O(n)_ | _O(1)_ | Easy | - -[Combine Two Tables]:https://oj.leetcode.com/problems/combine-two-tables/ -[combine-two-tables.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/combine-two-tables.sql -[Consecutive Numbers]:https://oj.leetcode.com/problems/consecutive-numbers/ -[consecutive-numbers.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/consecutive-numbers.sql -[Nth Highest Salary]:https://oj.leetcode.com/problems/nth-highest-salary/ -[nth-highest-salary.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/nth-highest-salary.sql -[Rank Scores]:https://oj.leetcode.com/problems/rank-scores/ -[rank-scores.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/rank-scores.sql -[Second Highest Salary]:https://oj.leetcode.com/problems/second-highest-salary/ -[second-highest-salary.sql]:https://github.com/kamyu104/LeetCode/blob/master/MySQL/second-highest-salary.sql - +##Design + # | Title | Solution | Time | Space | Difficulty | Tag | Note +-----|---------------- | --------------- | --------------- | --------------- | ------------- |--------------| ----- +284| [Peeking Iterator](https://leetcode.com/problems/peeking-iterator/)| [C++](./C++/peeking-iterator.cpp) [Python](./Python/peeking-iterator.py) | _O(1)_ | _O(1)_ | Medium || + +## 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 +