leetcode 算法栈系列应用二(利用栈解决字符串相关问题)

我算是一个算法小白,要从基础一点点来抠算法。遇到栈的问题的时我在想,究竟什么样的问题是需要利用栈来解决的呢。栈的特点就是先进后出。那么当遇到和配对相关的题目的时候,我们都可以考虑利用栈的方法来解决。
今天我想跟大家分享的是利用栈来解决字符串的相关问题。其实嫩够利用栈来解决的问题,大部分也都可以通过递归来解决,只不过递归的思路很绕。今天会列举三个题目,都会通过2种方法来做一下。
三个题目分别是:
856 https://leetcode-cn.com/problems/score-of-parentheses/
394 https://leetcode-cn.com/problems/decode-string/
224 https://leetcode-cn.com/problems/basic-calculator/
856 括号的分数
方法一:利用栈
1、遇到‘(’入栈,遇到‘)’出栈,这里用-1代替‘(’。
2、如果当前的sum 是0,则将1入栈。如果sum不等于0,则将sum * 2入栈。
3、将栈中的元素求和。

实现步骤

/*
*尝试使用栈的方法解决一下这道题
*遇到‘(’入栈,遇到‘)’出栈。
*/
#define MAX_LEN 100
int scoreOfParentheses(char *S)
{
    int index = 0;
    int stackIndex = -1;
    int sum = 0;
    int returnNum = 0;
    int *stack = (int *)malloc(sizeof(int) * MAX_LEN);
    while (S[index] != '\0') {
        if (S[index] == '(') {
            stack[++stackIndex] = -1;
        } else if (S[index] == ')') {
            // 将栈中元素相加
            while (stack[stackIndex] != -1){
                sum = sum + stack[stackIndex];
                stackIndex--;
            }

            if (sum == 0) {
                stack[stackIndex] = 1;
            } else {
                stack[stackIndex] = (sum * 2);
            } 
            sum = 0;
        }
        index++;
    }
    // 栈中元素求和
    int i;
    for (i = 0; i <= stackIndex; i++) {
        returnNum = returnNum + stack[i];
    }
    return returnNum;
}

方法二:递归
使用递归的方法主要需要考虑到什么时候进入递归,什么时候函数返回。找准这个时机,好像理解起来就比较快。本题的关键点在于,遇到‘(’开始递归,遇到‘)’结束递归。但是在结束递归的时候返回当前的值。如果是0,说明只有单层括号,返回1;如果不是0,说明是括号嵌套,返回sum * 2;在递归外面进行返回的值累加。中的结束条件就是字符串遍历完毕。

/*
*递归的方法。
*主要的点在于区分出递归里面和外面的值。
*/
int Dfs(char *s, int *index)
{
    int sum = 0;
    while (s[*index] != '\0') {
        if (s[*index] == '(') {
            (*index)++;
            sum += Dfs(s, index);
        } else {
            if (sum == 0) {
                return 1;
            } else {
                return (sum * 2);
            }
        }
        (*index)++;
    }  
    return  sum;
}

int scoreOfParentheses(char *S)
{
    int index = 0;
    return Dfs(S, &index);
}
  1. 字符串解码 https://leetcode-cn.com/problems/decode-string/
    方法一:利用栈的方法解决
    这道题利用栈的方式去解析的时候,思路还是比较清晰的。
    1、只要不是‘]’即入栈,遇到‘]’则出栈。
    2、在栈中取出所有的字母,即为需要重复的字符串。
    3、取出栈中所有的数字,并将字符串形式的数字转换成整型。
    4、通过循环次数和待重复的字符串对栈中的元素进行拼接。
    5、循环以上4个步骤。
/*
*利用栈的方法解决这个问题
*
*/
#define MAX_LEN 5000
// 计算数字
int CalcNum(int index, int tempIndex, char *stack)
{
    int num = 0;
    int i;
    for (i = index + 1; i < tempIndex; i++) {
        num = num * 10 + stack[i] - '0';
    }  
    return num;
}

// 获取需要重复的字符串
char *GetStr(char *stack, int *index, int tempIndex)
{
    char *tempStr = (char *)malloc(sizeof(char) * MAX_LEN);
    while (isalpha(stack[*index])) {
        (*index)--;
    }
    strncpy(tempStr, stack + (*index) + 1, tempIndex - (*index));
    tempStr[tempIndex - (*index)] = '\0';
    return tempStr;
}


// 获取数字
void GetNum(char *stack, int *index, int *tempIndex)
{
    *tempIndex = *index;
    *index = *index - 1;
    while ((*index) >= 0 && isdigit(stack[(*index)])) {
        (*index)--;
    }
    return;
}


// 拼接字符串
void SplicStr(char *stack, int *index, int num, char *tempStr)
{
    int i, j, ret, temp;
    ret = *index + 1;
    for (j = 0; j < num; j++) {
        strcpy(stack + ret, tempStr);
        ret = ret + strlen(tempStr);
    }
    stack[ret] = '\0';
    (*index) = ret - 1;
    return;
}


