算法苦手
二叉树剪枝
来源: https://leetcode.cn/problems/pOCWxh/
想法:
后序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* pruneTree(TreeNode* root) {
if (root == nullptr) {
return nullptr;
}
TreeNode* left = pruneTree(root->left);
TreeNode* right = pruneTree(root->right);
if (root->val == 0 && left == nullptr && right == nullptr) {
return nullptr;
}
root->left = left;
root->right = right;
return root;
}
};
时间复杂度: O(n)
空间复杂度: **O(n) **
从根节点到叶节点的路径数字之和
来源: https://leetcode.cn/problems/3Etpl5/
想法:
遍历树即可
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int sum = 0;
void run(TreeNode* node, int val) {
if (node->left != nullptr) run(node->left,val * 10 + node->val);
if (node->right != nullptr) run(node->right,val * 10 + node->val);
if (node->left == nullptr && node->right == nullptr) sum += val * 10 + node->val;
}
int sumNumbers(TreeNode* root) {
run(root,0);
return sum;
}
};
时间复杂度: O(n)
空间复杂度: **O(n) **
向下的路径节点之和
来源: https://leetcode.cn/problems/6eUYwP/
想法:
遍历树的同时维护节点路径
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int res = 0;
int target;
void preorder(TreeNode* node, vector<int>& road) {
road.push_back(node->val);
if (node->left != nullptr) preorder(node->left,road);
if (node->right != nullptr) preorder(node->right,road);
int tmp = 0;
for (int i = road.size() - 1 ; i >= 0 ; i--) {
tmp += road[i];
if (tmp == target) {
res++;
}
}
road.pop_back();
}
int pathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return 0;
vector<int> v;
target = targetSum;
preorder(root,v);
return res;
}
};
时间复杂度: O(n²)
空间复杂度: **O(n) **
展平二叉搜索树
来源: https://leetcode.cn/problems/NYBBNL/
想法:
前序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode *res = nullptr;
TreeNode *head;
void midorder(TreeNode *node) {
if (node->left != nullptr) midorder(node->left);
if (res == nullptr) {
res = new TreeNode(node->val);
head = res;
}
else {
res->right = new TreeNode(node->val);
res = res->right;
}
if (node->right != nullptr) midorder(node->right);
}
TreeNode* increasingBST(TreeNode* root) {
midorder(root);
return head;
}
};
时间复杂度: O(n²)
空间复杂度: **O(n) **
二叉搜索树中的中序后继
来源: https://leetcode.cn/problems/P5rCT8/
想法:
中序遍历
/**
* 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) {
stack<TreeNode*> s;
bool sign = false;
while (root != nullptr || !s.empty()) {
while (root != nullptr) {
s.push(root);
root = root->left;
}
root = s.top();
s.pop();
if (sign) break;
if (root == p) sign = true;
root = root->right;
}
return root;
}
};
时间复杂度: O(n)
空间复杂度: **O(n) **
所有大于等于节点的值之和
来源: https://leetcode.cn/problems/w6cpku/
想法:
中序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* convertBST(TreeNode* root) {
TreeNode *tmp1 = root, *tmp2 = root;
stack<TreeNode*> s;
int sum = 0;
int prev = 0;
while (tmp1 != nullptr || !s.empty()) {
while (tmp1 != nullptr) {
s.push(tmp1);
tmp1 = tmp1->left;
}
tmp1 = s.top();
s.pop();
sum += tmp1->val;
tmp1 = tmp1->right;
}
while (tmp2 != nullptr || !s.empty()) {
while (tmp2 != nullptr) {
s.push(tmp2);
tmp2 = tmp2->left;
}
tmp2 = s.top();
s.pop();
int tmp = tmp2->val;
tmp2->val = sum - prev;
prev += tmp;
tmp2 = tmp2->right;
}
return root;
}
};
时间复杂度: O(n)
空间复杂度: **O(n) **
二叉搜索树中两个节点之和
来源: https://leetcode.cn/problems/opLdQZ/
想法:
中序遍历,用哈希表存储已经遍历到的节点的值,然后每遍历一个节点,只需要找哈希表里是否存在 k - val 即可
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool findTarget(TreeNode* root, int k) {
stack<TreeNode*> s;
set<int> base;
while (root != nullptr || !s.empty()) {
while (root != nullptr) {
s.push(root);
root = root->left;
}
root = s.top();
s.pop();
if (base.find(k - root->val) != base.end()) return true;
base.insert(root->val);
root = root->right;
}
return false;
}
};
时间复杂度: O(n)
空间复杂度: **O(n) **
日程表
来源: https://leetcode.cn/problems/opLdQZ/
想法:
线段树,left存储日程在节点之前的,right存储日程在节点之后的
class MyCalendar {
public:
struct TreeNode{
TreeNode* left;
TreeNode* right;
int start;
int end;
TreeNode(int x, int y) : start(x), end(y), left(nullptr), right(nullptr) {}
};
TreeNode *root = nullptr;
MyCalendar() {
}
bool book(int start, int end) {
if (root == nullptr) {
root = new TreeNode(start,end);
return true;
}
TreeNode *tmp = root;
while (tmp != nullptr) {
if (end <= tmp->start) {
if (tmp->left == nullptr) {
tmp->left = new TreeNode(start,end);
return true;
}
tmp = tmp->left;
}else if (start >= tmp->end){
if (tmp->right == nullptr) {
tmp->right = new TreeNode(start,end);
return true;
}
tmp = tmp->right;
}else return false;
}
return true;
}
};
时间复杂度: O(logn)
空间复杂度: **O(n) **
实现前缀树
来源: https://leetcode.cn/problems/QC3q1f/
想法:
字典树
class Trie {
public:
vector<Trie*> children;
bool isEnd;
/** Initialize your data structure here. */
Trie() : children(26), isEnd(false){}
/** Inserts a word into the trie. */
void insert(string word) {
Trie* node = this;
for (char c : word) {
if (node->children[c - 'a'] == nullptr) {
node->children[c - 'a'] = new Trie();
}
node = node->children[c - 'a'];
}
node->isEnd = true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie* node = this;
for (char c : word) {
if (node->children[c - 'a'] == nullptr) {
return false;
}
node = node->children[c - 'a'];
}
return node != nullptr && node->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie* node = this;
for (char c : prefix) {
if (node->children[c - 'a'] == nullptr) {
return false;
}
node = node->children[c - 'a'];
}
return node != nullptr;
}
};
时间复杂度: **初始化为 O(1),其余操作为 O( | S | ),其中 | S | 是每次插入或查询的字符串的长度。** |
空间复杂度: **O(∣T∣⋅Σ),其中 | T | 为所有插入字符串的长度之和,Σ 为字符集的大小,本题 Σ=26。** |
替换单词
来源: https://leetcode.cn/problems/QC3q1f/
想法:
哈希表
class Solution {
public:
string replaceWords(vector<string>& dictionary, string sentence) {
string res = "";
string temp = sentence + " ";
vector<string> strs;
size_t pos = temp.find(" ");
while (pos != temp.npos) {
string tmp = temp.substr(0, pos);
strs.push_back(tmp);
temp = temp.substr(pos + 1, temp.size());
pos = temp.find(" ");
}
set<string> roots;
for (string i : dictionary) {
roots.insert(i);
}
for (string i : strs) {
bool flag = false;
for (int j = 1 ; j < i.length() ; j++) {
string tmp = i.substr(0,j);
if (roots.find(tmp) != roots.end()) {
res.append(tmp).append(" ");
flag = true;
break;
}
}
if (!flag) res.append(i).append(" ");
}
res = res.substr(0,res.size() - 1);
return res;
}
};
时间复杂度: O(n)
空间复杂度: O(n)
神奇的字典
来源: https://leetcode.cn/problems/US1pGT/
想法:
前缀树,遍历字符串,对每个字符存在25种替换,如果遍历其后面的子串可以遍历到尾,就返回true,否则返回false。
class MagicDictionary {
public:
vector<MagicDictionary*> children;
bool isEnd;
/** Initialize your data structure here. */
MagicDictionary() : children(26), isEnd(false){}
void buildDict(vector<string> dictionary) {
for (string str : dictionary) {
MagicDictionary* node = this;
for (char c : str) {
if (node->children[c - 'a'] == nullptr) {
node->children[c - 'a'] = new MagicDictionary();
}
node = node->children[c - 'a'];
}
node->isEnd = true;
}
}
bool search(string searchWord) {
MagicDictionary* node = this;
int n = searchWord.length();
for (int i = 0 ; i < n ; i++) {
int num = searchWord[i] - 'a';
for (int x = 0 ; x < 26 ; x++) {
if (x == num || node->children[x] == nullptr) continue;
string tmp_str = searchWord.substr(i + 1);
auto tmp_node = node->children[x];
bool flag = true;
for (int j = 0 ; j < tmp_str.length() ; j++) {
if (tmp_node->children[tmp_str[j] - 'a'] == nullptr) {
flag = false;
break;
}
tmp_node = tmp_node->children[tmp_str[j] - 'a'];
}
if (flag) flag = tmp_node->isEnd;
if (flag) return true;
}
if (node->children[num] == nullptr) return false;
node = node->children[num];
}
return false;
}
};
时间复杂度: **O( | S | ⋅ Σ),其中 | S | 是每次插入或查询的字符串的长度, Σ 为字符集的大小,本题 Σ=26。** |
空间复杂度: **O( | T | ⋅Σ),其中 | T | 为所有插入字符串的长度之和,Σ 为字符集的大小,本题 Σ=26。** |
单词之和
来源: https://leetcode.cn/problems/z1R5dt/
想法:
前缀树加深度遍历
class MapSum {
public:
vector<MapSum*> child;
bool isEnd;
map<string,int> table;
int res = 0;
/** Initialize your data structure here. */
MapSum() : child(26), isEnd(false){}
void insert(string key, int val) {
table[key] = val;
MapSum *node = this;
for (char c : key) {
if (node->child[c - 'a'] == nullptr) {
node->child[c - 'a'] = new MapSum();
}
node = node->child[c - 'a'];
}
node->isEnd = true;
}
void dst(MapSum* node, string str) {
for (int i = 0 ; i < 26 ; i++) {
if (node->child[i] != nullptr) {
char c = 'a' + i;
dst(node->child[i],str + c);
}
}
if (node->isEnd) res += table[str];
}
int sum(string prefix) {
MapSum* tmp = this;
bool flag = true;
for (char c : prefix) {
if (tmp->child[c - 'a'] == nullptr) {
flag = false;
break;
}
tmp = tmp->child[c - 'a'];
}
if (!flag) return 0;
else dst(tmp,prefix);
int v = res;
res = 0;
return v;
}
};
最大的异或
来源: https://leetcode.cn/problems/ms70jA/
想法:
将每个数字都化为32位的二进制数,然后生成一个前缀树,再对每个数进行遍历前缀树,对于每个节点,如果当前数的位为0,就走右子树,如果为0就走左子树(因为如果能保证当前位异或的结果为1一定是最大的)。
class Solution {
struct tree{
tree* left;
tree* right;
};
public:
int findMaximumXOR(vector<int>& nums) {
int res = -1;
auto root = new tree();
for (int num : nums) {
tree* node = root;
for (int i = 30 ; i >= 0 ; i--) {
int bit = (num >> i ) & 1;
if (bit == 0) {
if (node->left == nullptr) node->left = new tree();
node = node->left;
}
else{
if (node->right == nullptr) node->right = new tree();
node = node->right;
}
}
}
for (int num : nums) {
tree* node = root;
int tmp_res = 0;
bool flag = false;
for (int i = 30 ; i >= 0 ; i--) {
int bit = (num >> i ) & 1;
if (flag) tmp_res *= 2;
if (bit == 0) {
if (node->right != nullptr) {
tmp_res++;
node = node->right;
}else node = node->left;
}else {
flag = true;
if (node->left != nullptr) {
tmp_res++;
node = node->left;
}else node = node->right;
}
}
res = max(res,tmp_res);
}
return res;
}
};
时间复杂度:O(nlogC),其中 n是数组 nums 的长度,C 是数组中的元素范围,在本题中 C < 2^{31}。
空间复杂度:O(nlogC),其中 n是数组 nums 的长度,C 是数组中的元素范围,在本题中 C < 2^{31}。
查找插入位置
来源: https://leetcode.cn/problems/N6YdxV/
想法:
二分查找
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1, ans = n;
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
山峰数组的顶部
来源: https://leetcode.cn/problems/N6YdxV/
想法:
二分查找
class Solution {
public:
int peakIndexInMountainArray(vector<int>& arr) {
int n = arr.size();
int left = 1, right = n - 2, ans = 0;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] > arr[mid + 1]) {
ans = mid;
right = mid - 1;
}
else {
left = mid + 1;
}
}
return ans;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
排序数组中只出现一次的数字
来源: https://leetcode.cn/problems/skFtm2/
想法:
二分查找,在查找时,判断当前数字是否和前一个或者后一个相等,如果都不相等,则返回;如果相等,则判断这两个数字中索引较小的那一个的索引是奇数还是偶数,如果是奇数说明要找的结果在左边,否则在右边。
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int n = nums.size();
if (n == 1) return nums[0];
int left = 0, right = n - 1;
while (left != right - 1) {
int mid = ((right - left) / 2) + left;
if (nums[mid] == nums[mid - 1]) {
if ((mid - 1) % 2 == 0) left = mid;
else right = mid;
}else if (nums[mid] == nums[mid + 1]){
if (mid % 2 == 0) left = mid;
else right = mid;
}else {
return nums[mid];
}
}
if (left == 0) return nums[left];
if (right == n - 1) return nums[right];
return 0;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
狒狒吃香蕉
来源: https://leetcode.cn/problems/skFtm2/
想法:
二分答案
class Solution {
public:
int minEatingSpeed(vector<int>& piles, int h) {
int n = piles.size();
int max_i = -1;
for (int i : piles) max_i = max(max_i,i);
int l = 1, r = max_i;
while (l != r - 1) {
int mid = (l + r) / 2;
int tmp = 0;
for (int i : piles) {
int d = i / mid;
if (d * mid == i) tmp += d;
else tmp += (d + 1);
}
if (tmp > h) l = mid;
if (tmp <= h) r = mid;
}
int tmp = 0;
for (int i : piles) {
int d = i / l;
if (d * l == i) tmp += d;
else tmp += (d + 1);
}
if (tmp <= h) return l;
else return r;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
合并区间
来源: https://leetcode.cn/problems/SsGoHC/
想法:
按照左边界建了一个BST,然后中序遍历,分类讨论即可。
class Solution {
struct tree{
tree* left;
tree* right;
int l;
int r;
tree(int x, int y) : l(x), r(y), left(nullptr),right(nullptr) {}
};
public:
vector<vector<int>> res;
void midorder(tree* node) {
if (node->left != nullptr) midorder(node->left);
if (res.empty()) {
res.push_back({node->l,node->r});
}else {
vector<int> &tmp = res.back();
if (node->l <= tmp[1] && node->r >= tmp[1]) tmp[1] = node->r;
else if (node->l > tmp[1]) {
res.push_back({node->l,node->r});
}
}
if (node->right != nullptr) midorder(node->right);
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
tree *root = new tree(intervals[0][0],intervals[0][1]);
for (int i = 1 ; i < intervals.size() ; i++) {
tree *tmp = root;
int l = intervals[i][0];
int r = intervals[i][1];
while (tmp != nullptr) {
if (l <= tmp->l) {
if (tmp->left == nullptr) {
tmp->left = new tree(l,r);
break;
}
tmp = tmp->left;
}else if (l > tmp->l) {
if (tmp->right == nullptr) {
tmp->right = new tree(l,r);
break;
}
tmp = tmp->right;
}
}
}
midorder(root);
return res;
}
};
时间复杂度:O(nlogn)
空间复杂度:O(n)
数组中的第k大的数字
来源: https://leetcode.cn/problems/xx4gT2/
想法:
快排
class Solution {
public:
int res;
int k;
int getPivot(vector<int> &nums, int left, int right) {
int random = rand() % (right - left + 1) + left;
swap(nums[random], nums[right]);
int index = left;
for (int i = left; i < right; i++) {
if (nums[i] > nums[right]) {
swap(nums[i], nums[index++]);
}
}
swap(nums[index], nums[right]);
return index;
}
void qsort(vector<int> &nums, int left, int right) {
int pivot = getPivot(nums,left,right);
if (pivot == k - 1) {
res = nums[pivot];
return;
}else if (pivot < k) qsort(nums,pivot + 1, right);
else qsort(nums,left, pivot - 1);
}
int findKthLargest(vector<int>& nums, int k) {
this->k = k;
qsort(nums,0,nums.size() - 1);
return res;
}
};
时间复杂度:O(n)
空间复杂度:O(logn)
生成匹配的括号
来源: https://leetcode.cn/problems/IDBivT/
想法:
回溯
class Solution {
public:
void run(int left,int right, int unpaired, vector<string> &ans, string & now, int n) {
if (left == n && right == n && unpaired == 0) {
ans.emplace_back(now);
return;
}
if (left < n) {
now += "(";
run(left + 1,right,unpaired + 1,ans,now,n);
now.pop_back();
}
if (unpaired != 0) {
now += ")";
run(left, right + 1, unpaired - 1, ans, now, n);
now.pop_back();
}
}
vector<string> generateParenthesis(int n) {
vector<string> ans;
string now = "(";
run(1,0,1,ans,now,n);
return ans;
}
};
时间复杂度:?(算不来)
空间复杂度:?(算不来)
分割回文子字符串
来源: https://leetcode.cn/problems/M99OJA/
想法:
回溯
class Solution {
public:
bool judge(string s) {
int l = 0, r = s.length() - 1;
while (l <= r) {
if (s[l] != s[r]) return false;
l++,r--;
}
return true;
}
void run(vector<vector<string>>& ans, vector<string> &now, int idx, string s) {
if (idx == s.length()) {
bool flag = true;
for (string &i : now) {
if (!judge(i)) {
flag = false;
break;
}
}
if (flag) ans.emplace_back(now);
return;
}
int now_index = now.size() - 1;
string now_str = now[now_index];
now_str += s[idx];
now[now_index] = now_str;
run(ans,now,idx + 1,s);
now_str.pop_back();
now[now_index] = now_str;
string tmp;
tmp = s.substr(idx,1);
now.emplace_back(tmp);
run(ans,now,idx + 1,s);
now.pop_back();
}
vector<vector<string>> partition(string s) {
vector<vector<string>> ans;
vector<string> now;
string first = s.substr(0,1);
now.emplace_back(first);
if (s.length() == 1) {
ans.emplace_back(now);
return ans;
}
run(ans,now,1,s);
return ans;
}
};
时间复杂度:?(算不来)
空间复杂度:?(算不来)