LeetCode 394. 字符串解码

 

一、题目描述

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:

输入:s = "3[a]2[bc]" 输出:"aaabcbc"

示例 2:

输入:s = "3[a2[c]]" 输出:"accaccacc"

示例 3:

输入:s = "2[abc]3[cd]ef" 输出:"abcabccdcdcdef"

示例 4:

输入:s = "abc3[cd]xyz" 输出:"abccdcdcdxyz"

二、题目解析

1.根据题意和示例2可知,每遇到“["需要进行一次字符解析,且允许嵌套;因此可以使用递归的方式解决。

2.可以使用递归解决的问题,也可以采用栈的方式解决。

三、代码范例1——【算法思路:递归】

#define MAX_SIZE (100000)
char *CoreFunc(char *s, int start, int *end)
{    
    char *ret = (char *)malloc(sizeof(char) * MAX_SIZE);
    // memset(ret, '\0', sizeof(char) * MAX_SIZE);//如果后面不写繁琐的'\0',可以加上此句
    int retNum = 0;
    int multi = 0;
    while (start < strlen(s)) {
        if (s[start] == '[') {
            char *temp = CoreFunc(s, start + 1, end);
            int tempLen = strlen(temp);
            for (int i = 0; i < multi; i++) {
                strncpy(&ret[retNum], temp, tempLen);// ret没有结束符,不能使用strcpy
                retNum += tempLen;
            }
            multi = 0;
            free(temp);
            start = *end;
        } else if (s[start] >= '0' && s[start] <= '9') {
            multi = multi * 10 + (s[start] - '0');
            start += 1;
        } else if (s[start] == ']') {
            *end = start + 1;
            ret[retNum] = '\0';//递归时返回置结束符
            return ret;
        } else {
            ret[retNum++] = s[start];
            start += 1;
        }
    }
    ret[retNum] = '\0';//最外一层通过while体外返回
    *end = start;
    return ret;
}

char *decodeString(char *s)
{
    if (NULL == s) {
        return NULL;
    }
    int end = 0;
    return CoreFunc(s, 0, &end);
}

三、代码范例2——【算法思路:单栈】

#define MAX_LEN 10000
typedef struct tagStack {
    char s[MAX_LEN];
    int cnt;
    int dup;
} Stack;

char *decodeString(char *s)
{
    int slen = strlen(s);
    int depth = slen / 2 + 1;
    Stack *stk = (Stack *)calloc(depth, sizeof(Stack));
    // 栈顶为ssize而非ssize-1
    int ssize = 0;

    int dup = 0;
    for (int i = 0; i < slen; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            dup = dup * 10 + s[i] - '0';
        } else if (s[i] == '[') {
            ssize++;
            stk[ssize].dup = dup;
            dup = 0;
        } else if (s[i] == ']') {
            // 将当前站内元素,重复dup次赋值给上一级
            for (int j = 0; j < stk[ssize].dup; j++) {
                for (int k = 0; k < stk[ssize].cnt; k++) {
                    stk[ssize - 1].s[stk[ssize - 1].cnt++] = stk[ssize].s[k];
                }
            }
            stk[ssize].cnt = 0;
            stk[ssize].dup = 0;
            ssize--;
        } else {
            stk[ssize].s[stk[ssize].cnt++] = s[i];
        }
    }
    return stk[ssize].s;
}

三、代码范例3——【算法思路:双栈】

#define MAX_SIZE 10000
void reverse(char *s)
{
    for (int i = 0, j = strlen(s) - 1; i < j; i++, j--) {
        char tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}

char *decodeString(char *s)
{
    char letter[MAX_SIZE] = "";
    int nums[MAX_SIZE] = { 0 };
    int ltop = -1, ntop = -1;
    int tmp = 0;

    for (int i = 0; i < strlen(s); i++) {
        if (s[i] == '[') {
            nums[++ntop] = tmp;
            letter[++ltop] = '[';  // 将'['入栈
            tmp = 0;               // tmp归0
        } else if (s[i] == ']') {
            // 保存[XXX]之间的字符
            char str[1000] = "";
            int k = 0;
            while (letter[ltop] != '[') {
                str[k++] = letter[ltop--];
            }

            ltop--;  // 将’[’出栈

            reverse(str);

            // 将字符进堆栈
            int times = nums[ntop--];  // 倍数
            for (int i = 0; i < times; i++) {
                for (int j = 0; j < k; j++) {
                    letter[++ltop] = str[j];
                }
            }
        } else if (s[i] >= '0' && s[i] <= '9') {
            tmp = tmp * 10 + (s[i] - '0');
        } else {
            letter[++ltop] = s[i];
        }
    }
    char *ans = malloc(sizeof(char) * MAX_SIZE);
    ans[0] = '\0';
    strcat(ans, letter);  // strcat要求src和dst都必须有'\0',否则不知道copy多少和目的端起始位置
    return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值