算法练习:括号匹配、每日气温、爬楼梯

195 阅读7分钟

括号匹配检验

假设表达式中允许包含三种括号:圆括号( )、方括号[ ]和花括号{ },其嵌套的顺序随意。 { ( [ ] ( ) ) }或[ { ( [ ] [ ] ) } ]等为正确的格式,[ ( ] 、( [ ( ) ) 、( ( ) ]均为不正确的格式。检验括号是否匹配的方法可用“期待的急迫程度”这个概念来描述。

思路:

{ [ ( ) ] } 题目要求检验一串括号表达式是否是正确的,利用栈的特性

  1. 遍历第一个字符{, 是起始符号 ,{入栈 ,栈顶 { ,当务之急,下一个得是}
  2. 遍历第二个字符[, 又是起始符号,[入栈,栈顶 [ ,[的急迫程度更高,下一个得是]
  3. 遍历第三个字符(, 又是起始符号,(入栈,栈顶 ( ,(的急迫程度更高,下一个得是)
  4. 遍历第四个字符), Wow,是终止符号,先去看看栈顶最急迫的是不是(,如果不是,这个表达式就不对[)?{)? 如果是(,继续往下走
  5. 遍历第五个字符], 终止符, 去看看栈顶是不是最急迫的[, 是,继续往下走
  6. 遍历第六个字符}, 终止符,去看看栈顶是不是最急迫的{,是,继续往下走,
  7. 直到遍历完毕,查看栈里是否还有元素,有,说明没有匹配玩,表达式不对
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1

typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

/* 链栈的每一个节点,和单链表很像有没有 */
typedef struct StackNode {
    ElemType data;
    struct StackNode *next;
}StackNode;

typedef struct StackNode * StackNodePtr;

/* 栈结构 */
typedef struct
{
    StackNodePtr top;
    int count;
}LinkStack;

#pragma mark - 栈的基本操作

Status InitStack(LinkStack *S)
{
    S->top = NULL;
    S->count = 0;
    
    return OK;
}

Status ClearStack(LinkStack *S)
{
    if (S->top == NULL) return ERROR;
    
    StackNodePtr p;
    while (S->count != 0) {
        p = S->top;
        S->top = S->top->next;
        free(p);
        S->count--;
    }
    
    return OK;
}

int StackLength(LinkStack S)
{
    return S.count;
}

Status StackEmpty(LinkStack S)
{
    if (S.top == NULL) {
        return OK;
    } else {
        return ERROR;
    }
}

Status GetTop(LinkStack S, ElemType *e)
{
    if (S.top == NULL) return ERROR;
    // if (S->count == 0) return ERROR; // 也可以
    
    *e = S.top->data;
    
    return OK;
}

Status PushStack(LinkStack *S, ElemType e)
{
    // 创建新元素
    StackNodePtr p = (StackNodePtr)malloc(sizeof(StackNode));
    if (p == NULL) return ERROR;
    
    p->data = e;
    p->next = S->top;
    S->top = p;
    
    S->count++;
    
    return OK;
}

Status PopStack(LinkStack *S, ElemType *e)
{
    if (S->top == NULL) return ERROR;
    // if (S->count == 0) return ERROR; // 也可以
    
    /* 将栈顶指针指向新的栈顶 */
    StackNodePtr temp = S->top;
    S->top = S->top->next;
    
    if (e != NULL) {
        *e = temp->data;
    }
    
    free(temp);
    
    S->count--;
    
    return OK;
}

Status DestoryStack(LinkStack *S)
{
    ClearStack(S);
    
    return OK;
}

#pragma mark - 核心方法

Status BracketsCheck(char *brackets)
{
    // 创建栈
    LinkStack S;
    InitStack(&S);
    
    /* flag可以不加,主要是为了能够在while外销毁栈 */
    BOOL flag = NO;
    char *c = brackets;
    
    while (*c) {
        switch (*c) {
            case '{':
            case '[':
            case '(':
            {
                // push
                PushStack(&S, *c);
            }
                break;
            case ')':
            {
                if (StackEmpty(S)) {
                    flag = YES;
                    break;
                }
                
                ElemType popChar ;
                PopStack(&S, &popChar);
                if (popChar != '(') flag = YES;
            }
                break;
            case ']':
            {
                if (StackEmpty(S)) {
                    flag = YES;
                    break;
                }
                
                ElemType popChar ;
                PopStack(&S, &popChar);
                if (popChar != '[') flag = YES;
            }
                break;
            case '}':
            {
                if (StackEmpty(S)) {
                    flag = YES;
                    break;
                }
                
                ElemType popChar ;
                PopStack(&S, &popChar);
                if (popChar != '[') flag = YES;
            }
                break;
            default:
                break;
        }
        
        if (flag) {
            break;
        }
        
        c++;
    }
    
    if (flag) {
        // 销毁栈
        DestoryStack(&S);
        return ERROR;
    }
    
    // 最后,如果栈为空,则全部匹配完毕
    if (StackEmpty(S)) {
        // 销毁栈
        DestoryStack(&S);
        return OK;
    } else {
        // 销毁栈
        DestoryStack(&S);
        return ERROR;
    }
}



int main(int argc, const char * argv[]) {
    
    char str[30];
    while (1) {
        printf("请输入要检查的括号字符串:");
        gets(str);

        if (*str == '0') {
            break;
        }

        if (BracketsCheck(str))
        {
            printf("括号匹配正确\n\n");
        }
        else
        {
            printf("括号匹配错误\n\n");
        }
    }
    
    return 0;
}

每日气温

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

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

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

思路

用单调递减栈

这道题最重要的题意,简单的说,temperatures = [73, 74, 75, 71, 69, 72, 76, 73] 遍历每个气温向右找第一个比自己大的气温,需要找几次才能找到。比如73,右边第一个比他大的是74,只要找一次,所以输出是1;75,右边找4次,才找到比他大的76,所以输出是4;71,向右找2次才找到比他大的72,所以输出是2.......依次,我们输出[1, 1, 4, 2, 1, 1, 0, 0]

默认result[8] = {0}

  1. (0,73)入栈,74>73,73出栈,(1,74)入栈,栈顶74。输出:result[0] = 1-0=1;
  2. 找比栈顶74大的元素,75>74,74出栈,(2,75)入栈。输出:result[1] = 2-1=1
  3. 找比栈顶75大的元素,71<75,(3,71)入栈
  4. 找比栈顶71大的元素, 69<71, (4,69)入栈
  5. 找比栈顶69大的元素,72>69, 找到比69大的,69出栈。输出:result[4] = 5-4=1
  6. 用(5,72) 和栈顶元素71比较,72是第一个比71大的元素,(3,71)出栈。result[3] = 5-3=2
  7. 栈顶75,72<75, (5,72)入栈
  8. 栈顶72与76比较,(5,72)出栈,栈顶75,result[5] = 6-5=1
  9. 栈顶75与76比较,(2,75)出栈, result[2] = 6-2=4
  10. 栈为空,(6,76)入栈
  11. 栈顶76与73比较,76和73后面均没有比自己大的

上面是单调递减栈,比栈顶元素大的,栈顶出栈,继续与新栈顶比较。比新栈顶小的,自己入栈,遍历下一个元素。栈顶始终比栈底小。

先定义一个栈及基本操作,因为列表长度最大到30000,所以我采用了链栈。

#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1

typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
//typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

typedef struct ElemType {
    int place; // 输入数组中的位置
    int value; // 输入数组中的元素
} ElemType;

/* 链栈的每一个节点,和单链表很像有没有 */
typedef struct StackNode {
    ElemType data;
    struct StackNode *next;
}StackNode;

typedef struct StackNode * StackNodePtr;

/* 栈结构 */
typedef struct
{
    StackNodePtr top;
    int count;
}LinkStack;

#pragma mark - 栈的基本操作

Status InitStack(LinkStack *S)
{
    S->top = NULL;
    S->count = 0;
    
    return OK;
}

Status ClearStack(LinkStack *S)
{
    if (S->top == NULL) return ERROR;
    
    StackNodePtr p;
    while (S->count != 0) {
        p = S->top;
        S->top = S->top->next;
        free(p);
        S->count--;
    }
    
    return OK;
}

int StackLength(LinkStack S)
{
    return S.count;
}

Status StackEmpty(LinkStack S)
{
    if (S.top == NULL) {
        return OK;
    } else {
        return ERROR;
    }
}

Status GetTop(LinkStack S, ElemType *e)
{
    if (S.top == NULL) return ERROR;
    // if (S->count == 0) return ERROR; // 也可以
    
    *e = S.top->data;
    
    return OK;
}

Status PushStack(LinkStack *S, ElemType e)
{
    // 创建新元素
    StackNodePtr p = (StackNodePtr)malloc(sizeof(StackNode));
    if (p == NULL) return ERROR;
    
    p->data = e;
    p->next = S->top;
    S->top = p;
    
    S->count++;
    
    return OK;
}

Status PopStack(LinkStack *S, ElemType *e)
{
    if (S->top == NULL) return ERROR;
    // if (S->count == 0) return ERROR; // 也可以
    
    /* 将栈顶指针指向新的栈顶 */
    StackNodePtr temp = S->top;
    S->top = S->top->next;
    
    if (e != NULL) {
        *e = temp->data;
    }
    
    free(temp);
    
    S->count--;
    
    return OK;
}

Status DestoryStack(LinkStack *S)
{
    ClearStack(S);
    
    return OK;
}

核心代码

/// 每日温度
/// @param T 输入原始温度数组
/// @param returnArr 结果
Status DailyTempreatures(int *T, int TSize, int *returnArr)
{
    // 创建栈
    LinkStack S;
    InitStack(&S);
    
    int i = 0;
    ElemType temp;
    
    while (i != TSize) {
        
        if (StackEmpty(S))
        {
            ElemType e ;
            e.place = i;
            e.value = T[i];
            PushStack(&S, e);
        }
        else
        {
            GetTop(S, &temp);
            if (T[i] < temp.value)
            {
                ElemType e ;
                e.place = i;
                e.value = T[i];
                PushStack(&S, e);
            }
            else
            {
                PopStack(&S, &temp);
                returnArr[temp.place] = i - temp.place;
                continue;
            }
        }

        i++;
    }
    
    return OK;
}

爬楼梯

题目:假设你正在爬楼梯。需要n阶你才能到达楼顶。每次你可以爬1到2个台阶。你有多少种不同的方法可以爬到楼顶呢?

思路:斐波那契数列

不是递归,每次保存前一次的计算结果,累加

/*
 爬楼梯
 n 是台阶数
 */
void ClimbStairs(int n)
{
    int *arr = (int *)malloc(sizeof(int)*n);
    if (arr == NULL) return;
    
    for (int i = 0; i < n; i++) {
        if (i == 0 || i == 1)
            *(arr+i) = i+1;
        else
            *(arr+i) = *(arr+i-1) + *(arr+i-2);
    }
    
    printf("最大次数为:%d\n",*(arr+n-1));
    
    free(arr);
}