线段树
用处:给定数组v(n),求数组某区间[i,j]内的最大值(下标)/最小值(下标)/和
struct SegTreeNode
{
int le,ri; //区间左右值,数组[le,ri],le和ri对应数组v的下标
Node *left;
Node *right;
//以上四个参数是必须的,下面可以根据需要增加自定义参数
int sum;//sum=v[le]+...+v[ri]
int max;//max=max(v[le],...,v[ri])
int minIndex;//v[minIndex]=min(v[le],...,v[ri])
SegTreeNode(int le,int ri) : le(le),ri(ri), left(NULL), right(NULL){}
};
SegTreeNode *SegTreeBuild(vector<int>& v, int le ,int ri) {
if(le>ri)return nullptr;
SegTreeNode *root = new SegTreeNode(le,ri);
if(le==ri){root->sum=v[le],root->max=v[le],root->minIndex=le;}//叶子节点
else{
int mid = (ri +le) >>1;
root->left = SegTreeBuild(v, le , mid ) ;
root->right = SegTreeBuild(v, mid+1 , ri ) ;
root->max=max(root->left->max,root->right->max);//更新max
root->sum=root->left->sum+root->right->sum;//更新sum
root->minIndex=v[root->left->minIndex]>v[root->right->minIndex]?root->right->minIndex:root->left->minIndex;//更新minIndex
}
return root;
}
void addValue(SegTreeNode *root , int addIndex , int addValue)//v[addIndex]+=addValue
{
if(root->le==root->ri&&root->le==addIndex){root->max+=addValue,root->sum+=addValue;}
else{
int mid=(root->le+root->ri)>>1;
if(addIndex>=mid) addValue(root->right,addIndex,addValue);
else addValue(root->left,addIndex,addValue);
root->max=max(root->left->max,root->right->max);//更新max
root->sum=root->left->sum+root->right->sum;//更新sum
root->minIndex=v[root->left->minIndex]>v[root->right->minIndex]?root->right->minIndex:root->left->minIndex;//更新minIndex
}
}
int getSum(SegTreeNode* root,int le,int ri){
if(root->le==le&&root->root->ri==ri)return root->sum;
int mid=(root->le+root->ri)>>1;
if(ri<=mid)return sum(root->left,le,ri);
else if(le>mid)return sum(root->right,le,ri);
else return sum(root->left,le,mid)+sum(root->right,mid+1,ri);//+
}
int getMax(SegTreeNode* root,int le,int ri){
if(root->le==le&&root->root->ri==ri)return root->max;
int mid=(root->le+root->ri)>>1;
if(ri<=mid)return max(root->left,le,ri);
else if(le>mid)return max(root->right,le,ri);
else return max(max(root->left,le,mid),max(root->right,mid+1,ri));//max(a,b)
}
int getMinIndex(vector<int>& v,SegTreeNode* root,int le,int ri){//v
if(root->le==le&&root->ri==ri)return root->minIndex;
int mid=(root->le+root->ri)>>1;
if(ri<=mid)return getMinIndex(v,root->left,le,ri);
else if(le>mid)return getMinIndex(v,root->right,le,ri);
else {
int leftMinIndex=getMinIndex(v,root->left,le,mid);
int rightMinIndex=getMinIndex(v,root->right,mid+1,ri);
return v[leftMinIndex]>v[rightMinIndex]?rightMinIndex:leftMinIndex;//
}
}
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
输入: [2,1,5,6,2,3] 输出: 10
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//分治
if(heights.size()==0)return 0;
if(heights.size()==1)return heights[0];
return helper(heights,0,heights.size()-1);
}
int helper(vector<int>& v,int le,int ri){
if(le>ri)return 0;
if(le==ri)return v[le];
int minIndex=le;
for(int i=le+1;i<=ri;++i)
if(v[minIndex]>v[i])
minIndex=i;
int maxS=minIndex==le?0:helper(v,le,minIndex-1);
int rBig=minIndex+1;
while(rBig<=ri&&v[rBig]==v[minIndex])
++rBig;
maxS=rBig>ri?maxS:max(maxS,helper(v,rBig,ri));
return max(maxS,v[minIndex]*(ri-le+1));
}
};
线段树方法
class Solution {
public:
struct SegTreeNode{
int le,ri;
SegTreeNode *left,*right;
int minIndex;//数组下标,vec[minIndex]才是最小值
SegTreeNode(int le,int ri):le(le),ri(ri),left(nullptr),right(nullptr){}
};
int largestRectangleArea(vector<int>& heights) {
//分治
if(heights.size()==0)return 0;
if(heights.size()==1)return heights[0];
SegTreeNode* root=SegTreeBuild(heights,0,heights.size()-1);
return getMax(heights,root,0,heights.size()-1);
}
SegTreeNode* SegTreeBuild(vector<int>& v,int le,int ri){
if(le>ri)return nullptr;
SegTreeNode* root=new SegTreeNode(le,ri);
if(le==ri)
root->minIndex=le;
else{
int mid=(le+ri)>>1;
root->left=SegTreeBuild(v,le,mid);
root->right=SegTreeBuild(v,mid+1,ri);
root->minIndex=v[root->left->minIndex]>v[root->right->minIndex]?root->right->minIndex:root->left->minIndex;
}
return root;
}
int getMin(vector<int>& v,SegTreeNode* root,int le,int ri){
if(root->le==le&&root->ri==ri)return root->minIndex;
int mid=(root->le+root->ri)>>1;
if(ri<=mid)return getMin(v,root->left,le,ri);
else if(le>mid)return getMin(v,root->right,le,ri);
else {
int leftMinIndex=getMin(v,root->left,le,mid);
int rightMinIndex=getMin(v,root->right,mid+1,ri);
return v[leftMinIndex]>v[rightMinIndex]?rightMinIndex:leftMinIndex;
}
}
int getMax(vector<int>& v,SegTreeNode* root,int le,int ri){
if(le>ri)return 0;//
if(le==ri)return v[le];
int minIndex=getMin(v,root,le,ri);
int mid=(le+ri)>>1;
int leftMax=getMax(v,root,le,minIndex-1);
int rightMax=getMax(v,root,minIndex+1,ri);
return max((ri-le+1)*v[minIndex],max(leftMax,rightMax));
}
};
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//递增栈
if(heights.size()==0)return 0;
if(heights.size()==1)return heights[0];
stack<int> s;
s.push(0);
vector<int> len(heights.size(),-1);
int i=1;
int maxS=0;
while(s.size()||i<heights.size()){
if(s.size()==0||i<heights.size()&&heights[i]>=heights[s.top()])
s.push(i++);
else{
len[s.top()]+=i-s.top();
s.pop();
}
}
s.push(heights.size()-1);
i=heights.size()-2;
while(s.size()||i>=0){
if(s.size()==0||i>=0&&heights[i]>=heights[s.top()])
s.push(i--);
else{
len[s.top()]+=s.top()-i;
s.pop();
}
}
for(int j=0;j<len.size();++j)
maxS=max(maxS,len[j]*heights[j]);
return maxS;
}
};
给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "*"
输出: true
解释: '*' 可以匹配任意字符串。
示例 3:
输入:
s = "cb"
p = "?a"
输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
示例 4:
输入:
s = "adceb"
p = "*a*b"
输出: true
解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
示例 5:
输入:
s = "acdcb"
p = "a*c?b"
输出: false
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
if (p[j - 1] == '*') dp[i][j] = dp[i][j - 1] | dp[i - 1][j];
else if (p[j - 1] == '?' || s[i - 1] == p[j - 1]) dp[i][j] = dp[i - 1][j - 1];
class Solution {
//二维动态规划
public:
bool isMatch(string s, string p) {
int m = s.size();
int n = p.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
dp[0][0] = true;
for (int i = 1; i <= n&&p[i - 1] == '*'; ++i)
dp[0][i] = true;
for (int i = 1; i <= m; ++i)
for (int j = 1; j <= n; ++j)
if (p[j - 1] == '*')
dp[i][j] = dp[i][j - 1] | dp[i - 1][j];
else if (p[j - 1] == '?' || s[i - 1] == p[j - 1])
dp[i][j] = dp[i - 1][j - 1];
return dp[m][n];
}
};
class Solution {//一维动态规划
public:
bool isMatch(string s, string p) {
int sLen=s.size(),pLen=p.size();
vector<bool>dp(pLen+1,false);
dp[0]=true;
for(int i=1;i<=pLen&&p[i-1]=='*';++i)
dp[i]=true;
for(int i=1;i<=sLen;++i){
bool leftUp=dp[0];//leftUp和dp[0]的顺序易错
dp[0]=false;//
for(int j=1;j<=pLen;++j){
bool curUp=dp[j];//
if(p[j-1]=='*')
dp[j]=dp[j]||dp[j-1];
else if(s[i-1]==p[j-1]||p[j-1]=='?')
dp[j]=leftUp;
else dp[j]=false;//易漏掉
leftUp=curUp;//
}
}
return dp[pLen];
}
};