8、数据结构与算法 - 栈相关联系题解析

栈练习题
 

准备

#include <stdio.h>
#include "string.h"
#include "ctype.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"

#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1
#define MAXSIZE 20 //存储空间初始分配量

#define Stack_Init_Size 100
#define Stack_Increment 10

//顺序栈
typedef struct {
    char * base;//栈底指针
    char * top;//栈顶指针
    int stackSize;//栈MaxSize
} SqStack;
//初始化栈
//思路:
//1、如果栈底为空
//2、分配一个最大容量Stack_Init_Size的数组,栈底/栈顶都指向它
//3、初始化粘的最大容量 Stack_Init_Size.
int InitStack(SqStack *S){
    
    S->base = (char *)malloc(sizeof(char)*Stack_Init_Size);
    if (S->base == NULL) return -1;//已初始化无法再初始化{
    S->top = S->base;
    S->stackSize = Stack_Init_Size;
    printf("初始化成功\n");
    return 0;
}

//获取栈顶数据
//1、判断是否为空
//2、非空,则栈顶指针 -1,返回栈顶元素
char GetTop(SqStack S){
    if (S.base == S.top) return '#';//栈为空
    return *(S.top -1);
}

//往栈里插入元素
//思路
//1、判断栈是否已满,若满则返回ERROR。 #问题:如何判断栈是否已满?
//2、栈满,则续容空间。 #问题:如何给已满栈续容空间?
//3、将元素 e(element) 压栈
//4、栈顶指针 加 1
int Push(SqStack *S, char e){
    if (S->top - S->base == S->stackSize) {
        S->base = (char *)realloc(S->base, sizeof(char)*Stack_Increment);
        S->top = S->base + S->stackSize;
        S->stackSize += Stack_Increment;
    }
    *S->top = e;
    S->top += 1;
    return 0;
}

//删除栈顶元素
//思路
//1、判断是否为空
//2、非空,则获取栈顶元素,并将栈顶减 1
char Pop(SqStack *S){
    if (S->top == S->base) return '#';//为空
    
    return *--S->top ;
}

//释放空间 
int Destroy(SqStack *S){
    free(S->base);
    S->stackSize = 0;
    return 0;
}
//**********************
typedef struct {
    int data[MAXSIZE];
    int top;
} SqStack_1;

//4.1 构建一个空栈S
int InitStack_1(SqStack_1 *S){
    
    S->top = -1;
    return OK;
}

//4.6 插入元素e为新栈顶元素
int PushData(SqStack_1 *S, int e){
    
    //栈已满
    if (S->top == MAXSIZE -1) {
        return ERROR;
    }
    //栈顶指针+1;
    S->top ++;
    //将新插入的元素赋值给栈顶空间
    S->data[S->top] = e;
    
    return OK;
}

//4.7 删除S栈顶元素,并且用e带回
int Pop_1(SqStack_1 *S,int *e){
    
    //空栈,则返回error;
    if (S->top == -1) {
        return ERROR;
    }
    
    //将要删除的栈顶元素赋值给e
    *e = S->data[S->top];
    //栈顶指针--;
    S->top--;
    
    return OK;
}

1、括号匹配问题

假设表达中允许包含两种括号:圆括号与方括号,其嵌套顺序随意,即 ([()][]) 或者([])都是正确的,而 )[])() 类似的是不正确。写一个方法检验括号是否匹配 。

 

思路
 将[  ( 全部入栈,遇到  ) 或 ] 出栈,

