滑动窗口、双指针、单调队列
Leetcode.167两数之和 II - 输入有序数组 (so easy~)
Leetcode.88合并两个有序数组 (还行)
Leetcode.26删除有序数组中的重复项 (写的比我好)
Leetcode.76最小覆盖子串 (不瞒说,再做一遍还是不会)
Leetcode.32最长有效括号 (思路很牛逼,再做一遍还是不会)
Leetcode.155最小栈 (还是思路牛逼!!!)
Leetcode.42接雨水 (用的是最朴素的方法)
Leetcode.84柱状图中最大的矩形
Leetcode.239滑动窗口最大值
Leetcode.918环形子数组的最大和
一、Leetcode.167两数之和 II - 输入有序数组
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
vector<int> twoSum(vector<int>& numbers, int target) {
int i=0,j=numbers.size()-1;
while(i<j){
if(numbers[i]+numbers[j]==target)return {i+1,j+1};
else if(numbers[i]+numbers[j]>target)j--;
else i++;
}
return{-1,-1};
}
二、Leetcode.88合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=m-1,j=n-1,k=m+n-1;
while(i>=0&&j>=0){
if(nums1[i]>nums2[j])nums1[k--]=nums1[i--];
else nums1[k--]=nums2[j--];
}
while(j>=0)nums1[k--]=nums2[j--];
return;
}
三、Leetcode.26删除有序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
int removeDuplicates(vector<int>& nums) {
if(nums.empty())return 0;
int k=1;
for(int j=1;j<nums.size();j++){
if(nums[j]!=nums[k-1]){
nums[k]=nums[j];
k++;
}
}
return k;
}
四、Leetcode.76最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
unordered_map<char,int>sm,tm;
string ans="";
string minWindow(string s, string t) {
for(int i=0;i<t.size();i++)
tm[t[i]]++;
int cnt=0;
int k=0;
for(int i=0;i<s.size();i++){
sm[s[i]]++;
if(sm[s[i]]<=tm[s[i]])cnt++;
while(k<=i&&sm[s[k]]>tm[s[k]]){
sm[s[k++]]--;
}
if(cnt==t.size()){
if(ans.empty()||ans.size()>i-k+1)
ans=s.substr(k,i-k+1);
}
}
return ans;
}
五、Leetcode.32最长有效括号
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
int work(string s){
int start=0;
int cnt=0;
int ans=0;
for(int i=0;i<s.size();i++){
if(s[i]=='(')cnt++;
else cnt--;
if(cnt<0){start=i+1;
cnt=0;
}
else if(cnt==0)ans=max(ans,i-start+1);
}
return ans;
}
int longestValidParentheses(string s) {
int ans1=work(s);
reverse(s.begin(),s.end());
for(auto &c:s)c^=1;
int ans2=work(s);
return max(ans1,ans2);
}
六、Leetcode.155最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
stack<int>st,st_min;
MinStack() {
}
void push(int val) {
st.push(val);
if(st_min.empty())st_min.push(val);
else st_min.push(min(st_min.top(),val));
}
void pop() {
st.pop();
st_min.pop();
}
int top() {
return st.top();
}
int getMin() {
return st_min.top();
}
七、Leetcode.42接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
int trap(vector<int>& height) {
int n=height.size();
vector<int>left(n),right(n);
left[0]=height[0];
for(int i=1;i<height.size();i++){
left[i]=max(left[i-1],height[i]);
}
right[height.size()-1]=height[height.size()-1];
for(int i=height.size()-2;i>=0;i--){
right[i]=max(right[i+1],height[i]);
}
int ans=0;
for(int i=0;i<height.size();i++){
ans+=min(left[i],right[i])-height[i];
}
return ans;
}
八、Leetcode.84柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
stack<int>stack;
int largestRectangleArea(vector<int>& heights) {
int n=heights.size();
vector<int>left(n),right(n);
for(int i=0;i<heights.size();i++){
while(!stack.empty()&&heights[stack.top()]>=heights[i])stack.pop();
if(stack.empty())left[i]=-1;
else left[i]=stack.top();
stack.push(i);
}
while(!stack.empty())stack.pop();
for(int i=heights.size()-1;i>=0;i--){
while(!stack.empty()&&heights[stack.top()]>=heights[i])stack.pop();
if(stack.empty())right[i]=heights.size();
else right[i]=stack.top();
stack.push(i);
}
int ans=0;
for(int i=0;i<heights.size();i++)
ans=max(ans,heights[i]*(right[i]-left[i]-1));
return ans;
}
九、Leetcode.239滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int>ans;
deque<int>q;
for(int i=0;i<nums.size();i++){
if(q.size()&&q.front()+k<=i)q.pop_front();
while(q.size()&&nums[q.back()]<=nums[i])q.pop_back();
q.push_back(i);
if(i-k>=-1)ans.push_back(nums[q.front()]);
}
return ans;
}
十、Leetcode.918环形子数组的最大和
给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。
环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。
子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], …, nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。
int maxSubarraySumCircular(vector<int>& nums) {
int n=nums.size();
vector<int>sum(2*n+1,0);
for(int i=1;i<sum.size();i++){
if(i<=nums.size())
sum[i]=sum[i-1]+nums[i-1];
else sum[i]=sum[i-1]+nums[i-n-1];
}
deque<int>q;
q.push_back(0);
int ans=nums[0];
for(int i=1;i<=2*n;i++){
while(q.size()&&q.front()+n<i)q.pop_front();
ans=max(ans,sum[i]-sum[q.front()]);
while(q.size()&&sum[q.back()]>=sum[i])q.pop_back();
q.push_back(i);
}
return ans;
}