数据结构与算法(六):栈思想的一些练习题

349 阅读6分钟

前言

数据结构与算法(五):队列

数据结构与算法(四):栈

数据结构与算法(三):线性表练习题

数据结构与算法(二):线性表

数据结构与算法(一):基本概念

有效的括号 LeetCode 20

题目

给定一个只包括 '('')''{''}''['']'的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:  输入: "()"
输出: true

示例 2:  输入: "()[]{}"
输出: true

示例 3:  输入: "(]"
输出: false

示例 4:  输入: "([)]"
输出: false

示例5:  输入: "{[]}"
输出: true

思路

 1. 将第0个字符压栈
 2. 遍历[1,strlen(data)]
    (1). 取栈顶字符
    (2). 检查该字符是左括号("(","[","{")
         a.是左"(",则判断紧接其后的data[i]是为右")"
            YES->压栈,NO->出栈
         b.是左"[",则判断紧跟其后的data[i]是为右"]"
            YES->压栈,NO->出栈
         c.是左"{",则判断紧跟其后的data[i]是为右"}"
            YES->压栈,NO->出栈
 
 3.遍历结束,则判断栈是否为空,为空则表示匹配成功;否则匹配失败;

代码实现

int ExecuteData(SqStack stack,char* data){
    //将第0个字符压栈
    Push(&stack,data[0]);
    for(int i=1;i<strlen(data);i++){
        //开始遍历,取栈顶与当前字符比较 匹配上就出栈 不匹配就入栈
        char top = GetTop(stack);
        switch(top){
            case '(':
                if(data[i]==')')Pop(&stack);
                else Push(&stack,data[i]);
                break;
            case '[':
                if(data[i]==']')Pop(&stack);
                else Push(&stack,data[i]);
                break;
            case '{':
                if(data[i]=='}')Pop(&stack);
                else Push(&stack,data[i]);
                break;
                
            default:return -1;break;
        }
    }
    //如果栈为空,则返回"0"->匹配成功 否则返回"-1"匹配失败
    if(stack.top==stack.base){
        //释放栈空间
        Destroy(&stack);
        return 0;
    }
    else{
        //释放栈空间
        Destroy(&stack);
        return -1;
    }
}

每日温度 LeetCode 739

题目

根据每日气温列表,请重新生成一个列表,
对应位置的输出是需要再等待多久温度才会升高超过该日的天数。
如果之后都不会升高,请在该位置用0 来代替。

例如,给定一个列表temperatures = [73, 74, 75, 71, 69, 72, 76, 73],
你的输出应该是[1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是[1, 30000]。
每个气温的值的均为华氏度,都是在[30, 100]范围内的整数。

思路1 暴⼒法

  1. 从左到右开始遍历,从第一个数到最后一个数开始遍历. 最后一个数因为后面没有元素,默认是0,不需要计算;
  2. 从[i+1,TSize]遍历,每个数直到找到比它大的数,数的次数就是对应的值;

代码实现

 1.创建一个result 结果数组.
 2.默认reslut[TSize-1] = 0;
 3.从0个元素遍历到最后一个元素[0,TSize-1];
    A.如果当前i >0 并且当前的元素和上一个元素相等,则没有必要继续循环. 
    则判断result[i-1]是否等于0,
    如果等于则直接将result[i] = 0,否则将result[i] = result[i-1]-1;
    B.遍历元素[i+1,TSize]
        如果当前T[j]>T[i],则result[i] = j-i;
        如果当前T[j]已经是最后一个元素,则默认result[i] = 0;
int  *dailyTemperatures(int* T, int TSize, int* returnSize){
    
    int *result = (int *)malloc(sizeof(int) * TSize);
    *returnSize = TSize;
    result[TSize-1] = 0;
    
    for(int i = 0;i < TSize-1;i++)
        if(i>0 && T[i] == T[i-1])
            result[i] = result[i-1] == 0?0:result[i-1]-1;
        else{
            for (int j = i+1; j < TSize; j++) {
                if(T[j] > T[i]){
                    result[i] = j-i;
                    break;
                }
                if (j == TSize-1) {
                    result[i] = 0;
                }
            }
        }
    
    return result;
}

思路2 利用栈

1. 初始化一个栈(用来存储索引),value数组
 2. 栈中存储的是元素的索引值index;
 3. 遍历整个温度数组从[0,TSize];
    (1).如果栈顶元素<当前元素,则将当前元素索引index-栈顶元素index,
    计算完毕则将当前栈顶元素移除,将当前元素索引index 存储到栈中;
    出栈后,只要栈不为空.继续比较,直到栈顶元素不能满足T[i] > T[stack_index[top-1]]
 (2).如果当前的栈为空,则直接入栈;
 (3).如果当前的元素小于栈顶元素,则入栈
 (4).while循环结束后,当前元素也需要入栈;
 

代码实现

int* dailyTemperatures(int* T, int TSize, int* returnSize) {
    
    int* result = (int*)malloc(sizeof(int)*TSize);
    // 用栈记录T的下标。
    int* stack_index = malloc(sizeof(int)*TSize);
    *returnSize = TSize;
    // 栈顶指针。
    int top = 0;
    int tIndex;
    
    for (int i = 0; i < TSize; i++)
        result[i] = 0;
    
    for (int i = 0; i < TSize; i++) {
        printf("\n循环第%d次,i = %d\n",i,i);
       
        // 若当前元素大于栈顶元素,栈顶元素出栈。即温度升高了,所求天数为两者下标的差值。
        while (top > 0 && T[i] > T[stack_index[top-1]]) {
            tIndex = stack_index[top-1];
            result[tIndex] = i - tIndex;
            top--;
            printf("tIndex = %d; result[%d] = %d, top = %d \n",tIndex,tIndex,result[tIndex],top);
        }
        
        // 当前元素入栈。
        stack_index[top] = i;
        printf("i= %d;  StackIndex[%d] = %d ",i,top,stack_index[top]);
        top++;
        
        printf(" top = %d \n",top);
    }
    
    return result;
}

爬楼梯 LeeCode 70

题目

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶


示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

思路

假设爬 n 个台阶有f(n)个可能: 
1.假设先爬1阶, 剩下n-1阶有f(n-1)种可能
2.假设先爬2阶,剩下n-2阶有f(n-2)种可能

因此爬n阶可以转化成2种爬n-1问题的和. f(n) = f(n-1) + f(n-2);
 f(1)=1;
 f(2)=1;
 f(n) = f(n-1) + f(n-2)
使用递归求解

代码实现

int ClimbStairs(int n){
    
    if (n<1)  return 0;
    if (n == 1) return 1;
    if (n == 2) return 2;
    
    return ClimbStairs_1(n-1) + ClimbStairs_1(n-2);
}

杨辉三角 LeeCode 118

题目

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 5
输出:
[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]

思路


 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 **res = (int **)malloc(sizeof(int*)*numRows);
    
    for (int i = 0; i < numRows; i++) {
        res[i] = (int *)malloc(sizeof(int)*(i+1));
        res[i][0] = 1;
        res[i][i] = 1;
        
        for (int j = 1; j < i; j++) {
            res[i][j] = res[i-1][j] + res[i-1][j-1];
        }
    }
    return res;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("杨辉三角问题\n");
    int numRows = 5;
    int returnSize;
    int **returnResult;
    
    returnResult =  generate(numRows, &returnSize);
    for (int i = 0; i < returnSize; i++) {
        printf("[");
        for (int j = 0;  j<=i; j++) {
            printf(" %d ",returnResult[i][j]);
        }
        printf("]\n");
    }

    return 0;
}