如果是 ] 要判断出栈的是否是 [,如果不是就不匹配

如果是 ) 要判断出栈的是否是 (,如果不是就不匹配

int ExecuteData(SqStack S, char * data){
    
//    Push(&S, data[0]);
    for (int i=0; i<strlen(data); i++) {
        switch (data[i]) {
            case '[':
                Push(&S, data[i]);
                break;
            case '(':
                Push(&S, data[i]);
                break;
            case ']':
                if (S.top==S.base) return -1;
                if (Pop(&S) != '[') return -1;
                Pop(&S);
                break;
            case ')':
                if (S.top==S.base) return -1;
                if (Pop(&S) != '(') return -1;
                Pop(&S);
                break;
            default:
                return -1;
                break;
        }
    }
    
//全部出栈,释放。返回匹配成功
    if (S.top == S.base) {
        Destroy(&S);
        return 0;
    }
    
    Destroy(&S);
    return -1;
}
    SqStack stack;
    InitStack(&stack);
//1、括号匹配问题
    printf(" ***** 问题1、括号匹配问题 ***** \n");
//    char data[180];
//    printf("请输入待匹配的字符串\n");
//    scanf("%s",data);
    char data[180] = {'[','(',']','[','[',']','[',']',')',']'};
    int result = ExecuteData(stack,data);
    if(result==0)printf("括号是正确匹配的\n");
    else printf("括号匹配不正确\n");

//*****************************************************
 ***** 问题1、括号匹配问题 ***** 
 括号匹配不正确

2、每日温度问题

 根据每日气温列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用0来替代。例如:给定一个列表 temperatures = [73,74,75,71,69,72,76,73],输出应该是[1,1,4,2,1,1,0,0];
 提示:气温列表的范围是[1,30000]。每个气温的值均为华氏度,都在[30,100]范围内的整数。


 分析:
 实际就是找到从[i, TSize] 中找当前元素后第一个大于当前元素的值与当前元素的下标差值。
 最后一个元素默认是0,因为后面已经没有元素了。

 解法一:
 暴力法1、 递归(强烈不建议使用)
 思路:
 1、遍历数组,取出温度,执行递归比较。
 2、如果是数组最后一位,直接返回0。
 3、如果递归取到的值大于需要比较的温度返回1。否者继续递归,没递归一次进行一次++操作,如果到最后还不大于,将记录标记为 0.

int dailyTemperatures_0(int *a, int n, int count, int an, int num){
    
    if (n == count-1) return 0;
    if (an<a[n+1]) return 1;
    else{
        int x = n+1;
        while (x<count) {
            int p = dailyTemperatures_0(a, x, count, an, num++);
            x++;
            if (p == 1) {
                return num;
            }else if(p == 0 && n == count-1){
                return 0;
            }
        }
    }
    return 0;
}


 暴力法2、
 思路:
 1、从左到右开始遍历(从第一个数到最后一个数开始遍历)。最后一个元素默认是0,不需要在进行计算
 2、从[i+1,TSize]遍历,每个数值知道找到比他大的数,数的次数就是对应值
 
 步骤:
 1、创建一个result 结果数组
 2、默认result[TSize-1] = 0;
 3、从0个元素遍历到最后一个元素[0,TSize-1];
 3.1、如果当前i > 0并且当前的元素和上一个元素相等,则没有必要继续循环。则判断一下result[i-1]是否等于0,如果等于则直接将result = 0,否者result[i] = result[i-1]-1;
 3.2、遍历元素[i+1,TSzie]如果当前 T[j]>T[i],则result[i] = j-i;如果当前T[j] 已经是最后一个元素,则默认result[i] = 0;

int  *dailyTemperatures_1(int* T, int TSize){
    
    int *result = (int *)malloc(sizeof(int)*TSize);//创建结果数组
    result[TSize-1] = 0;
    
//    遍历不需要遍历最后天的,因为直接就是0,没有遍历的意义
    for (int i=0; i<TSize-1; i++) {
        //如果当前温度与前一天温度相等,无需继续计算,直接返回前一天的值-1
        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[i] < T[j]) {
                    result[i] = j-i;
                    break;
                }
                
                if (j == TSize-1) {
                    result[i] = 0;
                }
            }
        }
    }
    return result;
}

 

 三、跳跃法
 思路:
 1、从右到左遍历。因为最后一天默认等于0;
 2、i 从[TSzie-2,0]; 从倒数第二天开始遍历比较,每次减 1;
 3、j 从[i+1,TSize]遍历,j+=result[j],可以利用已经有结果的位置进行跳跃,从而减少遍历次数
    (3.1)、若T[i]<T[j],那么Result[i] = j - i;
    (3.2)、若result[j] == 0,则表示后面不会有更大的值,那么当前值就应该也是0;
 
 步骤
 1、创建一个 result 结果数组
 2、默认result[TSize-1] = 0;
 3、从TSize-2个元素开始遍历,遍历到第一个元素。[TSize-2,0]
 4、从[i+1,TSize]遍历,j+=result[j];
    (4.1)、若T[i]<T[j],那么Result[i] = j-i;
    (4.2)、若Result[j] = 0,则表示后面不会有更大的值,那么当前值就应该也是0;