char * decodeString(char *s)
{
    char *stack = (char *)malloc(sizeof(char) * MAX_LEN);
    int index = -1;
    int tempIndex = 0;
    char *tempStr = NULL;
    while (*s != '\0') {
        // 入栈
        if (*s != ']') {
            stack[++index] = *s;
        } else { // 出栈
            tempStr = GetStr(stack, &index, index);
            GetNum(stack, &index, &tempIndex);
            int num = 0;
            // 计算数字
            num = CalcNum(index, tempIndex, stack);
            // 拼接字符串入栈
            SplicStr(stack, &index, num, tempStr);
        }
        s++;
    }
    stack[index + 1] = '\0';
    return stack;
}

方法二:利用递归的方法解决
递归的方法在思路上有点绕,但是实现起来相对要简单一些。
1、遇到数字就转换成整型并计算出值。
2、遇到字母则放到returnBuf中存储起来。
3、遇到‘[’则调用递归函数,把递归函数返回的字符串,按照本循环计算出的num 循环次数,拼接到本循环的returnBuf中。本轮要注意的是returnBuf的长度的计算。
4、遇到‘]’则结束函数,返回当前循环存储的returnBuf。注意外层while循环的索引也要增加。

/*
*方法一:递归
*主要是把需要重复的字符串从递归中带出来,然后拼接
*/
#define MAX_LEN 5000
char *decodeStringDfs(char * s, char **outS)
{
    char *returnBuf = (char *)malloc(sizeof(char) * MAX_LEN);
    int num = 0;
    int index = 0;
    char *buf = NULL;
    int ret;
    int sLen;
    while (*s != '\0') {
        if (isdigit(*s)) {
            num = num * 10 + *s - '0';
        } else if (isalpha(*s)) {
            returnBuf[index++] = *s;
        } else if (*s == '[') {
            buf = decodeStringDfs(s + 1, outS);
            ret = index;
            sLen = strlen(buf);
            while (num) {
                strcpy(returnBuf + ret, buf);
                ret = ret + sLen;
                num--;
            }
            s = *outS;
            index = ret;
            returnBuf[ret] = '\0';
        } else if(*s == ']') {
            returnBuf[index] = '\0';
            *outS = s;
            return returnBuf;
        }
        s++;
    }
    returnBuf[index] = '\0';
    return returnBuf;
}


char * decodeString(char *s)
{
    char *outS = NULL;
    return decodeStringDfs(s, &outS);
}

224 基本计算器 https://leetcode-cn.com/problems/basic-calculator/
方法一:使用栈(请参考https://blog.csdn.net/weixin_37939079/article/details/108820436)
方法二:递归
1、判断如果是‘ ’则不处理,继续循环。
2、判断如果是运算符(+ 或者 -)则记录下当前的运算符,后面计算的时候使用。运算符的初始值是+。
3、判断如果是数字,因为可能存在大于等于1位数的数字,所以我们通过while循环判断,如果一直是数字,则将数字字符串转换成整型。然后通过运算符进行计算,利用total 的值加或者减去当前计算出的整型的数值。
4、如果遇到’(‘则调用递归函数,根据运算符计算出total 加或者减当前递归返回的值。
5、如果遇到’)‘,则递归返回,返回当前的total。
6、循环1-5步骤,直到字符串被遍历完成。

/*
*这道题用逆波兰表达式 + 栈真的是一个很不错的解决方法。但是使用递归是我的弱项,总是想不出来,还想用递归的方法计算下。
*1、因为这题只有加减运算和括号,优先级一样。因此可以遇到括号就递归,不是括号的时候按照顺序计算就可以。
*/

int dfs(char *s, int *index)
{
    int sum = 0;
    int total = 0;
    int sLen = strlen(s);
    char sign = '+';
    int tempIndex = 0;
    while (*index < sLen) {
        if (isdigit(s[*index])) {
            while (isdigit(s[*index])) {
                sum = sum * 10 + (s[*index] - '0');
                (*index)++;
            }
            if (sign == '+') {
                total += sum;
            } else {
                total -= sum;
            } 
            sum = 0;
            continue;
        } else if (s[(*index)] == ' ') {
            (*index)++;
            continue;
        } else if (s[(*index)] == '+' || s[(*index)] == '-') {
            sign = s[(*index)];
        } else if (s[(*index)] == '(') {
            (*index)++;
            if (sign == '+') {
                total = total + dfs(s, index);
            } else {
                total = total - dfs(s, index);
            }
        } else if (s[(*index)] == ')') {
            return total;
        }
        (*index)++;
    }
    return total;
}


int calculate(char * s)
{
    int index = 0;
    int sum;
    sum = dfs(s, &index);
    return sum;
}
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页