[LEECODE]算法进阶自练习3-4 堆栈&队列&二分查找
3.堆栈、队列
简单
- 删除字符串中的所有相邻重复项 leetcode 1047
这个题目之所以用栈原因是在于如果去掉相邻之后还需要再进行相邻的清除,因此只能用栈,否则除非一直循环直到没有重复的元素,但是效率就不高了。
string removeDuplicates(string S) {
stack<char> st;
int len = S.size();
for(int i=0; i<len; i++){
if(st.size() > 0){
char top = st.top();
if(top == S[i]){
st.pop();
}
else{
st.push(S[i]);
}
}
else{
st.push(S[i]);
}
}
int ssize = st.size();
string ret(ssize,'a');
for(int i=ssize-1; i>=0; i--){
ret[i] = st.top();
st.pop();
}
return ret;
}
- 删除最外层的括号 leetcode 1021
string removeOuterParentheses(string S) {
int count = 0, slen = S.size();
stack<char> st;
string ret;
for(int i = 0; i<slen; i++){
if(S[i] == '('){
if(st.size()>0) ret += S[i];
st.push(S[i]);
}
if(S[i] == ')'){
st.pop();
if(st.size()>0) ret += S[i];
}
}
return ret;
}
困难
- 柱状图中最大的矩形 leetcode 84 再复习一次 枚举宽度,会超出时间限制:
int largestRectangleArea(vector<int>& heights) {
int hsize = heights.size();
if(hsize == 0) return 0;
int ret = INT_MIN;
for(int i=0; i<hsize; i++){
int minHeight = INT_MAX;
for(int j=i; j<hsize; j++){
minHeight = min(minHeight,heights[j]);
ret = max(ret,(j-i+1)*minHeight);
}
}
return ret;
}
枚举高度,会超出时间限制:
int largestRectangleArea(vector<int>& heights) {
int hsize = heights.size();
if(hsize == 0) return 0;
int ret = INT_MIN;
for(int i=0; i<hsize; i++){
int left = i, right = i, height = heights[i];
for(; left-1>=0 && heights[left-1]>=height; left--);
for(; right+1<hsize && heights[right+1]>=height; right++);
ret = max(ret,height*(right-left+1));
}
return ret;
}
单调栈解法:
int largestRectangleArea(vector<int>& heights) {
int hsize = heights.size();
if(hsize == 0) return 0;
vector<int> left(hsize), right(hsize);
stack<int> st;
for(int i=0; i<hsize; i++){
while(!st.empty() && heights[st.top()] >= heights[i]) st.pop();
left[i] = st.empty()? -1 : st.top();
st.push(i);
}
st = stack<int>();
for(int i=hsize-1; i>=0; i--){
while(!st.empty() && heights[st.top()] >= heights[i]) st.pop();
right[i] = st.empty()?hsize:st.top();
st.push(i);
}
int ret = INT_MIN;
for(int i=0; i<hsize; i++){
ret = max(ret, (right[i] - left[i]-1) *heights[i]);
}
return ret;
}
优化空间:
int largestRectangleArea(vector<int>& heights) {
int ret = 0;
vector<int> st;
heights.insert(heights.begin(),0); heights.push_back(0);
int hsize = heights.size();
for(int i=0; i<hsize; i++){
while(!st.empty() && heights[st.back()] > heights[i]){
int cur = st.back();
st.pop_back();
int left = st.back() + 1;
int right = i - 1;
ret = max(ret, (right - left + 1 )*heights[cur]);
}
st.push_back(i);
}
return ret;
}
- 接雨水 leetcode 42 按照最低点探测求最终雨水量
int trap(vector<int>& height) {
int hsize = height.size(), ans = 0;
for(int i=1; i<hsize-1; i++){
int max_left = 0, max_right = 0;
for(int j=i+1; j<hsize; j++){
if(height[j] > max_right){ // 这里用max会超时
max_right = height[j];
}
}
for(int j=i-1; j>=0; j--){
if(height[j] > max_left){ // 这里用 max会超时
max_left = height[j];
}
}
int minHeight = min(max_left, max_right);
if(minHeight > height[i]){
ans+= minHeight - height[i];
}
}
return ans;
}
上面每次都得求左侧最大值和右侧最大值,可以用空间换时间先求出来左侧最大值和右侧最大值,保存起来,这样时间效率就高了很多。
int trap(vector<int>& height) {
int hsize = height.size(), ret = 0;
if(hsize < 3) return ret;
vector<int> max_left(hsize,0), max_right(hsize,0);
for(int i=1; i<hsize; i++){ // 这里从 1 开始到 hsize-1 结束
max_left[i] = max(max_left[i-1],height[i-1]);
}
for(int i=hsize-2; i>=0; i--){ // 这里从 hsize-2 开始 到 0 结束
max_right[i] = max(max_right[i+1],height[i+1]);
}
for(int i=1; i<hsize-1; i++){
int minh = min(max_left[i], max_right[i]);
ret += (minh > height[i]) ? minh - height[i] : 0;
}
return ret;
}
4.二分查找
简单
- 排列硬币 leetcode 441
int arrangeCoins(int n) {
int left=0, right=n;
while(left<=right){ // 这里注意有可能是等于
int mid = (right-left)/2 + left;
long cost = (mid+1)*mid/2;
if(cost == n){
return mid;
}
else if(cost < n){
left = mid+1;
}
else{
right = mid-1;
}
}
return right; // 这里返回right是因为 1,2,3,4,5 === 5 在第一次判断后right已经调到了mid-1了。
}
中等
- Pow(x, n) leetcode 50
递归解法(一半一半拆的思路):
double subPow(double x, long n){
if(n == 1) return x;
double tmp = subPow(x, n/2);
tmp *=tmp;
return (n&1) == 1 ? tmp*x : tmp; // 这里要注意 n&1 要带括号
}
double myPow(double x, int n) {
if(n == 0 || x == 1.0) return 1;
if(x == 0.0) return 0;
long m = n;
m = (m>0) ? m : -m;// 这里要注意转为正数可能会溢出
double ret = subPow(x,m);
if(n<0) return 1.0/ret;
return ret;
}
迭代解法(将n二进制化,计算贡献值):
double quickMul(double x, long n){
double ret = 1.0;
double y = x;
while(n>0){
if(n&1 == 1) ret*=y;
y*=y;
n = n>>1;
}
return ret;
}
double myPow(double x, int n) {
long m = n;
return m<0 ? 1.0/quickMul(x,-m):quickMul(x,m);
}
困难
- 地下城游戏 leetcode 174还可以优化空间复杂度,得再看看
int calculateMinimumHP(vector<vector<int>>& dungeon) {
// 初始值尽可能小 路径和尽可能大
int n = dungeon.size(), m = dungeon[0].size();
vector<vector<int>> dp(n+1, vector<int>(m+1,INT_MAX));
dp[n][m-1] = dp[n-1][m] = 1;
for(int i=n-1; i>=0; i--){
for(int j=m-1; j>=0; j--){
int minn = min(dp[i+1][j], dp[i][j+1]);
dp[i][j] = max(minn-dungeon[i][j],1);
}
}
return dp[0][0];
}