1. 括号匹配检验
假设表达式中允许包含两种括号:圆括号与⽅括号,其嵌套顺序随意,即() 或者[([][])]都是正确的。 ⽽这[(]或者(()])或者([()) 都是不正确的格式。 检验括号是否匹配的⽅法可⽤”期待的急迫程度"这个概念来描述。 例如,考虑以下括号的判断: [ ( [ ] [ ] ) ]
解题思路:
1.用栈来实现
2.取出第一个字符,入栈
3.遍历字符串,取出元素与栈顶元素比较
4.如果能配对 则出栈, 否则入栈
5.最后比较栈中元素数量
typedef struct StackNode{
char data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack{
LinkStackPtr top;
int count;
}LinkStack;
int Push(LinkStack *S, char e){
LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
if (p == NULL) {
return 0;
}
p->next = S->top;
p->data = e;
S->top = p;
S->count++;
return 1;
}
int Pop(LinkStack *S){
if (S->top == NULL) {
return 0;
}
LinkStackPtr t = S->top;
S->top = t->next;
free(t);
S->count--;
return 1;
}
int isValid(char *s){
if (strlen(s)==0) {
return 0;
}
LinkStack ls;
ls.top = NULL;
ls.count = 0;
Push(&ls, s[0]);
for (int i=1; i<strlen(s); i++) {
char c = s[i];
if (ls.count == 0) {//栈为空时 直接入栈
Push(&ls, c);
continue;
}
char top = ls.top->data;
if ((top == '{' && c == '}') ||
(top == '[' && c == ']') ||
(top == '(' && c == ')')) {//匹配上则出栈
Pop(&ls);
}
else {//未匹配上则入栈
Push(&ls, c);
}
}
if (ls.count == 0) {
return 1;
} else {
return 0;
}
}
2. 每日天气
根据每日气温列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1,
30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
解法一: 遍历法 O(n^2) 耗时太长 leetcode不能通过 1.从前向后遍历取出温度T[i]; 2.从j开始依次向后取出温度T[j]; 3.如果T[i]<T[j],根据j-i,求出天数
int* dailyTemperatures(int* T, int TSize, int* returnSize){
int count;
int *result = (int *)malloc(sizeof(int)*TSize);
*returnSize = TSize;
for (int i=0; i<TSize; i++) {
count = 0;
for (int j=i+1; j<TSize; j++) {
if (T[i]<T[j]) {
count = j-i;
break;
}
}
result[i] = count;
}
return result;
}
解法二:
利用栈
1.top为栈顶指针 stack为用来模拟栈的数组;
2.result存储返回结果,初始化全部为0;
3.遍历温度数组,取出当前温度值 与 栈顶元素的值(数组下标) 作比较;
4.如果大于 则找到栈顶元素的所需要的天数 出栈 结果存入result;
5.继续与栈顶元素作比较;
6.如果不大于 则将当前温度的下标入栈;
这里需要注意一点 从栈底元素到栈顶元素 元素所对应的温度值是依次减小的 否则就是出栈了
int* dailyTemperatures2(int* T, int TSize, int* returnSize){
*returnSize = TSize;
int top = -1; //栈顶下标
int stack[TSize];//创建TSize大小的数据 模拟栈 存储值为T的下标
int *result = (int *)malloc(sizeof(T[0])*TSize);
for (int i = 0;i < TSize;i++) {
result[i] = 0;
}
for (int i = 0; i<TSize; i++) {
int t = T[i];
while (top>=0) {
int index = stack[top];
int data = T[index];
if (t>data) {
top--;
result[index] = i - index;
} else {
break;
}
}
top++;
stack[top] = i;
}
return result;
}
解法三: 跳跃法可以 减少循环次数 从右向左遍历 可以利用后面温度的天数结果 来减少循环次数 1.声明同等容量值数组 赋初始值都为0 2.从倒数第二个温度开始向前遍历 倒数第一个天数肯定是0 3.遍历到第i个温度时,与第i+1个温度值作比较 4.如果T[i]<T[j],则拿j-i的值作为结果 5.如果T[i]不小于T[j],则向后跳result[j]个温度再去向后查找 因为这中间不可能有大于T[i]的温度了 6.如果T[i]不小于T[j] 且 result[j] 为0, 则直接result[i]=0。因为后面大于T[j]的都没,更不可能有大于T[i]的了
int* dailyTemperatures3(int* T, int TSize, int* returnSize){
int *result = (int *)malloc(sizeof(int)*TSize);
*returnSize = TSize;
result[TSize-1] = 0;
for (int i=TSize-2; i>=0; i--) {
for (int j=i+1; j<TSize; j += result[j]) {
if (T[i]<T[j]) {
result[i] = j-i;
break;
} else if (result[j]==0) {
result[i] = 0;
break;
}
}
}
return result;
}
3. 爬楼梯问题
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
解法一:
采用递归
采用自顶而下的分治法
走到n阶时 可以是从n-2走了2步 也可以是从n-1走了1步
fn = f(n-1)+f(n-2)
当n = 1 时返回1
当n = 2 时返回2
当n <= 0是 返回0
缺点: 耗时较多 leetcode 不能通过
int climbStairs(int n){
if ( n <= 0) return 0;
if ( n <= 2) return n;
return climbStairs(n-2) + climbStairs(n-1);
}
解法二:
采用动态规划
采用自底而上开始累加 刚好与 递归相反
当n = 1 时返回1
当n = 2 时返回2
当n = 3 时 = 1 + 2
n递增 得到
fn = f(n-1)+f(n-2)
int climbStairs2(int n){
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
int t1, t2, t3;
t1 = 1;
t2 = 2;
t3 = t1 + t2;
for (int i = 3; i<=n; i++) {
t3 = t2 + t1;
t1 = t2;
t2 = t3;
}
return t3;
}
4.字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
例如: s = "3[a]2[bc]", 返回 "aaabcbc".z s = "3[a2[c]]", 返回 "accaccacc". s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
解题思路:
- 利用栈来解题
- 循环遍历字符串,如果字符不是’]‘ 就入栈
- 如果遇到’]‘,开始解码
- 出栈 直到遇到'[' 得到要复制的字符串
- 将'['出栈
- 继续出栈,直到遇到不是数字的字符,得到要复制的数目
- 通过两层循环 将复制的字符串入栈
- 继续遍历
- 得到解码字符串
代码实现:
char * decodeString(char * s){
int len = (int)strlen(s);
int stackSize = 50;
char* stack = (char*)malloc(stackSize * sizeof(char));
int top = -1;
for (int i=0; i<len; i++) {
char c = s[i];
if (c != ']') {//如果字符不是]则一直入栈
if (top==stackSize-1) {//如果此时栈满了 就扩容
stack = realloc(stack, (stackSize += 50) * sizeof(char));
}
stack[++top] = c;
} else {
//创建临时数组 存放要复制的字符
int tempSize = 10;
char* tempStack = (char*)malloc(tempSize * sizeof(char));
int tempTop = -1;
//出栈 得到到要复制的字符串
while (stack[top] != '[') {
if (tempTop==tempSize-1) {
tempStack = realloc(tempStack, (tempSize += 10)*sizeof(char));
}
//栈顶元素存入临时数组
tempStack[++tempTop] = stack[top];
//stack 出栈
top--;
}
//得到要复制的字符串
char *cpyStr = (char*)malloc((tempTop+2)*sizeof(char));
for (int i=tempTop; i>=0; i--) {
cpyStr[tempTop-i] = tempStack[i];
}
cpyStr[++tempTop] = '\0';
//'['出栈
top--;
//取出需要复制的数量
int cpyNum = 0;
int j = 0;
while (top>=0 && stack[top]>='0' && stack[top]<='9') {
cpyNum += (stack[top]-'0')*pow(10, j);
top--;
j++;
}
//复制的字符重新入栈
for (int i=0; i<cpyNum; i++) {
for (int j=0; j<strlen(cpyStr); j++) {
if (top==stackSize-1) {//如果此时栈满了 就扩容
stack = realloc(stack, (stackSize += 50) * sizeof(char));
}
stack[++top] = cpyStr[j];
}
}
free(tempStack);
}
}
char* result = realloc(stack, (top + 2) * sizeof(char));
result[++top] = '\0';
return result;
}
5.杨辉三角
思路:
用一个二维数组来表示
1.第一层循环控制行数i : 默认[i][0] = 1,[i][i] = 1
2.第二层循环控制列数j : triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]
int** generate(int numRows, int* returnSize){
*returnSize = numRows;
int **result = malloc(sizeof(int*)*numRows);
for (int i=0; i<numRows; i++) {
//二维数组的每一个元素 都是一个一维数组的指针
result[i] = malloc(sizeof(int)*(i+1));
//每行第一个元素和最后一个元素,固定赋值为1;
result[i][0] = 1;
result[i][i] = 1;
for (int j=1; j<i; j++) {
result[i][j] = result[i-1][j] + result[i-1][j-1];
}
}
return result;
}
6.进制转换
十进制转换成8进制
1.初始化一个空栈S
2.当十进制N非零时,循环执行以下操作
* 把N与8求余得到的八进制数压入栈S;
* N更新为N与8的商;
3.当栈S非空时,循环执行以下操作
* 弹出栈顶元素e;
* 输出e;
void conversion(int N){
int stackSize = 20;
int *stack = malloc(sizeof(int)*stackSize);
int top = -1;
while (N) {
if (top==stackSize-1) {
stack = realloc(stack, stackSize+=20);
}
stack[++top] = N%8;
N=N/8;
}
printf("\n");
while (top>=0) {
printf("%d", stack[top--]);
}
printf("\n");
}
7.字符串去重
给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入: "bcabc"
输出: "abc"
示例 2:
输入: "cbacdcbc"
输出: "acdb"
解题思路:
用栈来存储最终返回的字符串,并维持字符串的最小字典序。
1.先统计一下每个字母在字符串中出现的次数
2.遍历字符串
3.如果当前字符已在栈中 则继续向后遍历
4.如果当前字符不在栈中
4.1 当前字符大于栈顶元素,先入栈,栈中元素保持字典序递增
4.2 当前字符小于栈顶元素,从栈顶向下遍历栈元素,看是否可以使得当前栈中元素的字典序 变得更小:
4.2.1如果字符串后面还有同样的栈顶元素,就先出栈,等到后面再存进来
4.2.2如果字符串后面没有同样的栈顶元素了,那字典序也不能再小了
4.3当前字符入栈
char * removeDuplicateLetters(char * s){
if (s == NULL || strlen(s) == 0) {
return "";
}
if (strlen(s) == 1) {
return s;
}
char record[26] = {0};
int len = (int)strlen(s);
int top = -1;
char *stack = malloc(sizeof(char)*(len+1));
for (int i=0; i<len; i++) {
record[s[i]-'a']++;
}
for (int i=0; i<len; i++) {
int isExist = 0;
for (int j=0; j<=top; j++) {
if (stack[j]==s[i]) {
isExist = 1;
record[s[i]-'a']--;
break;
}
}
if (isExist==1) {
continue;
} else {
if (top==-1 || s[i]>stack[top]) {
stack[++top] = s[i];
record[s[i]-'a']--;
} else {
while (top>=0 && record[stack[top]-'a']>0 && s[i]<stack[top]) {
top--;
}
stack[++top] = s[i];
record[s[i]-'a']--;
}
}
}
stack[++top] = '\0';
return stack;;
}