目录
目录
LeetCode496:下一个元素(进阶:LeetCode503)
一、单调栈
1.1 单调栈介绍
单调栈的主要介绍参考以上文章,其典型应用是在数组中寻找第一个比自己大或者小的数,其经典代码如下所示:
//从数组input中寻找每个元素的下一个更大元素的坐标
vector<int> nextExceed(vector<int> &input) {
vector<int> result (input.size(), -1);//存坐标
stack<int> monoStack;
for(int i = 0; i < input.size(); ++i) {
while(!monoStack.empty() && input[monoStack.top()] < input[i]) {
result[monoStack.top()] = i;
monoStack.pop();
}
monoStack.push(i);
}
return result;
}
1.2 代表题目
LeetCode496:下一个元素(进阶:LeetCode503)
题目:力扣
题目给定两个数组nums1与nums2,nums1是nums2的子集,需要找出nums1找那个元素在nums2中所在位置右侧第一个比自己大的数。此题是单调栈的简单应用:本人题解如下:
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
int m=nums1.size(),n=nums2.size();
unordered_map<int,int> nexBiger;//键值对分别为num2的值与其下一个更大值,初始化为-1
for(int i=0;i<n;i++){
nexBiger[nums2[i]]=-1;
}
stack<int> maxstack;//单调递减栈,存下一个更大的值的坐标
for(int i=0;i<n;i++){
while(!maxstack.empty() && nums2[i]>nums2[maxstack.top()]){
nexBiger[nums2[maxstack.top()]]=nums2[i];//把值放到哈希表
maxstack.pop();
}
maxstack.push(i);
}
vector<int> ans(m,-1);
for(int i=0;i<m;i++){
ans[i]=nexBiger[nums1[i]];
}
return ans;
}
};
LeetCode84:柱状图中的最大矩形
力扣:只要找到数字当前元素左右两边第一个比自己小的元素,就可以得到以当前元素为高的矩形的最大宽度。因此需要用两次单调栈
题解:
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//经典单调栈模型,一堆数中找到第一个比自己小/大的
int ans=0,n=heights.size();
stack<int> minStack;
vector<int> right(n,n),left(n,-1);//表示第一个小的数的坐标,初始化为右边n,左边-1
//右边第一个比自己小的数的坐标
for(int i=0;i<n;i++){
while(!minStack.empty() && heights[i]< heights[minStack.top()]){
right[minStack.top()]=i;
minStack.pop();
}
minStack.push(i);
}
minStack=stack<int>();//重新清空栈
//左边第一个比自己小的数的坐标
for(int i=n-1;i>=0;i--){
while(!minStack.empty() && heights[i]< heights[minStack.top()]){
left[minStack.top()]=i;
minStack.pop();
}
minStack.push(i);
}
for(int i=0;i<n;i++){
ans=max(ans,heights[i]*(right[i]-left[i]-1));
}
return ans;
}
};
LeetCode739:每日温度
LeetCode85:最大矩形
LeetCode42:接雨水
LeetCode962:最大坡度
二、滑动窗口
基本介绍:Leetcode刷题总结之滑动窗口法(尺取法) - 知乎。
滑动窗口本质上是一种循环优化手段,是双指针的一种特殊情况。
以LeetCode 3 :无重复字符的最长子串 为例:力扣。其经典写法如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n=s.size();
int ans=0,rp=0;
unordered_set<char> hash;
for(int i=0;i<n;i++){ //左指针
if(i) //左指针右移后需要在集合中去掉相应元素
hash.erase(s[i-1]);
while(rp<n && !hash.count(s[rp])){ //根据题目设置循环条件
ans=max(ans,rp-i+1);
hash.insert(s[rp]);
rp++;
}
}
return ans;
}
};
LeetCode1208:尽可能是字符串相等 力扣
这题与上题基本相同,只是在初始时需要转化一下,根据题目要求使用vector记录每个位置的差值。
class Solution {
public:
int equalSubstring(string s, string t, int maxCost) {
int n=s.length();
//用一个数组记录每个位置的差值绝对值
vector<int> cost(n,0);
for(int i=0;i<n;i++){
cost[i]=abs(s[i]-t[i]);
}
//在差值满足要求的情况下使得长度最长 参考滑动窗口的代码模板
int ans=0,right=0,sum=0;
for(int i=0;i<n;i++){
if(i)
sum-=cost[i-1];
while(right<n && sum<=maxCost){
sum+=cost[right];
if(sum<=maxCost){
ans=max(ans,right-i+1);
}
right++;
}
}
return ans;
}
};
LeetCode209 :长度最小的子数组 力扣
还是可以参考经典代码做修改
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n=nums.size();
int sum=0,ans=100001,right=0;
for(int i=0;i<n;i++){
sum+=nums[i];
}
if(sum<target) //判断一下特殊情况
return 0;
sum=0;
//这里是要最小的满足条件的连续子数组,处理有些不一样
for(int i=0;i<n;i++){
if(i)
sum-=nums[i-1];
while(right<n && sum<target){ //条件这样设置使得可以找到第一个满足条件的子数组
sum+=nums[right];
if(sum>=target){
ans=min(ans,right-i+1);
sum-=nums[right]; //防止right出的重复计算
break;
}
right++;
}
}
return ans;
}
};
leetcode 1004:最大连续1的个数 力扣
直接套模板就行了
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
//翻译一下就是,找含有k个0的最长子数组
int n=nums.size();
int sum=0,right=0,ans=0;//sum表示0的个数
for(int i=0;i<n;i++){
if(i && nums[i-1]==0)
sum--;
while(right<n && sum<=k){
if(nums[right]==0)
sum++;
if(sum<=k)
ans=max(ans,right-i+1);
right++;
}
}
return ans;
}
};
三、字符串
字符串介绍
字符串类型的题目很杂,啥都有
LeetCode 5 :最长回文子串5. 最长回文子串 - 力扣(LeetCode)
以下是动态规划解法
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
vector<vector<int>> dp(n,vector<int> (n)); //表示[i,j]是否为回文串
string ans;
for(int len=0;len<n;len++){ //len=length
for(int i=0;i+len<n;i++){ //左边界
int j=i+len;
if(len==0)
dp[i][j]=1; //长度为1 则必定回文
else if(len==1)
dp[i][j]= (s[i]==s[j]); //长度为2,则比较两字符是否相等
else
dp[i][j]= (s[i]==s[j] && dp[i+1][j-1]); //与头尾是否相等,前一位是否相等
if(dp[i][j] && len+1>ans.size()) //满足条件且长度大于现有ans,则更新答案
ans=s.substr(i,len+1);
}
}
return ans;
}
};