leetcode 单调栈
leetcode300. 最长递增子序列
1. 题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104。
2. 解答
int lengthOfLIS(int* nums, int numsSize) {
if (numsSize == 0) {
return 0;
}
int *stack = (int *)malloc(sizeof(int) * numsSize);
memset(stack, 0, sizeof(int) * numsSize);
int top = 0;
stack[top++] = nums[0];
for (int i = 1; i < numsSize; i++) {
if (nums[i] > stack[top - 1]) {
stack[top++] = nums[i];
} else {
for (int j = 0; j < top; j++) {
if (nums[i] <= stack[j]) {
stack[j] = nums[i];
break;
}
}
}
}
return top;
}
leetcode739. 每日温度
1. 题目
请根据每日气温列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用0来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:
气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
2. 解答
int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize) {
if (temperaturesSize == 0) {
*returnSize = 0;
return NULL;
}
int *res = (int *)malloc(sizeof(int) * temperaturesSize);
int *stack = (int *)malloc(sizeof(int) * temperaturesSize);
memset(res, 0, sizeof(int) * temperaturesSize);
memset(stack, 0, sizeof(int) * temperaturesSize);
int top = -1;
for (int i = 0; i < temperaturesSize; i++) {
while (top != -1 && temperatures[i] > temperatures[stack[top]]) {
int index = stack[top];
top--;
res[index] = i - index;
}
stack[++top] = i;
}
*returnSize = temperaturesSize;
return res;
}
leetcode503. 下一个更大元素II
1. 题目
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
2. 解答
int* nextGreaterElements(int* nums, int numsSize, int* returnSize) {
*returnSize = numsSize;
if (numsSize == 0) {
return NULL;
}
int *stack = (int *)malloc(sizeof(int) * (2 * numsSize - 1));
memset(stack, 0, sizeof(int) * (2 * numsSize - 1));
int *res = (int *)malloc(sizeof(int) * numsSize);
memset(res, -1, sizeof(int) * numsSize);
int top = 0;
for (int i = 0; i < 2 * numsSize - 1; i++) {
int index = i % numsSize;
while (top > 0 && nums[stack[top - 1]] < nums[index]) {
res[stack[top - 1]] = nums[index];
top--;
}
stack[top++] = index;
}
return res;
}
leetcode962. 最大宽度坡
1. 题目
给定一个整数数组 A,坡是元组 (i, j),其中 i < j 且 A[i] <= A[j]。这样的坡的宽度为 j - i。
找出 A 中的坡的最大宽度,如果不存在,返回 0 。
示例 1:
输入:[6,0,8,2,1,5]
输出:4
解释:
最大宽度的坡为 (i, j) = (1, 5): A[1] = 0 且 A[5] = 5.
示例 2:
输入:[9,8,1,0,1,9,4,0,4,1]
输出:7
解释:
最大宽度的坡为 (i, j) = (2, 9): A[2] = 1 且 A[9] = 1.
提示:
2 <= A.length <= 50000
0 <= A[i] <= 50000
2. 解答
#define max(a,b) a > b ? a : b
/*解题思路:1.创建一个单调递增栈用于维护,存放数组的索引
2.当数组当前值小于当前栈索引的数组值时,将数组当前值的索引存入栈中
3.倒序检查数组,当栈不空且数组值大于或等于栈顶索引对应的数组值时,更新最大坡度
栈顶出栈;
当索引小于最大坡度时 就没有检查的必要了,结束循环
*/
int maxWidthRamp(int* A, int ASize) {
int *stack = (int *)malloc(sizeof(int) * (ASize + 1));
int res = 0;
int top = 0;
stack[top++] = 0;
for (int i = 1; i < ASize; i++) {
if (A[i] < A[stack[top - 1]]) {
stack[top++] = i;
}
}
for (int i = ASize - 1; i >= 0; i--) {
while (top > 0 && A[i] >= A[stack[top - 1]]) {
res = max(res, (i - stack[top - 1]));
top--;
}
if (top == -1) {
break;
}
}
return res;
}
剑指offer63. 股票的最大利润
1. 题目
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
限制:
0 <= 数组长度 <= 10^5
2. 解答
方法一:
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
int maxProfit(int* prices, int pricesSize) {
int *stack = (int *)malloc(sizeof(int) * pricesSize);
memset(stack, 0, sizeof(int) * pricesSize);
int top = -1;
int res = 0;
int temp = 0;
if (pricesSize <= 1) {
return 0;
}
for (int i = 0; i < pricesSize; i++) {
while (top != -1 && prices[stack[top]] > prices[i]) {
top--;
}
temp = prices[i] - prices[stack[0]];
res = MAX(res, temp);
stack[++top] = i;
}
return res;
}
方法二:
int maxProfit(int* prices, int pricesSize) {
if (pricesSize <= 1) {
return 0;
}
int maxprof = 0;
int min = prices[0];
for (int i = 0; i < pricesSize; i++) {
if (prices[i] > min) {
maxprof = MAX(prices[i] - min, maxprof);
} else if (prices[i] < min) {
min = prices[i];
}
}
return maxprof;
}
leetcode 678. 有效的括号字符串
1. 题目
给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:
任何左括号 ( 必须有相应的右括号 )。
任何右括号 ) 必须有相应的左括号 ( 。
左括号 ( 必须在对应的右括号之前 )。
- 可以被视为单个右括号 ) ,或单个左括号 ( ,或一个空字符串。
一个空字符串也被视为有效字符串。
示例 1:
输入: “()”
输出: True
示例 2:
输入: “(*)”
输出: True
示例 3:
输入: “(*))”
输出: True
注意:
字符串大小将在 [1,100] 范围内。
2. 解答
#define MAXSIZE 100000
bool isValidStar(int *stack, int *star, int stackLen, int starLen)
{
if (stack[stackLen - 1] > star[starLen - 1]) {
return false;
}
while (starLen > 0 && stackLen > 0) {
if (stack[stackLen - 1] < star[starLen - 1]) {
stackLen--;
}
starLen--;
}
return stackLen == 0;
}
bool checkValidString(char * s) {
int len = strlen(s);
if (len == 0) {
return true;
}
int stack[MAXSIZE];
int star[MAXSIZE];
int stackLen = 0;
int starLen = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == '(') {
stack[stackLen++] = i;
} else if (s[i] == ')') {
stackLen--;
if (stackLen < 0) {
if (starLen > 0) {
starLen--;
stackLen++;
} else {
return false;
}
}
} else {
star[starLen++] = i;
}
}
if (!stackLen) {
return true;
}
if (stackLen > starLen) {
return false;
}
return isValidStar(stack, star, stackLen, starLen);
}