解析
max ksubarray sum: 最大和 of 连续子序列 => 最大和 of k份连续子序列 属于dp,30行代码搞定,注意一些边界。
substr diff: 无queue的区间滑动窗口,记录当前最大值
maxtree:
九章算法中有讲到, 对每个节点,找到离他最近且比它大的左右两个节点中较小的那个,作为他的父节点。
其中,找父节点: 用递增栈分别从左向右和从右向左扫描一次,对每个节点取栈顶元素即可。 在O(n)时间里就可以找到距离该节点最近的比他大的节点。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param A: Given an integer array with no duplicates.
* @return: The root of max tree.
*/
TreeNode* maxTree(vector<int> A) {
// write your code here
int n = A.size();
// allocate tree
TreeNode * nodes = new TreeNode[n];
for(int i =0; i<n; i++){
nodes[i] = TreeNode(A[i]);
}
// obtain the left/right nearest larger node
stack<int> ss;
vector<int> lp(n, -1), rp(n, -1);
for(int i =0; i<n; i++){
while(!ss.empty() && A[i]>A[ss.top()]){
ss.pop();
}
if(!ss.empty()){
lp[i] = ss.top();
}
ss.push(i);
}
ss=stack<int>();
for(int i =n-1; i>=0; i--){
while(!ss.empty() && A[i]>A[ss.top()]){
ss.pop();
}
if(!ss.empty()){
rp[i] = ss.top();
}
ss.push(i);
}
// construct tree
TreeNode * root = NULL;
for(int i = 0; i<n; i++){
if(lp[i]>=0 && (rp[i]<0 || A[rp[i]]>A[lp[i]])){
nodes[lp[i]].right = &nodes[i];
}
else if(rp[i]>=0 && (lp[i]<0 || A[lp[i]]>A[rp[i]])){
nodes[rp[i]].left = &nodes[i];
}else{
root = &nodes[i];
}
}
return root;
}
};
tree iterator:
实质:找一个节点的中序下一个节点。
用dfs(root, p) 在root树中,找p的下一个节点。 代价是O(logn)
如果要O(1)的时间代价,需要一个栈(空间O(logn))保存当前的路径(root ->xx -> p)。
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
* Example of iterate a tree:
* Solution iterator = new Solution(root);
* while (iterator.hasNext()) {
* TreeNode node = iterator.next();
* do something for node
* }
*/
public class Solution {
TreeNode r;
TreeNode p;
boolean org;
//@param root: The root of binary tree.
public Solution(TreeNode root) {
// write your code here
r = p = root;
if(p!=null) while(p.left != null) p=p.left;
org = true;
}
//@return: True if there has next node, or false
public boolean hasNext() {
// write your code here
TreeNode q = p;
if(!org) q = dfs(r, p);
return q != null;
}
//@return: return next node
public TreeNode next() {
// write your code here
if(!org) p = dfs(r, p);
org = false;
return p;
}
private TreeNode dfs(TreeNode root, TreeNode p){
if(root == null || p == null) return null;
if(root.val>p.val){
TreeNode q= dfs(root.left, p);
if(q != null) return q;
else return root;
}else{
return dfs(root.right, p) ;
}
}
}
动态Median
用一个大顶堆维护较小的一半序列,一个小顶堆维护较大的一半序列。
保持两边序列长度平衡,每次取大顶堆的顶,即为中位数。
class Solution {
public:
/**
* @param nums: A list of integers.
* @return: The median of numbers
*/
vector<int> medianII(vector<int> &nums) {
// write your code here
priority_queue<int> lq;
priority_queue<int, vector<int>, greater<int> >rq; // top small, bottom bigger
vector<int> rs;
for(int i = 0; i<nums.size(); i++){
if(lq.empty() || nums[i]<=lq.top())
lq.push(nums[i]);
else rq.push(nums[i]);
if(lq.size()>rq.size()+1){
int t = lq.top();
lq.pop(), rq.push(t);
}else if(lq.size()<rq.size()){
int t = rq.top();
rq.pop(), lq.push(t);
}
rs.push_back(lq.top());
}
return rs;
}
};
remove bst node
这个题目不好写,如果删除一个节点p,先找到他的父节点prt,然后找到他的左子数最大点pre以及父节点preprt,或右子树最小点nxt以及父节点nxtprt,然后用该点pre/nxt替换掉自己就可以了。
指针运算很容易出错地奥! 尤其是当preprt == p的时候, prt==null的时候,都需要注意。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of the binary search tree.
* @param value: Remove the node with given value.
* @return: The root of the binary search tree after removal.
*/
TreeNode* removeNode(TreeNode* root, int value) {
// write your code here
if(!root) return NULL;
if(root->val == value ){
if(root->left){
TreeNode *t;
TreeNode *p = preNode(root, &t);
// remove pre, insert at root
if(t!=root){
t->right = p->left, p->left = root->left;
}
p->right = root->right;
delete root; return p;
}else if(root->right){
TreeNode *t;
TreeNode *p = nxtNode(root, &t);
if(t!=root){
t->left= p->right, p->right = root->right;
}
p->left = root->left;
delete root; return p;
}else{
delete root; return NULL;
}
}else{
if(root->val > value){
root->left = removeNode(root->left, value);
return root;
}else{
root->right =removeNode(root->right, value);
return root;
}
}
}
// @param root: no equal to NULL
// get root's largest smaller sub-node, and its parent
TreeNode *preNode(TreeNode *root, TreeNode **prt){
TreeNode *p = root->left; *prt = root;
if(p) while(p->right) *prt = p, p = p->right;
return p;
}
TreeNode *nxtNode(TreeNode *root, TreeNode **prt){
TreeNode *p = root->right; *prt = root;
if(p) while(p->left) *prt = p, p = p->left;
return p;
}
};
Word Search II
class Solution {
public:
/**
* @param board: A list of lists of character
* @param words: A list of string
* @return: A list of string
*/
vector<string> wordSearchII(vector<vector<char> > &board, vector<string> &words) {
// write your code here
int m = board.size();
vector<string> res;
if(!m) return res;
int n = board[0].size();
vector<vector<bool> >visit(m, vector<bool>(n, false));
dr[0][0] = -1, dr[0][1] = 0, dr[1][0] = 1, dr[1][1] = 0;
dr[2][0] = 0, dr[2][1] = -1, dr[3][0] = 0, dr[3][1] = 1;
for(int i = 0; i<words.size(); i++){
for(int j = 0; j<m; j++){
int k = 0;for( ; k<n; k++){
if(dfs(board, words[i], visit, 0, j, k)) {
res.push_back(words[i]);
break;
}
}
if(k<n) break;
}
}
return res;
}
int dr[4][2] ;//= {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
bool dfs(vector<vector<char> >& board, const string &word, vector<vector<bool> > &visit, int idx, int x, int y){
//if(idx>=word.length()) return true;//@remove
if(board[x][y]!=word[idx]) return false;
if(idx==word.length()-1) return true; //@add
visit[x][y] = true;
bool s = false;
int m = visit.size(), n = visit[0].size();
for(int i = 0; i<4; i++){
int x1 = x+dr[i][0], y1 = y+dr[i][1];
if(x1>=0 && x1<m && y1>=0 && y1<n && !visit[x1][y1])
if(dfs(board, word, visit, idx+1, x1, y1)){
s = true; break;
}
}
visit[x][y] = false;
return s;
}
};
MAX k subarray sum
三维DP:
- maxn [i][k] = max{ maxn[i-1][k], maxn[j<i][k-1] + maxsub[j+1][i] }
其中maxsub[i][j]代表【i,j】区间最大的连续子段的sum,
- maxsub[i][j] = max{maxsub[i][j-1], max{ sum([k, j-1]), i<=k<=j }+ nums[j] }, 前后两项分别表示该子段不使用nums[j]和使用
class Solution {
public:
/**
* @param nums: A list of integers
* @param k: An integer denote to find k non-overlapping subarrays
* @return: An integer denote the sum of max k non-overlapping subarrays
*/
int maxKSubArrays(vector<int> nums, int K) {
// write your code here
int n = nums.size();
if(!n || n<K) return 0;
vector<vector<int> > one(n, vector<int>(n, 0));
for(int i = 0; i<n; i++){
one[i][i] = nums[i];
int lst = max(0, nums[i]);
for(int j = i+1; j<n; j++){
one[i][j] = max(one[i][j-1], lst+nums[j]);
lst += nums[j];//@error: not nums[i]
if(lst<0) lst = 0;
// cout<<i<<','<<j<<": "<<one[i][j]<<endl;
}
}
vector<vector<int> > m(n, vector<int>(K+1));
for(int i = 0; i<n; i++){
m[i][1] = one[0][i];
for(int j = 2; j<=i+1 && j<=K; j++){
m[i][j] = m[i-1][j-1]+nums[i];
if(j<i+1) m[i][j] =max(m[i][j], m[i-1][j]);
if(nums[i]>0 && j<i+1)
for(int k = i-1; k>=j-1; k--){//@error: k>=j-1 not j
m[i][j] = max(m[i][j], m[k-1][j-1]+one[k][i]);
}
// cout<<i<<" divide "<<j<<": "<<m[i][j]<<endl;
}
}
return m[n-1][K];
}
};
substr diff
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
//int cnt[i][j][l]= m; // given m, return max l
// cnt[i-j]
int N; cin>>N;
for(int ii=0; ii<N; ii++){
string s, t; int m;
cin>>m>>s>>t;
int maxL=-1;
int n = s.length();
for(int i = 0; i<n; i++){
int c = 0, k = i;
for(int j = i; j<n; j++){
if(s[j] != t[j-i]) c++;
while(c>m) { while(s[k] == t[k-i]) k++; k++; c--;}
maxL = max(maxL, j-k+1);
}
}
for(int i = 0; i<n; i++){
int c = 0, k = i;
for(int j = i; j<n; j++){
if(t[j] != s[j-i]) c++;
while(c>m) { while(t[k] == s[k-i]) k++; k++; c--;}
maxL = max(maxL, j-k+1);
}
}
cout<<maxL<<endl;
}
return 0;
}
附加:二叉树线索化
http://baike.baidu.com/link?url=h2Z7V2zrCul8bVb5ARq9YFxRKLp_0ba_eoxtB1FcUetAhOy-l0SulzlB9Me_wHxJ7O_3-NRubjsPxWHc2n42Da
建立线索二叉树,或者说对二叉树线索化,实质上就是遍历一棵二叉树。在遍历过程中,访问结点的操作是检查当前的左,右指针域是否为空,将它们改为指向前驱结点或后续结点的线索。为实现这一过程,设指针pre始终指向刚刚访问的结点,即若指针p指向当前结点,则pre指向它的前驱,以便设线索。
另外,在对一颗二叉树加线索时,必须首先申请一个头结点,建立头结点与二叉树的根结点的指向关系,对二叉树线索化后,还需建立最后一个结点与头结点之间的线索。
下面是建立中序二叉树的
递归算法,其中pre为全局变量。
序列化和反序列化
方法1 BFS
BFS分层序列化,空指针用#代替。反序列化的时候,用一个队列不断把当前节点的子节点添加进来,空节点利用bfs顺序的固定性。
(node) (node) ... # .. (node) ... #