int  *dailyTemperatures_2(int* T, int TSize){
    
    int *result = (int *)malloc(sizeof(int)*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;
            }
            
//            判断i 之后的温度,如果比i 的温度还要低或相等的时候。如果后面不会有更大的值,那么当前值就应该也是0;
            if (result[j] == 0) {
                result[i] = 0;
                break;
            }
        }
    }
    return result;
}

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

int* dailyTemperatures_3(int* T, int TSize) {
    
    int *result = (int *)malloc(sizeof(int)*TSize);
//    用栈记录 T的下标
    int *stack_index = malloc(sizeof(int)*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 次循环\n",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;
}
//2、每日气温
//    暴力法1 递归
    int test[8] = {73,74,75,71,69,72,76,73};
    int b[8];
    int n = 0;
    while (n <8) {
        int i = dailyTemperatures_0(test, n, 8, test[n], 1);
        b[n] = i;
        n++;
        printf("%d  ",i);
    }

    int  *result1,*result2,*result3;
    int  returnSize=8;

    result1 = dailyTemperatures_1(test, 8);//暴力法
    result2 = dailyTemperatures_2(test, 8);//跳跃法
    result3 = dailyTemperatures_3(test, 8);//栈思想
    
    printf("\n");
    for (int i = 0; i < returnSize;i++ ) {
        printf("%d ",test[i]);
    }
    printf("\n result1: ");

    for (int i = 0; i < returnSize;i++ ) {
        printf("%d ",result1[i]);
    }
    printf("\n result2: ");
    for (int i = 0; i < returnSize;i++ ) {
        printf("%d ",result2[i]);
    }
    printf("\n result3: ");
    for (int i = 0; i < returnSize;i++ ) {
        printf("%d ",result3[i]);
    }
    printf("\n");

//************************************************
1  1  4  2  1  1  0  0  
 第 0 次循环
i=0; stackIndex[0] = 0top = 1 

 第 1 次循环
tIndex = 0; result[0] = 1,top = 0
i=1; stackIndex[0] = 1top = 1 

 第 2 次循环
tIndex = 1; result[1] = 1,top = 0
i=2; stackIndex[0] = 2top = 1 

 第 3 次循环
i=3; stackIndex[1] = 3top = 2 

 第 4 次循环
i=4; stackIndex[2] = 4top = 3 

 第 5 次循环
tIndex = 4; result[4] = 1,top = 2
tIndex = 3; result[3] = 2,top = 1
i=5; stackIndex[1] = 5top = 2 

 第 6 次循环
tIndex = 5; result[5] = 1,top = 1
tIndex = 2; result[2] = 4,top = 0
i=6; stackIndex[0] = 6top = 1 

 第 7 次循环
i=7; stackIndex[1] = 7top = 2 

73 74 75 71 69 72 76 73 
 result1: 1 1 4 2 1 1 0 0 
 result2: 1 1 4 2 1 1 0 0 
 result3: 1 1 4 2 1 1 0 0 


 3、爬楼问题

 假设你正在爬楼梯。需要 n 阶才能到达楼顶。每次你可以爬1或2个台阶。一共有多少种方法可以爬到楼顶?给定 n 是一个正整数。
 
 方法一:
 递归法
 分析:
 1、一次只能爬1阶或2阶,有固定条件。可以拆分成一样的小块处理
 2、给定n 能到达楼顶,有出口
 所以第一想到的肯定是递归。在进行分析:
 n = 1; 只有1种方式
 n = 2; 有 2种方式
 n = 3; 有 3种方式
 n = 4; 有 5种方式
 结论
 n <= 3 时 有n 种
 n > 3  时 有 f(n-1) + f(n-2) 种

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

 

 方法二:
 动态规划法
 思路
 1、创建一个长度为 n+1 的数组
 2、当前的i 有多少种方法 = i-1 + i-2 的方法数量

int ClimbStairs_2(int n){
    
    if (n <= 3) return n;
    int num = n+1;
    int * sum = (int *)malloc(sizeof(int)*num);
    sum[0]=0;
    sum[1]=1;
    sum[2]=2;
    
    for (int i=3; i<=n; i++) {
        sum[i] = sum[i-1] + sum[i-2];
    }
    return sum[n];
}
//3、爬楼问题
    printf(" ***** 问题3、爬楼问题 ***** \n");
    int num = 5;
    int i_1 = ClimbStairs_1(num);
    printf("1、 一共有 %d 级台阶,公有 %d 种爬楼方式\n",num,i_1);
    int i_2 = ClimbStairs_2(num);
    printf("2、 一共有 %d 级台阶,公有 %d 种爬楼方式\n",num,i_2);

//****************************************
 ***** 问题3、爬楼问题 ***** 
1、 一共有 5 级台阶,公有 8 种爬楼方式
2、 一共有 5 级台阶,公有 8 种爬楼方式


 4、去除重复字母(LeetCode-困难)

 给定一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)
 示例1:
 输入: ”bcabc“
 输出: "abc"
 
 示例2:
 输入:"cbacdcbc"
 输出:”acdb“

 分析:
 字典序:例如字典中的排列顺序。例如任意一个a开头的字符串都大于任意一个b开头的字符串
 
 思路:
 1、判断字符串可能出现的特殊情况(字符串为空,字符串长度小于等于1)
 2、用一个 record(记录) 数组记录字符串字母出现的次数
 3、申请一个字符串栈 stack 用来存储去除重复字母之后的结果,并利用他的特性帮助我们找到正确的次序
 4、遍历字符串 s
 5、从0 - top 空间,遍历stack 判断当前字符s[i]是否已经存在栈中。用一个falg isExist 标记即可,0标识不存在,1标识存在
 6、如果isExist 不存在,则:
    (1)、如果不存在,则需要循环一个找到一个正确的位置,然后在存储起来;
    (2)、如果不存在,跳过栈中所有比当前字符大,且后面还会出现的元素,然后将当前字符入栈
    top > -1表示栈非空
    stack[top] > s[i] 表示栈顶元素比当前元素大
    record[stack[top]] > 1 表示后面还会出现
    通过while 循环找到栈中位置错误的数据,出栈。找到当前合适的位置,则结束while循环;找到合理的位置后,则将当前字符s[i]入栈;
 8、知道遍历完所有的字符后,则为字符串栈stack 添加一个结束符 '\0',并返回当前字符串首地址;
 

