偷了两天懒,今天继续
96. 不同的二叉搜索树 - medium
动态规划求ans[n]分三种情况:
- 以1为root时,ans[n] = ans[n-1];(第一和最后一棵树)
- 以n为root时,ans[n] = ans[n-1];(第二和第三棵树)
- 以除了1和n为root时,则是左边至少有一个节点的树的数量*右边至少有一个节点的树的数量,的和,就是下面代码中那个for循环
//14.04
//14.22
class Solution {
vector<int> ans;
int helper(int n) {
if(n <= 1) return 1;
if(n == 2) return 2;
if(ans[n] != -1) return ans[n];
int tmp = n-1, sum = 0; //这里的tmp是代表除了root意外还有多少个节点
for(int i = 1; tmp-i >= 1; i++) { //i是指左子树的节点数,
sum += helper(i)*helper(tmp-i); //tmp-i >= 1就是右子树至少有一个节点
}
ans[n] = helper(n-1)*2+sum;
return ans[n];
}
public:
int numTrees(int n) {
if(n <= 1) return 1;
if(n == 2) return 2;
ans.resize(n+1, -1);
helper(n);
return ans[n]; //其实直接返回helper(n)即可
}
};
105. 从前序与中序遍历序列构造二叉树 - medium
这题重点在于如何通过那两个数组画出这棵树,之后就是套娃了,弄清楚如何去套娃即可
//14.51
//15.29
class Solution {
void helper(TreeNode* &root, vector<int> & pre, vector<int> &ino, int l_pre, int r_pre, int l_ino, int r_ino) {
if(l_ino > r_ino || l_pre > r_pre) return ;
if(l_ino == r_ino) {
root = new TreeNode(ino[l_ino]);
return ;
}
int i = l_ino;
for(; i <= r_ino; i++) {
if(ino[i] == pre[l_pre]) break;
}
root = new TreeNode(ino[i]);
int cnt_l = i-l_ino;
int cnt_r = r_ino-i;
if(cnt_l) helper(root->left, pre, ino, l_pre+1, r_pre-cnt_r, i-cnt_l, i-1);
if(cnt_r) helper(root->right, pre, ino, r_pre-cnt_r+1, r_pre, i+1, r_ino);
}
public:
TreeNode* buildTree(vector<int>& pre, vector<int>& ino) {
if(pre.empty()) return nullptr;
TreeNode* root = nullptr;
helper(root, pre, ino, 0, pre.size()-1, 0, pre.size()-1);
return root;
}
};
3. 无重复字符的最长子串** - medium
滑动窗口用queue
//15.59
//16.40
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty()) return 0;
if(s.size() == 1) return 1;
int check[1000] = {0};
queue<char> tmp;
int cnt = 1;
tmp.push(s[0]);
check[s[0]] = 1;
for(int i = 1; i < s.size(); i++) {
if(check[s[i]]) {
cnt = cnt >= tmp.size()? cnt : tmp.size();
while(tmp.front() != s[i]) {
check[tmp.front()] = 0;
tmp.pop();
}
tmp.pop();
}
check[s[i]] = 1;
tmp.push(s[i]);
}
return cnt >= tmp.size()? cnt : tmp.size();
}
};