char *removeDuplicateLetters(char * s){
/*
 1、特殊情况处理 s为空,长度为0
 2、s长度为1,直接输出
 */
    if (s== NULL || strlen(s) ==0) return "";
    if (strlen(s) == 1) return s;
    
//    record 数组,用来记录字符串 s 中每个字符未来会出现的次数
    char record[26] = {0};
    int len = (int)strlen(s);
    
//    申请一个字符串 stack;(用栈的特性来进行stack 字符串的数据进出)
    char *stack = (char *)malloc(sizeof(char)*(len+1));//至少加1,用来放字符串结束符 '\0'
    memset(stack, 0, sizeof(char)*(len+1));
//    栈顶赋初值为 -1
    int top = -1;
    
//    统计每个字符的频次
//    s[i] - 'a' 得出在数组中对应的索引
    int i;
    for (i =0; i<len; i++) {
        record[s[i] - 'a']++;
    }
    
//    遍历字符串s 入栈
    for (i=0; i<len; i++) {
        
        //isExist 标记当前字符是否存在栈中;
        int isExist = 0;
        
//        从0 - top,遍历stack 判断当前字符串s[i] 是否存在栈中
//        当前字符串是否存在栈中falg,0表示不存在,1表示存在
//        top 指向栈顶(也就是执行stack 字符串最后一个字符的位置,表示字符串长度上限)
        for (int j=0; j<=top; j++) {
            if (s[i] == stack[j]) {
                isExist = 1;
                break;
            }
        }
        
//        如果存在,record[s[i]]位置上的出现次数减一,并继续遍历下一个字符
//        如果不存在,则需要循环一个正确位置存储起来
//        如果不存在,跳过栈中多有比当前字符大,且后面还会出现的元素,然后将当前字符入栈
        if (isExist == 1) {
            record[s[i]-'a']--;
        }else{
//            top >-1 表示栈非空
//            stack[top] > s[i] 表示栈顶元素比当前元素大
//            record[stack[top] -'a'] >1 表示后面还会出现当前字符,所以可以出栈
//            循环出栈,直到栈为空 或 栈顶元素不大于当前元素 或 栈顶元素在后面的字符串中没有了为止
            while (top >-1 && stack[top] > s[i] && record[stack[top]-'a'] >1) {
//                跳出该元素 频次减一
                record[stack[top]-'a']--;
                //出栈
                top--;
            }
//            将当前元素插入到top 的下一个位置
//            top往上移动 1 位
//            入栈
            top++;
            stack[top] = s[i];
        }
    }
    
//    结束栈顶添加字符结束符
    stack[++top] = '\0';
    return stack;
}
//    4、去除重复字符
    char *s ;
    s = removeDuplicateLetters("bcabcddacb");
    printf("%s\n",s);

//*********************************
abcd

总结:
 1、用一个数组记录字符串中各个字符出现的次数
 2、第一个字符入栈
 3、遍历字符串。那当前字符与栈(遍历栈)中元素比较。如果栈中元素等于当前元素,比较为1。表示栈中已存在。同时数组计数-1
 4、当前字符,栈中不存在。遍历栈与当前字符比较,如果栈中字符 > 当前字符并且栈中字符 数组中计数 > 1,则数组中栈元素对应的数值减1,同时出栈
 5、top++ 将当前字符入栈。继续遍历字符串
 6、栈中添加结束符,返回。


 5、字符串编码

编码规则:K[encoded_string],表示其中方括号内部的 encoded_string 正好重复K 次。注意 k 保证为正整数。你可以认为输入字符串总是有效的,输入字符串中没有额外的空格,且输入的方括号是符合格式要求的。此外,你可以认为原始数据不包含数字,所有数字只表示重复次数 k。例如不会出现像 3a 或 2[4] 的输入
 例如:
 s = "3[a]2[bc]",返回 “aaabcbc”
 s = "3[a2[c]]",返回 “accaccacc”
 s = "3[ab]2[cd]ef",返回 “abababcdcdef”
 
 分析
 1、处理问题先从简到难,先用解决最简答的,例如 12[a]
 2、12是两位需要注意判断。
 
 思路:
 1、遍历字符串 S
 2、如果当前字符不为方括号 “]” 则入栈 stack;
 3、如果当前字符串遇到了方括号"]" 则:
    (3.1)、先找到要复制的字符,例如 stack = "12[a",那么我要首先获取字符串a;将这个a 保存在另外一个栈去 tempStack;
    (3.2)、再找到需要备份的数量,例如 stack = “12[a”,因为出栈为字符串"a",则当前的top 指向了"[",也就是等于2;
 (3.3)、而12对于字符串是2个字符,我们要通过遍历找到数字12的top上限/下限的位置索引,此时上限 curTop = 2,下限通过出栈,top = -1;
 (3.4)、根据范围[-1,2],读取出12保存到strOfInt 字符串中来,并将x字符串”12\0“,转成数字12
 (3.5)、当前top = -1,将tempStack中的字符a,复制12份入栈 stack 中来;
 (3.6)、为当前的stack 扩容,在stack 字符串的末尾添加字符串结束符号”\0”
 

char * decodeString(char * S){
    /*
     1、获取字符串长度
     2、设置默认栈长度为50
     3、开辟字符串栈(空间为0)
     4、设置栈头指针top = -1;
     */
    int len = (int)strlen(S);
    int stackSize = 50;
    char * stack = (char *)malloc(sizeof(char)*stackSize);
    int top = -1;
    
//    遍历字符串,在没有遇到“]”之前入栈
    for (int i=0; i<len; i++) {
        if (S[i] != ']') {
//            判断top 是否达到了栈的上限,如果达到了栈的上限就进行扩容,扩容到原大小的2倍(根据自己需要进行扩容,不是必须为2倍。只是OC底层的一些代码基本上都是以2倍的形式扩容,所以这里模仿一下)
            if (top == stackSize-1) {
                stack = realloc(stack, sizeof(char)*(stackSize*2));
            }
//            将字符串入栈 stack
            stack[++top] = S[i];
            printf("(1)、没有遇到‘]’之前。 top = %d\n",top);
        }
        else{
            int tempSize = 10;
            char * temp = (char *)malloc(sizeof(char)*tempSize);
            int topOfTemp = -1;
            
            printf("(2)、开始获取要复制的字符信息之前。 top= %d\n",top);
//            从栈顶位置开始遍历stack ,直到‘[’结束
//            把[a] 这个字母a 赋值到temp 栈中来;
//            简单说,就是将stack 中方括号里的字符出栈,复制到temp 栈中来;
            
            while (stack[top] != '[') {
//                如果topOfTemp到达了栈的上限,则为栈扩容;
                if (topOfTemp == tempSize-1) {
                    temp = (char *)realloc(temp, sizeof(char)*(tempSize*2));
                }
//                temp栈的栈顶指针自增
//                stack 出栈,则top 栈顶指针递减
                temp[++topOfTemp] = stack[top--];
            }
            printf("(2)、开始获取要复制的字符信息之后。 top= %d\n",top);
            
//            找到倍数数字.strOfInt 字符串
//            注意:如果是大于1位的情况就处理
            char strOfInt[11];
            int curTop = top;
            printf("(3)、开始获取数字,数字位置上限。 curTop= %d\n",curTop);
            
//            top-- 的目的是吧‘[’ 剔除,才能找到数字;
//             因为上面的 while (stack[top] != '[')将数字入栈了,遇到’[‘会跳出循环,也就是说当前这时候是’[‘,这时候栈顶指针 -- 跳过’[‘
            top--;
//            遍历stack 得出数字。跳过’[‘之后(由于出栈是由后向前的,所以’[‘跳过之后就能得到数字)
//            例如39[a] 接要找到这个数字 39.
//            p指向当前的top,我就知道上限了;那么接下来通过循环来找到它的数字下限;
            while (top != -1 && stack[top] >= '0' && stack[top] <= '9') {
                top--;
            }
            printf("(3)、开始获取数字,数字位置下限。top = %d\n",top);
            
//            从top-1 遍历到p 之间,把stack[top-1, p]之间的数字复制到到strOfInt 中来;
//            39中 3 和 9都是字符。我们要获取到这2个数字,存储到strOfInt 数组
            for (int j = top+1; j<curTop; ++j) {
                strOfInt[j - (top +1)] = stack[j];
            }
            strOfInt[curTop - (top +1)] = '\0';
            
//            把strOfInt 字符串转换成整数 atoi 函数;
//            把字母复制strOfInt 分到stack 中去;
//            例如 39[a],就需要把a 复制39份存进去。
            int curNum = atoi(strOfInt);
            for (int k=0; k<curNum; k++) {
                //从-1 到topOfTemp 范围内,复制curNum份到stackTop中去;
                int kk = topOfTemp;
                while (kk != -1) {
//                    如果stack 达到了栈的上限,则栈扩容
                    if (top == stackSize -1) {
                        stack = realloc(stack, sizeof(char)*(stackSize*2));
                    }
                    
//                    将temp 栈的字符复制到stack 中;
                    stack[++top] = temp[kk--];
                }
            }
            free(temp);
            temp = NULL;
        }
    }
//    realloc 动态内存调整
    //void *realloc(void *mem_address, unsigned int newsize);
//    构成字符串stack 后,在stack 的空间扩容
    char *ans = realloc(stack, sizeof(char)*(top+1));
    ans[++top] = '\0';
    
//    stack 栈不用,则释放;
    free(stack);
    return ans;
}
//    5、字符编码
    char *s1,*s2,*s3,*s4;
    s1 = decodeString("12[a]");
    printf("字符编码后的结果: %s\n\n\n\n",s1);

    s2 = decodeString("3[a]2[bc]");
    printf("字符编码后的结果: %s\n\n\n\n",s2);

    s3 = decodeString("3[a12[c]]");
    printf("字符编码后的结果: %s\n\n\n\n",s3);

    s4 = decodeString("2[abc]3[cd]ef");
    printf("字符编码后的结果: %s\n\n\n\n",s4);

//********************************************

(1)、没有遇到‘]’之前。 top = 0
(1)、没有遇到‘]’之前。 top = 1
(1)、没有遇到‘]’之前。 top = 2
(1)、没有遇到‘]’之前。 top = 3
(2)、开始获取要复制的字符信息之前。 top= 3
(2)、开始获取要复制的字符信息之后。 top= 2
(3)、开始获取数字,数字位置上限。 curTop= 2
(3)、开始获取数字,数字位置下限。top = -1
字符编码后的结果: aaaaaaaaaaaa



(1)、没有遇到‘]’之前。 top = 0
(1)、没有遇到‘]’之前。 top = 1
(1)、没有遇到‘]’之前。 top = 2
(2)、开始获取要复制的字符信息之前。 top= 2
(2)、开始获取要复制的字符信息之后。 top= 1
(3)、开始获取数字,数字位置上限。 curTop= 1
(3)、开始获取数字,数字位置下限。top = -1
(1)、没有遇到‘]’之前。 top = 3
(1)、没有遇到‘]’之前。 top = 4
(1)、没有遇到‘]’之前。 top = 5
(1)、没有遇到‘]’之前。 top = 6
(2)、开始获取要复制的字符信息之前。 top= 6
(2)、开始获取要复制的字符信息之后。 top= 4
(3)、开始获取数字,数字位置上限。 curTop= 4
(3)、开始获取数字,数字位置下限。top = 2
字符编码后的结果: aaabcbc



(1)、没有遇到‘]’之前。 top = 0
(1)、没有遇到‘]’之前。 top = 1
(1)、没有遇到‘]’之前。 top = 2
(1)、没有遇到‘]’之前。 top = 3
(1)、没有遇到‘]’之前。 top = 4
(1)、没有遇到‘]’之前。 top = 5
(1)、没有遇到‘]’之前。 top = 6
(2)、开始获取要复制的字符信息之前。 top= 6
(2)、开始获取要复制的字符信息之后。 top= 5
(3)、开始获取数字,数字位置上限。 curTop= 5
(3)、开始获取数字,数字位置下限。top = 2
(2)、开始获取要复制的字符信息之前。 top= 14
(2)、开始获取要复制的字符信息之后。 top= 1
(3)、开始获取数字,数字位置上限。 curTop= 1
(3)、开始获取数字,数字位置下限。top = -1
字符编码后的结果: accccccccccccaccccccccccccacccccccccccc



(1)、没有遇到‘]’之前。 top = 0
(1)、没有遇到‘]’之前。 top = 1
(1)、没有遇到‘]’之前。 top = 2
(1)、没有遇到‘]’之前。 top = 3
(1)、没有遇到‘]’之前。 top = 4
(2)、开始获取要复制的字符信息之前。 top= 4
(2)、开始获取要复制的字符信息之后。 top= 1
(3)、开始获取数字,数字位置上限。 curTop= 1
(3)、开始获取数字,数字位置下限。top = -1
(1)、没有遇到‘]’之前。 top = 6
(1)、没有遇到‘]’之前。 top = 7
(1)、没有遇到‘]’之前。 top = 8
(1)、没有遇到‘]’之前。 top = 9
(2)、开始获取要复制的字符信息之前。 top= 9
(2)、开始获取要复制的字符信息之后。 top= 7
(3)、开始获取数字,数字位置上限。 curTop= 7
(3)、开始获取数字,数字位置下限。top = 5
(1)、没有遇到‘]’之前。 top = 12
(1)、没有遇到‘]’之前。 top = 13
字符编码后的结果: abcabccdcdcdef


6、 杨辉三角

思路:
 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;
}
//    6、
    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");
    }

//*********************************
杨辉三角问题
[ 1 ]
[ 1  1 ]
[ 1  2  1 ]
[ 1  3  3  1 ]
[ 1  4  6  4  1 ]

7、进制转换

1、初始化一个空栈
2、当十进制N 非零的时候,循环执行以下操作
 (1)、把N 与需要的进制数取余  例如:八进制 %8 得到八进制的数压栈入栈S
 (2)、N更新为N与 需要的进制数的商  例如:八进制  /8
 3、当栈S 非空时,循环执行以下操作
 (1)、弹出栈顶元素e;
 (2)、输出e;
 

int conversion(int N, int IntoSystem){
    
    if (IntoSystem <=1) return ERROR;
    
    SqStack_1 S;
    int e;
    
//    1、初始化一个空栈S
    InitStack_1(&S);
    
//    2、
    while (N) {
        PushData(&S, N % IntoSystem);
        N = N / IntoSystem;
    }
    
//    3、
    while (S.top != -1) {
        Pop_1(&S, &e);
        printf("%d \n",e);
    }
    return OK;
}
//    7、进制转换
    conversion(1348,8);

//*************************

2 
5 
0 
4 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值