leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 4 】2021-09-13 - 394. 字符串解码 #13

Open azl397985856 opened 3 years ago

azl397985856 commented 3 years ago

394. 字符串解码

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/decode-string/

前置知识

编码规则为: 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"

L-SUI commented 3 years ago

/**

yuruiew commented 3 years ago

思路

1.栈+迭代

构建辅助栈 stack, 遍历字符串 s 中每个字符 c; 当 c 为数字时,将数字字符转化为数字 multi,用于后续倍数计算; 当 c 为字母时,在 res 尾部添加 c; 当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置 00: 记录此 [ 前的临时结果 res 至栈,用于发现对应 ] 后的拼接操作; 记录此 [ 前的倍数 multi 至栈,用于发现对应 ] 后,获取 multi × [...] 字符串。 进入到新 [ 后,res 和 multi 重新记录。 当 c 为 ] 时,stack 出栈,拼接字符串 res = last_res + cur_multi * res,其中: last_res是上个 [ 到当前 [ 的字符串,例如 "3[a2[c]]" 中的 a; cur_multi是当前 [ 到 ] 内字符串的重复倍数,例如 "3[a2[c]]" 中的 2。 返回字符串 res。

代码

/**
 * 栈+迭代
 */
class Day4LC394V0 {
    public String decodeString(String s) {
        StringBuilder res = new StringBuilder();
        int multi = 0;
        LinkedList<Integer> stack_multi = new LinkedList<>();
        LinkedList<String> stack_res = new LinkedList<>();
        for (Character c : s.toCharArray()) {
            if (c == '[') {
                stack_multi.addLast(multi);
                stack_res.addLast(res.toString());
                multi = 0;
                res = new StringBuilder();
            } else if (c == ']') {
                StringBuilder tmp = new StringBuilder();
                int cur_multi = stack_multi.removeLast();
                for (int i = 0; i < cur_multi; i++) tmp.append(res);
                res = new StringBuilder(stack_res.removeLast() + tmp);
            } else if (c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + "");    //记录数字
            else res.append(c); //直接添加字符
        }
        return res.toString();
    }
}

复杂度分析

2.递归

总体思路与辅助栈法一致,不同点在于将 [ 和 ] 分别作为递归的开启与终止条件:

当 s[i] == ']' 时,返回当前括号内记录的 res 字符串与 ] 的索引 i (更新上层递归指针位置); 当 s[i] == '[' 时,开启新一层递归,记录此 [...] 内字符串 tmp 和递归后的最新索引 i,并执行 res + multi * tmp 拼接字符串。 遍历完毕后返回 res。

代码

/**
 * 递归
 */
class Day4LC394V1 {
    public String decodeString(String s) {
        return dfs(s, 0)[0];
    }

    private String[] dfs(String s, int i) {
        StringBuilder res = new StringBuilder();
        int multi = 0;
        while (i < s.length()) {
            if (s.charAt(i) >= '0' && s.charAt(i) <= '9')
                multi = multi * 10 + Integer.parseInt(String.valueOf(s.charAt(i)));
            else if (s.charAt(i) == '[') {
                String[] tmp = dfs(s, i + 1);
                i = Integer.parseInt(tmp[0]);
                while (multi > 0) {
                    res.append(tmp[1]);
                    multi--;
                }
            } else if (s.charAt(i) == ']')
                return new String[]{String.valueOf(i), res.toString()};
            else
                res.append(String.valueOf(s.charAt(i)));
            i++;
        }
        return new String[]{res.toString()};
    }

}

复杂度分析

MoncozGC commented 3 years ago
class Day4LC394V0 {
    public String decodeString(String s) {
        StringBuilder res = new StringBuilder();
        int multi = 0;
        LinkedList<Integer> stack_multi = new LinkedList<>();
        LinkedList<String> stack_res = new LinkedList<>();
        for (Character c : s.toCharArray()) {
            if (c == '[') {
                stack_multi.addLast(multi);
                stack_res.addLast(res.toString());
                multi = 0;
                res = new StringBuilder();
            } else if (c == ']') {
                StringBuilder tmp = new StringBuilder();
                int cur_multi = stack_multi.removeLast();
                for (int i = 0; i < cur_multi; i++) tmp.append(res);
                res = new StringBuilder(stack_res.removeLast() + tmp);
            } else if (c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + "");    //记录数字
            else res.append(c); //直接添加字符
        }
        return res.toString();
    }
}
Mahalasu commented 3 years ago

思路

建立一个栈,遍历字符串,判断每个字符的类型,如果是[则说明后续字母是重复的,如果是]则说明重复字符串结束,需要出栈,剩下的数字和字符直接存储在栈中。

class Solution:
    def decodeString(self, s: str) -> str:
        stack = []

        for char in s:
            if char == ']':
                repeat = ''
                num = ''
                while stack and stack[-1] != '[':
                    repeat = stack.pop() + repeat
                stack.pop()
                while stack and stack[-1].isdigit():
                    num = stack.pop() + num
                stack.append(int(num) * repeat)
            else:
                stack.append(char)

        return "".join(stack)

T: O(N) S: O(N)

user1689 commented 3 years ago

题目

https://leetcode-cn.com/problems/decode-string/

思路

模拟

python3

# 写法一
class Solution:
    def decodeString(self, s: str) -> str:

        # time s + |s|
        # space n
        # 单栈模拟
        stack = []

        for char in s:
            if char != ']':
                stack.append(char)
            else:

                # 取出字符
                alpha = list()
                while stack and stack[-1].isalpha():
                    alpha.append(stack.pop())
                # 数组 -> string
                tmp = ""
                for i in range(len(alpha) - 1, -1, -1):
                    tmp += str(alpha[i])
                alpha = tmp

                # case:
                # s = "3[ab]2[bc]"
                # stack = ['3','[','a','b']
                # alpha = ['b','a']
                # tmp = "ab"

                # 取出[
                if stack and stack[-1] == '[':
                    stack.pop()

                # 取出倍数
                multiple = list()
                while stack and stack[-1].isdigit():
                    multiple.append(stack.pop())
                # 数组 -> string -> int
                tmp = ""
                for i in range(len(multiple) - 1, -1, -1):
                    tmp += str(multiple[i])
                multiple = int(tmp)

                # 放回 倍数个字符
                while multiple > 0:
                    stack.append(alpha)
                    multiple -= 1

        res = ""
        for i in range(0, len(stack)):
            res += stack[i]
        return res

# 写法二
class Solution:
    def decodeString(self, s: str) -> str:
        stack = []
        res = ""
        multi = 0

        for c in s:
            if c == '[':
                stack.append([multi, res])
                multi, res = 0, ""
            elif c == ']':
                cur_multi, last_res = stack.pop()
                res = last_res + cur_multi * res
            elif '0' <= c <= '9':
                multi = multi * 10 + int(c) 
            else:
                res += c

        return res

时间复杂度

相关题目

1.待补充

mixtureve commented 3 years ago

思路

Start traversing string s and process each character based on the following rules:

Case 1) Current character is not a closing bracket ]. Push the current character to stack.

Case 2) Current character is a closing bracket ].

Start decoding the last traversed string by popping the string decodedString and number k from the top of the stack.

Pop from the stack while the next character is not an opening bracket [ and append each character (a-z) to the decodedString. Pop opening bracket [ from the stack. Pop from the stack while the next character is a digit (0-9) and build the number k.

代码

Java Code:


class Solution {
    public String decodeString(String s) {
        // 3[a2[bc]]
        // when meet ] poll out from stack
        // a temp list to hold parsed string with in a []

        // 注意!!!!k的取值范围 k可能并不是一个digit

        Deque<Character> stack = new ArrayDeque<>();
        char[] sArr = s.toCharArray();
        for (int i = 0; i < sArr.length; i++) {
            if (sArr[i] != ']') {
                stack.push(sArr[i]);
            } else {
                List<Character> tempList = new ArrayList<>();
                while(!stack.isEmpty() && stack.peek() != '[') {
                    tempList.add(stack.pop());
                }
                stack.pop(); // pop out '['
                int base = 1;
                int num = 0;
                while (!stack.isEmpty() && Character.isDigit(stack.peek())) {
                    num += (stack.pop() - '0') * base;
                    base *= 10;
                }

                // reverse order push into stack again
                while (num-- > 0) {
                    for (int j = tempList.size() - 1; j >= 0; j--) {
                        stack.push(tempList.get(j));
                    }
                }   
            }
        }

        char[] result = new char[stack.size()];
        int i = stack.size() - 1;
        while (!stack.isEmpty()) {
            result[i--] = stack.pop();
        }
        return new String(result);

    }
}

复杂度分析

令 n 为数组长度。

cdd111 commented 3 years ago

解题思路

通过栈来解决本题 1、通过循环原来的字符串依次将除了']'以外的字符进栈a, 2、如果遇到中括号‘]’就从栈顶依次出栈,用一个临时栈b来保存,直到遇到‘[’,此时栈顶是这段字符串的重复次数, 取出数字并重复之前的临时栈,计算出结果再倒序插入原来的栈a,清空用来保存临时数组的临时栈b 3、然后继续循环,直到S字符串被遍历完

`javascript

代码

/**
 * @param {string} s
 * @return {string}
 */
 var decodeString = function(s) {
  let newZhan = [];
  let temp=[]
  for(let i=0;i<s.length;i++){
      if(s[i]!=']'){
        newZhan.push(s[i])
      }else{
        let time = new Array()
        while(newZhan[newZhan.length-1]!='['){
          temp.push(newZhan.pop())
        }
        newZhan.pop()
        while(!isNaN(newZhan[newZhan.length-1])){
          let tmp = newZhan.pop()
          time.push(tmp)
        }
        time= Number(time.reverse().join(''))
        newZhan.push(temp.reverse().join('').repeat(time));
        temp.splice(0,temp.length)
      }
  }
  return newZhan.join('');
};
leolisgit commented 3 years ago

思路

双栈,一个用来记录count,一个用来存储再次遇到 [ 之前已经构建好的字符串。

  1. 数字:需要把数字字符串转化为int
  2. 字母:直接添加到当前正在构建的字符串末尾
  3. [ :把count压栈,把当前构建的字符压栈
  4. ] :弹出count,以及之前构建好的字符串,把当前构建的字符串添加到之前构建好的字符串末尾count次。

代码

class Solution {
    public String decodeString(String s) {
        int n = s.length();

        Stack<Integer> numStack = new Stack<>();
        Stack<String> strStack = new Stack<>();

        StringBuilder builder = new StringBuilder();
        int count = 0;
        for (int i = 0; i < n; i++) {
            char ch = s.charAt(i);

            if (Character.isDigit(ch)) {
                count = count * 10 + ch - '0';
            } else if (ch == '[') {
                numStack.push(count);
                strStack.push(builder.toString());
                count = 0;
                builder.setLength(0);
            } else if (ch == ']') {
                int num = numStack.pop();
                StringBuilder temp = new StringBuilder(strStack.pop());
                for (int j = 0; j < num; j++) {
                    temp.append(builder);
                }
                builder = temp;
            } else {
                builder.append(ch);
            }
        }
        return builder.toString();
    }
}

复杂度

时间:O(n)
空间:O(n)

aatoe commented 3 years ago
      function decodeString(S) {
        // if(S.length===0) return ""
        let stack = []
        let num = ''
        for (const s of S) {
          // 数字可能会多个,注意一下这里的技巧
          if (!isNaN(s)) {
            num += s
            continue
          }
          if (num) {
            stack.push(num)
            num = ''
          }

          // 进栈
          if (s !== ']') {
            stack.push(s)
            continue
          } else if (s === ']') {
            // 出栈
            let str = ''
            // 遇见 [ 出栈结束
            while (stack.length && stack.slice(-1)[0] !== '[') {
              let lastEle = stack.pop()
              console.log(lastEle)
              str = lastEle + str
            }
            stack.pop() // 删除 [
            let num = +stack.pop()
            stack.push(str.repeat(num))
          }
        }
        console.log(stack, 'stack')
        return stack.join('')
      }
BpointA commented 3 years ago

思路

想到类似基本计算器的栈,但是实操没出来。最后自己用递归做的,依次解开括号,得到答案。

Python代码

class Solution:
    def decodeString(self, s: str) -> str:
        if "]" not in s:
            return s
        idx=s.index("]")
        j=idx
        while j>=0 and s[j]!="[":
            j-=1
        t=j-1
        while s[t].isdigit():
            t-=1
        k=int(s[t+1:j])
        words=s[j+1:idx]
        replace=words*k
        s_new=s[:t+1]+replace+s[idx+1:]
        return self.decodeString(s_new)

复杂度

时间复杂度:O(n^2) n为字符串长度

空间复杂度:O(n)

优化

学习了官方题解的栈思想,括号匹配这种其实只要一个栈就够了,之前想歪了。改成栈之后只用一次遍历,时间复杂度为O(n)。

class Solution:
    def decodeString(self, s: str) -> str:
        i=0
        stk=[]
        while i<len(s):
            if s[i]!="]":
                stk.append(s[i])
            else:
                word=""
                while stk[-1]!="[":
                    word=stk.pop()+word
                stk.pop()
                num=0
                k=0
                while len(stk)>0 and stk[-1].isdigit():
                    num=pow(10,k)*int(stk.pop())+num
                    k+=1
                stk.append(word*num)
            i+=1
        return "".join(stk)
Huangxuang commented 3 years ago

题目:394. Decode String

思路

代码

public class Solution {
    public String decodeString(String s) {
        String res = "";
        Stack<Integer> countStack = new Stack<>();
        Stack<String> resStack = new Stack<>();
        int idx = 0;
        while (idx < s.length()) {
            if (Character.isDigit(s.charAt(idx))) {
                int count = 0;
                while (Character.isDigit(s.charAt(idx))) {
                    count = 10 * count + (s.charAt(idx) - '0');
                    idx++;
                }
                countStack.push(count);
            }
            else if (s.charAt(idx) == '[') {
                resStack.push(res);
                res = "";
                idx++;
            }
            else if (s.charAt(idx) == ']') {
                StringBuilder temp = new StringBuilder (resStack.pop());
                int repeatTimes = countStack.pop();
                for (int i = 0; i < repeatTimes; i++) {
                    temp.append(res);
                }
                res = temp.toString();
                idx++;
            }
            else {
                res += s.charAt(idx++);
            }
        }
        return res;
    }
}

复杂度分析

wang-hejie commented 3 years ago

思路1

利用栈思想解决。

  1. 遍历字符串s。
  2. 字符依次入栈,直到遇到右括号 ']' 停下。
  3. 字符依次出栈,直到遇到左括号 '[' 停下,将刚才出栈的字符逆序排列成字符串string。
  4. 从栈中弹出紧邻左括号 '[' 左边的数字,直到不是数字停下,将数字逆序排列成整数n。
  5. 这组括号内的字符串最终为n遍string,压入栈中
  6. 继续1)

复杂度1

代码1(Python)

class Solution:
    def decodeString(self, s: str) -> str:
        stack = []
        for char in s:
            if char != ']':
                stack.append(char)
            else:
                temp_list_str = []
                while True:
                    if stack[-1] == '[':
                        stack.pop()
                        break
                    temp_list_str.append(stack.pop())
                temp_list_str.reverse()
                temp_list_num = []
                while True:
                    if not stack or not stack[-1].isdigit():
                        break
                    temp_list_num.append(stack.pop())
                temp_list_num.reverse()
                temp_num = ''.join(temp_list_num)
                temp_str = ''.join(temp_list_str) * int(temp_num)
                stack.append(temp_str)
        return ''.join(stack)

思路2

递归思想解决

递归入口: 从头开始遍历字符串s。最外层保存一个解析串decoded和一个计数器cnt,当遇到普通字符时,添加到decoded后面;当遇到数字时,添加到cnt后面;当遇到左括号 '[' 时,陷入下一层递归。 下一层也新保存一个解析串decoded和一个计数器cnt,当遇到普通字符时,添加到decoded后面;当遇到数字时,添加到cnt后面;当遇到左括号 '[' 时,再陷入下一层递归。

递归出口: 当遇到右括号 ']' 时,递归结束,返回2个东西:当前这一层括号内的模式串pattern,以及当前右括号的下一个下标index。 回到上一层,在陷入递归的地方拿到pattern和index。该层的解析串decoded后面添加pattern * cnt,重置cnt为空,并把遍历字符串s的指针跳到index位置。

复杂度2

代码2(Python)

class Solution:
    def decodeString(self, s:str, i = 0) -> str:
        decoded = ''
        cnt = ''

        while i < len(s):
            # 普通字符,直接拼接到decoded后面
            if s[i].isalpha():
                decoded += s[i]
                i += 1
            # 普通数字,直接拼接到cnt后面
            elif s[i].isdigit():
                cnt += s[i]
                i += 1
            # 左括号 '[' ,将括号内的字符串重复cnt次,再拼接到decoded后面
            # 注意:括号内可能还会嵌套括号,要递归处理
            elif s[i] == '[':
                # 需要从递归中取2个东西:括号内的模式串,以及右括号的下一个下标index
                pattern, index = self.decodeString(s, i+1)
                pattern = pattern * int(cnt)  # 重复cnt次
                decoded += pattern  # 拼接到decoded上
                cnt = ''  # 重置计数器cnt
                i = index
            # 右括号 ']',说明括号内的模式解析完毕
            # 递归结束,返回需要的2个东西:括号内的模式串,以及右括号的下一个下标index
            elif s[i] == ']':
                return decoded, i + 1
        return decoded
kuwan commented 3 years ago

思路

复杂度

时间复杂度O(n) 空间复杂度O(n)

zhiyuanpeng commented 3 years ago
class Solution:
    def decodeString(self, s: str) -> str:
        stack = []
        for c in s:
            if c is not ']':
                stack.append(c)
            else:
                rep = ''
                while True:
                    s = stack.pop()
                    if s == '[':
                        break
                    else:
                        rep += s
                k = ''
                while True:
                    k += stack.pop()
                    if not stack or not(stack[-1] in '0123456789'):
                        break
                for i in range(int(k[::-1])):
                    for j in range(len(rep)-1, -1, -1):
                        stack.append(rep[j])
        return ''.join(stack)

time complexity: maxK^(count_k)n space complexity: maxK^(count_k)n

aduispace commented 3 years ago
class Solution {
    public String decodeString(String s) {
        return dfs(s, 0)[0];
    }
    private String[] dfs(String s, int i) {
        StringBuilder res = new StringBuilder();
        int multi = 0;
        while(i < s.length()) {
            if(s.charAt(i) >= '0' && s.charAt(i) <= '9') 
                multi = multi * 10 + Integer.parseInt(String.valueOf(s.charAt(i))); 
            else if(s.charAt(i) == '[') {
                String[] tmp = dfs(s, i + 1);
                i = Integer.parseInt(tmp[0]);
                while(multi > 0) {
                    res.append(tmp[1]);
                    multi--;
                }
            }
            else if(s.charAt(i) == ']') 
                return new String[] { String.valueOf(i), res.toString() };
            else 
                res.append(String.valueOf(s.charAt(i)));
            i++;
        }
        return new String[] { res.toString() };
    } 
}
ccslience commented 3 years ago
string decodeString(string s)
    {
        vector<string> stack;
        int len = s.length();
        int stack_len = 0;
        for (int i = 0 ; i < len; i++)
        {
            if (s[i] != ']')
            {
                stack.push_back(string(1, s[i]));
                stack_len++;
            }
            else
            {
                string repeat_str = "";
                while(stack_len && stack[stack_len - 1] != "[")
                {
                    repeat_str = stack[stack_len - 1] + repeat_str;
                    stack.pop_back();
                    stack_len--;
                }
                stack.pop_back();   // 弹出'['
                stack_len--;
                string num = "";
                while(stack_len && stack[stack_len - 1] >= "0" && stack[stack_len - 1] <= "9")
                {
                    num = stack[stack_len - 1] + num;
                    stack.pop_back();
                    stack_len--;
                }
                string tmp = "";
                for (int j = 0; j < atoi(num.c_str()); j++)
                    tmp += repeat_str;
                stack.push_back(tmp);
                stack_len++;
            }
        }
        string res = "";
        for (int i = 0; i < stack.size(); i++)
        {
            res += stack[i];
        }
        return res;
    }
KennethAlgol commented 3 years ago

思路: 使用栈,压入栈的思想 代码: Java class Solution { public String decodeString(String s) { StringBuilder res = new StringBuilder(); int multi = 0; LinkedList stack_multi = new LinkedList<>(); LinkedList stack_res = new LinkedList<>(); for(Character c : s.toCharArray()) { if(c == '[') { stack_multi.addLast(multi); stack_res.addLast(res.toString()); multi = 0; res = new StringBuilder(); } else if(c == ']') { StringBuilder tmp = new StringBuilder(); int cur_multi = stack_multi.removeLast(); for(int i = 0; i < cur_multi; i++) tmp.append(res); res = new StringBuilder(stack_res.removeLast() + tmp); } else if(c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + ""); else res.append(c); } return res.toString(); } } 复杂度:O(n)

simonsayshi commented 3 years ago

string input分以下几种,数字,char,和左括号,右括号 数字之后必然是左括号,右括号可看作返回字符串的标记 遇到是数字的字符串,把字符串变成数字; 数字之后一定是左括号 左括号之后一定是字符 所以逻辑就变成,遇到数字字符,变成数字N,再把后面括号中的内容读取完(以右括号为终结),返回字符串,重复累加字符串N遍,返回

class Solution {
public:
    string decodeString(string s) {
        string res;
        int i = 0;
        return helper(s, i);

    }

    string helper(string s, int& indx) {
        string res = "";

        for(;indx<s.size();indx++) {
            if(s[indx] == ']') {
                break;
            }else if(s[indx] < '0' || s[indx] > '9') {
                res+= s[indx];
            } else {
                int count = 0;
                while(s[indx] >= '0' && s[indx] <='9') {
                    count = count * 10 + s[indx] - '0';
                    indx++;
                }
                indx++;
                string temp = helper(s, indx);
                while(count != 0) {
                    res+=temp;
                    count--;
                }
            }
        }
        return res;
    }
};
LOVEwitch commented 3 years ago

//递归 var decodeString = function(s) { return recursion(s, 0); }; var recursion = function(s, i){ let res = '', num = ''; while(i < s.length) { if(/[0-9]/.test(s[i])) { num += s[i]; i++; } else if(/[a-z]/i.test(s[i])) { res += s[i]; i++; } else if(s[i] === '[') { const [pattern, nextIndex] = recursion(s, i+1) res += pattern.repeat(Number(num)); num = ''; i = nextIndex; continue; } else if(s[i] === ']') { return [res, i+1] } } return res; }

wangcn111 commented 3 years ago
 function decode(str) {
    let arr = str.split("");
    let res = [];
    let temp = "";
    let flag = 0;
    let encode = false;
    while (arr.length > 0) {
        let s = arr.pop();
        if (encode === true) {
            //数字的情况
            temp = temp.repeat(Number(s));
            encode = false;
            flag === 0 ? (res.push(temp), (temp = "")) : null;
        } else if (s === "]") {
            //右括号
            flag++;
        } else if (s === "[") {
            //左括号
            flag--;
            encode = true;
        } else if (flag == 0) {
            //没有括号
            res.push(s);
        } else {
            temp = `${s}${temp}`;
        }
    }
    return res.reverse().join("");
}
KennethAlgol commented 3 years ago

思路

使用栈,压入栈,保存字符串

代码

Java

class Solution {
    public String decodeString(String s) {
        StringBuilder res = new StringBuilder();
        int multi = 0;
        LinkedList<Integer> stack_multi = new LinkedList<>();
        LinkedList<String> stack_res = new LinkedList<>();
        for(Character c : s.toCharArray()) {
            if(c == '[') {
                stack_multi.addLast(multi);
                stack_res.addLast(res.toString());
                multi = 0;
                res = new StringBuilder();
            }
            else if(c == ']') {
                StringBuilder tmp = new StringBuilder();
                int cur_multi = stack_multi.removeLast();
                for(int i = 0; i < cur_multi; i++) tmp.append(res);
                res = new StringBuilder(stack_res.removeLast() + tmp);
            }
            else if(c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + "");
            else res.append(c);
        }
        return res.toString();
    }
}

复杂度

O(n)

JunQu commented 3 years ago

思路

主要是用栈的思维,先进后出。遇到[则入栈,遇到]则出栈,再注意数字部分就可以。

代码

const decodeString = (str) => {
  const strStack = []; // 非最小重复部分则入栈
  const numStack = []; // 保存数字部分
  let resultStr = ''; // 保存每一次的重复部分
  let num = 0; // 保存数字
  for (const letter of str) {
    switch (letter) {
      case '[':
        // 全部入栈
        strStack.push(resultStr);
        numStack.push(num);
        resultStr = '';
        num = 0;
        break;
      case ']':
        // 出栈时需要注意拼接
        resultStr = strStack.pop() + resultStr.repeat(numStack.pop());
        break;
      default:
        // 需要特殊处理一下数字部分
        if (parseInt(letter, 10) >= 0) {
          num = num * 10 + parseInt(letter, 10);
        } else {
          resultStr += letter;
        }
    }
  }
  return resultStr;
};

复杂度

令 k 为字符串的最大嵌套深度的数字至它外层所有数字部分之积, 则 k 最小位1。 时间复杂度: 最小时间复杂度是O(n),最大时间复杂度是O(n*K),最复杂情形是:100[2[3[4[5[b]]]]] 空间复杂度: 字符串必须是新字符,所以最小空间是O(n),同样取决于K,最大空间是O(n*k) ps: 我不懂复杂度计算,以上是我瞎猜的,总觉得repeat会消耗空间和时间。

LareinaWei commented 3 years ago

Thinking

Using a list as a stack, push every character in the string into the stack if it is not a closing bracket.
If we encounter a closing bracket, we need to start pop characters out of the stack to get the repeated string and how many times the string is repeated.
We first pop out the characters and store them into a temp string until we meet a starting bracket. The temp string is what is need to be repeated. We then pop the opening bracket.
Then we pop out the number characters one by one until the last element of the stack is not a numeric character. We then get the number of times to repeat. Use the number and temp string to get the repeated string, then push it back to the stack, since it might still be part of another longer repeating string.
We repeat the steps above go through every character in the provided string. Then the answer is combining all elements in the stack together.

Code

class Solution:
    def decodeString(self, s: str) -> str:
        stack = []

        for char in s:
            if char == "]":
                tempStr = ""
                count = ""

                while stack and stack[-1] != "[":
                    tempStr = stack.pop() + tempStr

                #pop the "[" character
                stack.pop() 

                #pop all the numbers from the stack and get the count number
                while stack and stack[-1].isnumeric():
                    count = stack.pop() + count

                #get the repeated temp string
                repeat = int(count) * tempStr

                #push the repeated string to the stack
                stack.append(repeat)
            else:
                stack.append(char)

        #get the final answer
        res = ""

        for i in range(len(stack)):
            res += stack[i]

        return res

Complexity

Time Complexity: O(n). Since it needs to go through the string once.
Space Complexity: O(n).

Laurence-try commented 3 years ago

思路

利用入栈和出栈,遍历string

代码

使用语言:Python3

class Solution:
    def decodeString(self, s: str) -> str:
        res = []
        for char in s:
            if char == ']':
                rep = ''
                repCount = ''
                while res and res[-1] != '[':
                    rep = res.pop() + rep
                res.pop()
                while res and res[-1].isnumeric():
                    repCount = res.pop() + repCount
                res.append(rep * int(repCount))
            else:
                res.append(char)
        return ''.join(res)

复杂度分析 时间复杂度:O(N) 空间复杂度:O(N)

HydenLiu commented 3 years ago

思路

js

/**
 * @param {string} s
 * @return {string}
 */
var decodeString = function (s) {
  let numStact = []  // 倍数栈
  let strStact = [] // 字符栈
  let res = ''
  let num = 0

  for (let i of s) {
    if (!isNaN(i)) { // 是否是数字
    // * 10是因为可能是多位树
      num = num * 10 + Number(i)
    } else if (i === '[') {
       /*
        * 是否遇到‘[’
        * 将之前的res和倍数放入对应的栈中
        */
      strStact.push(res) 
      res = ''
      numStact.push(num)
      num = 0
    } else if (i === ']') {
      /*
        * 是否遇到‘]’
        * 获取最后放入栈的字符
        * repeat 批量返回res
        */
      res = strStact.pop() + res.repeat(numStact.pop())
    } else {
      res += i
    }
  }

  return res
};

复杂度分析

lilixikun commented 3 years ago

思路

使用双栈来解决、一个用来储存复制多少次、一个用来储存当前需要复制的 字符串

代码

    const numStack =[];
    const strStack =[];
    let resStr = "",num=""
    for(let str of s){
        if(!isNaN(str))num+=str。//处理 100a 这种情况
        // 这个地方是关键、先➕入需要复制的字符串
        else if(str==="["){
            strStack.push(resStr)
            numStack.push(num)
            resStr=''
            num=""
        }
        else if(str==="]"){
            resStr=strStack.pop()+resStr.repeat(numStack.pop())
        }else resStr+=str
    }
    return resStr

复杂度

JinMing-Gu commented 3 years ago
class Solution {
public:
    string decodeString(string s) 
    {
        string res = "";
        stack <int> nums;
        stack <string> strs;
        int num = 0;
        int len = s.size();
        for(int i = 0; i < len; ++ i)
        {
            if(s[i] >= '0' && s[i] <= '9')
            {
                num = num * 10 + s[i] - '0'; // 123-->0*10+1-->1*10+2-->12*10+3
            }
            else if((s[i] >= 'a' && s[i] <= 'z') ||(s[i] >= 'A' && s[i] <= 'Z'))
            {
                res = res + s[i];
            }
            else if(s[i] == '[') //将‘[’前的数字压入nums栈内, 字母字符串压入strs栈内
            {
                nums.push(num);
                num = 0;
                strs.push(res); 
                res = "";
            }
            else //遇到‘]’时,操作与之相配的‘[’之间的字符,使用分配律
            {
                int times = nums.top();
                nums.pop();
                for(int j = 0; j < times; ++ j)
                    strs.top() += res;
                res = strs.top(); //之后若还是字母,就会直接加到res之后,因为它们是同一级的运算
                                  //若是左括号,res会被压入strs栈,作为上一层的运算
                strs.pop();
            }
        }
        return res;
    }
};
m-z-w commented 3 years ago
var decodeString = function(s) {
    const stack = []
    let res = ''
    let brackets = 0
    let repeatStr = ''
    let numStr = ''
    for (let i = 0; i < s.length; i++) {
        if (!isNaN(Number(s[i]))) {
            numStr += s[i]
            continue
        } else if (numStr) {
            stack.push(Number(numStr))
            numStr = ''
        }
        if (s[i] !== ']') {
            stack.push(s[i])
        }
        if (s[i] === '[') {
            brackets++
        } else if (s[i] === ']') {
            brackets--
            let str = ''
            let a = stack.pop()
            while (a !== '[') {
                str = a + str
                a = stack.pop()
            }
            a = stack.pop()
            for (let i = 0; i < a; i++) {
                repeatStr += str
            }
            if (brackets === 0) {
                res += repeatStr
            } else {
                stack.push(repeatStr)
            }
            repeatStr = ''
        } else if (isNaN(Number(s[i])) && brackets === 0) {
            res += s[i]
            stack.pop()
        }
    }
    return res
};

时间复杂度:O(n), n为s的长度 空间复杂度:O(n)

HouHao1998 commented 3 years ago

思路

用的栈,数字和字母封开存放,存放之后,遇到]就取出最顶上的并传递

代码

class Solution {
    public String decodeString(String s) {
        String k="" ;
        String out="" ;
        int intK ;
        boolean r = true;
        String d="" ;
        Stack<Integer> stack = new Stack<>();
        Stack<String> stack1 = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            if(s.charAt(i)=='['){
                r=false;
                int x = i;
                k="";
                while (x>0){
                    if(Character.isDigit(s.charAt(x - 1))){
                        k= s.charAt(x - 1)+k;
                    }else {
                        x=0;
                    }
                    x--;
                }
                stack.add(Integer.parseInt(k));
                 x = i;
                 d="";
                while (x<s.length()){
                    if(Character.isDigit(s.charAt(x + 1))||s.charAt(x + 1)==']'){
                        x=s.length();
                    }else {
                        d= d+s.charAt(x + 1);
                    }
                    x++;
                }
                stack1.add(d);
            }else
            if(s.charAt(i)==']'){
                intK=stack.pop();
                d=stack1.pop();
                String dd="";
                for (int j = 0; j < intK; j++) {
                    dd=dd+d;
                }
                if(!stack.empty()){
                    dd = stack1.pop()+dd;
                    if(i!=s.length()-1&&!Character.isDigit(s.charAt(i + 1))){
                        int x=i;
                        while (x<s.length()){
                            if(Character.isDigit(s.charAt(x + 1))||s.charAt(x + 1)==']'){
                                x=s.length();
                            }else {
                                dd= dd+s.charAt(x + 1);
                            }
                            x++;
                        }
                    }
                    stack1.add(dd);
                }else {
                    out=out+dd;
                }
                if(i<s.length()-1&&!Character.isDigit(s.charAt(i + 1))&&stack.empty()){
                        int x=i;
                        while (x<s.length()-1){
                            if(Character.isDigit(s.charAt(x + 1))){
                                x=s.length();
                            }else {
                                out= out+s.charAt(x + 1);
                            }
                            x++;
                        }
                }

            }else {
                if(!Character.isDigit(s.charAt(i ))&&r){
                    out =out+s.charAt(i);
                }

            }

        }
        return out;
    }
}

复杂度

时间复杂度O(N) 常数有点大

zhuliangyu commented 3 years ago

@solution-sync:begin

''' 3[a2[c]] st st = 3 [ a 2 [ c ] c 2 st = 3 [ a c c c c a reverse! 3 * (a c c)

acc acc acc

while not [ push all char into stack

meet ] pop all letters -> save to tmpStr pop [ pop all digits -> save to tmpNum reverse(tmpStr) tmpNum * tmpStr -> push into stack

3[a]2[bc] st = 3 [ a a 3 st = aaa2[bc cb 2 cbcb reverse-> bcbc aaa + bcbc

''' from collections import deque from typing import List from collections import OrderedDict from collections import defaultdict import functools import heapq import bisect

class Solution: def decodeString(self, s: str) -> str: if not s: return ""

    st = deque()

    i = 0
    while i < len(s):

        # 不能在两个地方 同时对i + 1
        if s[i] != ']':
            st.append(s[i])
        else: # == ]
            tmpStr = ""
            # error
            while st and st[-1].isalpha():
                # print(poped)
                tmpStr = st.pop() + tmpStr

            # get rid of [
            if st:
                st.pop()

            tmpNum = ''
            while st and (st[-1].isdigit()):
                tmpNum = st.pop() + tmpNum
            tmpNum = int(tmpNum)

            tmpStr = tmpStr * tmpNum

            for ele in tmpStr:
                st.append(ele)

        # error
        i += 1

    return "".join(st)

@solution-sync:end

if name == 'main': s = "100[leetcode]"

result = Solution().decodeString(s)
print(result)
ginnydyy commented 3 years ago

Problem

https://leetcode.com/problems/decode-string/

Notes

Solution

class Solution {
    public String decodeString(String s) {
        Stack<Character> stack = new Stack<>();

        for(int i = 0; i < s.length(); i++){
            char curr = s.charAt(i);

            // start to process the encoded string from stack
            if(curr == ']'){
                List<Character> list = new LinkedList<>();
                while(!stack.isEmpty() && stack.peek() != '['){
                    list.add(0, stack.pop());
                }

                // pop the '[' from stack and dump it
                stack.pop();

                // process the digits from stack
                int base = 1;
                int k = 0;
                while(!stack.isEmpty() && Character.isDigit(stack.peek())){
                    k += Character.getNumericValue(stack.pop()) * base;
                    base *= 10;
                }

                // decode the string by generating the sub string k times and push to stack
                while(k > 0){
                    for(char c : list){
                        stack.push(c);
                    }
                    k--;
                }
            }else{
               stack.push(curr); 
            }

        }

        StringBuilder result = new StringBuilder();
        while(!stack.isEmpty()){
            result.append(stack.pop());
        }

        return result.reverse().toString();
    }
}

Complexity

ZJP1483469269 commented 3 years ago

思路

使用栈对括号进行匹配,每次将字符串与数字入栈,遇到】进行一次出栈,并对字符串进行运算。

代码

class Solution {
public String decodeString(String s) {
    StringBuilder res = new StringBuilder();
    int multi = 0;
    LinkedList<Integer> stack_multi = new LinkedList<>();
    LinkedList<String> stack_res = new LinkedList<>();
    for(Character c : s.toCharArray()) {
        if(c == '[') {
            stack_multi.addLast(multi);
            stack_res.addLast(res.toString());
            multi = 0;
            res = new StringBuilder();
        }
        else if(c == ']') {
            StringBuilder tmp = new StringBuilder();
            int cur_multi = stack_multi.removeLast();
            for(int i = 0; i < cur_multi; i++) tmp.append(res);
            res = new StringBuilder(stack_res.removeLast() + tmp);

        }
        else if(c >= '0' && c <= '9') multi = multi * 10 + Integer.parseInt(c + "");
        else res.append(c);
    }
    return res.toString();
}

}

复杂度分析

时间复杂度:O(N) 空间复杂度:O(N)

newbeenoob commented 3 years ago

思路


设置两个辅助栈,一个用于存储数字,一个用于存储encoded_string (这个栈内最后的内容就是结果) 遇到数字时候,要记得处理连续的数字位,n = n * 10 + cur 最后再压入数字栈 遇到非数字时,分情况讨论:

  1. 遇到 右方括号,代表括号闭合,不断弹出栈直到遇到最近的左方括号,在这个过程当中弹出的栈就是要重复k次的encoded string , 从数字栈中弹出一个元素 , repeat 计算后再放回 encoded_string栈内

  2. 其余情况一股脑入栈即可

代码:Javascript


var decodeString = function(s) {
    let ans = "";

    let data = [];
    let count = [];
    s = s.split('');
    for(let i = 0 ; i < s.length ; ++i){
        if(isNaN(+s[i])){
            if(s[i] === ']'){
                let temp = '';
                while(data[data.length - 1] !== '[') {
                    temp += data.pop();
                }
                data.pop();
                let times = count.pop();
                data.push(temp.repeat(times));
            }else{
                data.push(s[i]);
            }

        }else if(!isNaN(+s[i])){
            let num = 0;

            while(!isNaN(+s[i])) {
                num = +s[i] + num * 10;
                ++i;
            }

            count.push(num);
            --i;
        }
    }

    return data.reduce((acc , cur) => {
        return acc + cur.split('').reverse().join('')
    } , '')
};

复杂度分析


标签


字符串 ,

JAYWX commented 3 years ago

思路

循环s的各元素i放入栈res,
当元素i为']'时,从栈res往外取数据并进行字符合并,直到遇到'[';
之后开始数字的合并,直到栈往外取不是数字,最后的字符串=数字项*字符串;
再把算得字符串放入栈中,往下循环s的下各元素
注:

  1. '['前的数字不一定是一位,可能是两位数字,如10[a]
  2. 栈最后的边界条件,res为空,res[-1]报错 (查了好半天 =,=)

复杂度分析

时间复杂度:最坏$O(n^2)$
空间复杂度:$O(n)$

代码

class Solution:
    def decodeString(self, s: str) -> str:
        res = []
        s = '1' + '[' + s + ']'
        for i in s:
            if i == ']':
                x = res.pop()
                _i = ''
                while x != '[':
                    _i = x + _i
                    x = res.pop()
                num_str = ''
                while True:
                    if not (res and res[-1].isdigit()):
                        break
                    num_str = res.pop() + num_str
                _i = int(num_str) * _i
                res.append(_i)
            else:
                res.append(i)

        return res[-1]
xyinghe commented 3 years ago

public String decodeString(String s) {

    Stack<Character> stack = new Stack<>();

    for(char c : s.toCharArray())
    {
        if(c != ']') 
            stack.push(c); // 把所有的字母push进去,除了]

        else 
        {
            //step 1: 取出[] 内的字符串

            StringBuilder sb = new StringBuilder();
            while(!stack.isEmpty() && Character.isLetter(stack.peek()))
                sb.insert(0, stack.pop());

            String sub = sb.toString(); //[ ]内的字符串
            stack.pop(); // 去除[

            //step 2: 获取倍数数字

            sb = new StringBuilder();
            while(!stack.isEmpty() && Character.isDigit(stack.peek()))
                sb.insert(0, stack.pop());

            int count = Integer.valueOf(sb.toString()); //倍数

            //step 3: 根据倍数把字母再push回去

            while(count > 0)
            {
                for(char ch : sub.toCharArray())  
                    stack.push(ch);
                count--;
            }
        }
    }

  //把栈里面所有的字母取出来
    StringBuilder retv = new StringBuilder();
    while(!stack.isEmpty())
        retv.insert(0, stack.pop());

    return retv.toString();
}
yanjyumoso commented 3 years ago
class Solution:
    def decodeString(self, s: str) -> str:
        # 遇到 】 之前不断进行压栈
        # 遇到 】 之后开始出栈直到非数字为止,再压栈

        stack = []
        for c in s:
            if c == ']':
                pattern = ''
                count = ''
                while stack and stack[-1] != '[':
                    pattern  = stack.pop() + pattern
                stack.pop()
                while stack and stack[-1].isdigit():
                    count = stack.pop() + count
                stack.append(int(count) * pattern)
            else:
                stack.append(c)
        return "".join(stack)
chaggle commented 3 years ago

Day-4 :2021-09-13

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"

题目思路

代码块

class Solution {
public:
    string decodeString(string s) {
        stack<string> pos;
        stack<int> nums;
        string res = "";
        int sum = 0;
        for(int i = 0; i < s.size(); i++)
        {
            if(s[i] >= '0' && s[i] <= '9')
                sum = sum * 10 + s[i] - '0';
            else if((s[i] >= 'a' && s[i] <= 'z')||(s[i] >= 'A' && s[i] <= 'Z'))
                res += s[i]; //注意大小写,之前第一次提交发现大小写也存在区分
            else if(s[i] == '[')
            {
                nums.push(sum);
                sum = 0;    //重置 0
                pos.push(res);
                res = "";   //重置为空字符串
            } 
            else if(s[i] == ']')        //此处举例3[a2[c]];
            {                           //出现[后将3放入nums中,sum重置,res仍为""
                sum = nums.top();       //而后再出现[,此时sum=2;res="a",存入pos
                nums.pop();             //第一次出现], 此时sum = nums.top() == 2
                while(sum)              //pos.top = a, res = 'c',输出为res = "acc"
                {                       //第二次出现],sum = nums.top() == 3;
                    pos.top() += res;   //pos.top = "" 第一次存入的res, res ="acc",
                    sum--;              //画图更好理解,sum经历变化后的值最终始终为0
                }
                res = pos.top();
                pos.pop();
            }
        }
        return res;
    }
};

复杂度

flame0409 commented 3 years ago

思路

(最初想到的是用迭代,但是不太好控制,看了题解后选择使用栈,是在略菜,一边自己动手一边照着改) 思路就是压栈,子字符串压栈,最后依次拿出来,与对应的重复次数做循环叠加后再入栈,作为上一个字符串的子字符串,最后完成全部的字符串

class Solution {
     int ptr = 0 ;
    public String decodeString(String s) {
        LinkedList<String> stk = new LinkedList<String>();
        int rep = 1; //rep设为重复次数
        StringBuffer c_str = new StringBuffer();//用于压栈的子字符串
       while(ptr < s.length()){
           char chr = s.charAt(ptr);
           if(Character.isDigit(chr)){
               String digits = getDigits(s);//从ptr开始,为数字,依次进栈
               stk.addLast(digits);
           }
           else if(Character.isLetter(chr)||chr == '['){
               //开始字符压栈
               stk.addLast(String.valueOf(s.charAt(ptr++)));
           }
           else{//右括号
               ++ptr;//跳过括号,直接进行一个字符串的组装
               LinkedList<String> sub = new LinkedList<>();
               while (!"[".equals(stk.peekLast())){   // peeklast:检查队尾元素,出栈,遇见了左括号停止
                   sub.addLast(stk.removeLast());
               }
               //子字符串翻转
               Collections.reverse(sub);
               stk.removeLast();//左字符串弹出
               rep = Integer.parseInt(stk.removeLast());//取出重复字符串的string形式,转成int
               StringBuffer stringBuffer = new StringBuffer();
               String sub_str = getString(sub);
               while(rep-- > 0){
                   stringBuffer.append(sub_str);
               }
               stk.add(stringBuffer.toString());
           }

       }
        return getString(stk);
    }
    public String getDigits(String s) {
        StringBuffer ret = new StringBuffer();
        while (Character.isDigit(s.charAt(ptr))) {
            ret.append(s.charAt(ptr++));
        }
        return ret.toString();
    }

    public String getString(LinkedList<String> v) {
        StringBuffer ret = new StringBuffer();
        for (String s : v) {
            ret.append(s);
        }
        return ret.toString();
    }

}

复杂度分析:

时间复杂度:O(n)

空间复杂度:O(n)

AnhTom2000 commented 3 years ago

思路

使用两个辅助栈。

一个存储数字,一个存储遇到"["的瞬时结果(这个栈中的所有瞬时结果合起来就是最最终的结果)。

如果遇到数字,需要处理多位数字的情况,使用mutil变量将他们连接起来,并在遇到"["时压入存储数字的栈。

非数字情况,有三种情况:

代码:Java

class Solution { 
    public String decodeString(String s) {
        Stack<Integer> s1  = new Stack<>();
        Stack<String> s2 = new Stack<>();
        StringBuilder res = new StringBuilder();
        int mutil = 0;
        for(char c: s.toCharArray()){
          if(c == '['){
            s1.push(mutil);
            s2.push(res.toString());
            res = new StringBuilder();
            mutil = 0;
          }else if(c == ']'){
            int nums = s1.pop();
            StringBuilder temp = new StringBuilder();
            for(int i = 0; i < nums;i++){
              temp.append(res);
            }
            res  = new StringBuilder(s2.pop() + temp);
          }else if(Character.isDigit(c)){
            mutil = mutil * 10 + (c - '0');
          }else res.append(c);
        }
        return res.toString();
    }
}

复杂度分析

时间复杂度:O(n),n代表字符串长度

空间复杂度:O(n),栈空间最大存储的是字符串的长度。

septasset commented 3 years ago

思路

  1. 字符串匹配 → 栈

关键点

  1. n[xxx]展开重新入栈
  2. n可能有两位以上

代码(Java)

class Solution {
    public String decodeString(String s) {        
        StringBuilder strB = new StringBuilder();
        StringBuilder strB2 = new StringBuilder();
        Deque<Character> stack = new LinkedList<Character>();

        for (int i = s.length()-1; i>=0; --i){
            char chr = s.charAt(i);
            if (chr == ']') stack.push(chr);
            else if (Character.isLetter(chr)){
                if (stack.size()==0) strB.insert(0, chr);
                else {
                    stack.push(chr);
                }
            }else { // '['
                StringBuilder tmpt = new StringBuilder();
                int ptr = i;
                do {
                    ptr--; 
                    if (!Character.isDigit(s.charAt(ptr))){
                        break;
                    }
                    tmpt.insert(0, s.charAt(ptr));                    
                } while (ptr>=1);
                int repeat = Integer.parseInt(tmpt.toString());

                List<Character> inner = new ArrayList<Character>();
                while (stack.peek() != ']'){
                    inner.add(stack.pop());
                }
                stack.pop();
                for (int r=0; r<repeat;++r){
                    for (int j = inner.size()-1; j>=0; --j){
                        stack.push(inner.get(j));
                    }
                }

                if (ptr==0 && Character.isDigit(s.charAt(ptr))) break;
                else i=ptr+1;
            }
        }
        while (stack.size()>0){
            strB2.append(stack.pop());
        }
        return strB2.toString()+strB.toString();
    }
}

复杂度分析

YQYCS commented 3 years ago

思路

用栈处理,遇到 "[",就要开始重复字符串了,另外重复的数字是可能存在多位的, 所以需要往前找到不为数字的那⼀位,把数字转换出来。 最后⽤把 stack ⾥⾯的字符串都串联起来即可

代码

class Solution:
    def decodeString(self, s: str) -> str:
        def dfs(s, i):
            res, multi = "", 0
            while i < len(s):
                if '0' <= s[i] <= '9':
                    multi = multi * 10 + int(s[i])
                elif s[i] == '[':
                    i, tmp = dfs(s, i + 1)
                    res += multi * tmp
                    multi = 0
                elif s[i] == ']':
                    return i, res
                else:
                    res += s[i]
                i += 1
            return res
        return dfs(s,0)

复杂度

时间复杂度: O(n) 空间复杂度: O(n)

suukii commented 3 years ago

Link to LeetCode Problem

S1: 递归

https://camo.githubusercontent.com/cfacf3e8bb0851bd0b122e218ad63e5ab2abf6d23d439dadf638ecb72298de74/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7375756b69692f39312d646179732d616c676f726974686d2f6173736574732f6465636f64655f737472696e675f747265652e706e67

n[string] 表示解析 [] 模板里面的内容,然后重复 n 次,即得到 nstring 拼接起来的字符串。

根据题意,[] 里面还可以再嵌套 [] ,例如 n[m[string]]。这种情况下,我们得先解析最内层的模板,重复 m 次,然后将 m * string 的结果作为外层模板的解析内容,再重复 n 次。

如果嵌套的层数更多,我们也是得先找到最内层的 [],就像洋葱一样,一层层剥开,然后再从内到外一层层解析和拼接。这种层层嵌套的描述很容易就让人想到了递归。

按照常规,写递归时不要过多考虑前后的递归函数,想好当前递归函数需要处理些什么就好了。

class Solution {
public:
    string decodeString(string s) {
        return decodeString(s, 0).first;
    }

    pair<string, int> decodeString(string s, int cur) {
        int k = 0;
        string decoded;
        while (cur < s.size()) {
            // 收集数字
            if (isdigit(s[cur])) {
                k = k * 10 + s[cur] - '0';
                cur++;
            }
            // 收集字母
            else if (isalpha(s[cur])) {
                decoded.push_back(s[cur]);
                cur++;
            }
            // 开始解析下一层嵌套
            else if (s[cur] == '[') {
                pair<string, int> res = decodeString(s, cur + 1);
                // 解析完嵌套模式后
                while (k-- > 0) {
                    decoded.append(res.first);
                }
                k = 0;
                cur = res.second;
            }
            // 结束当前递归
            else if (s[cur] == ']') {
                return {decoded, cur + 1};
            }
        }
        return {decoded, -1};
    }
};
/**
 * @param {string} s
 * @return {string}
 */
var decodeString = function(s, cur = 0) {
    let k = 0;
    let decoded = '';
    while (cur < s.length) {
        if (s[cur] === '[') {
            const [str, pos] = decodeString(s, cur + 1);
            decoded += str.repeat(k);
            k = 0;
            cur = pos;
        } else if (s[cur] === ']') {
            return [decoded, cur + 1];
        } else if (/[0-9]/.test(s[cur])) {
            k = k * 10 + parseInt(s[cur++]);
        } else {
            decoded += s[cur++];
        }
    }
    return decoded;
};

S2: 循环+栈

可以用递归解决的问题,也可以用循环来解决。

这里我用了正则 /[a-zA-Z]+|[0-9]+|\[|\]/ 和 exec() 方法来遍历字符串并把它们拆分成 token,比如,lz3[ab2[c]] 会被拆分成 lz3[ab2[c]]

  1. 遇到字母块 (lz)、数字时,入栈;
  2. 遇到 [ 时,入栈,用来标识当前进入一个模板解析了;
  3. 遇到 ] 时,说明当前模板遍历完了,我们可以开始解析了。
    1. 开始出栈,把出栈的字母块都拼接起来。
    2. 等出栈到 [ 时,说明当前模板解析完成了。
    3. 继续出栈一个元素,这个元素就是当前模板要重复的次数。
    4. 字母块 * 次数 重新入栈,这是因为模板是可嵌套的,当前模板外面可能还有一层模板,所以我们要把当前层级的解析结果重新入栈,接着解析外层的模板。

https://camo.githubusercontent.com/cf2e9f7f12b4e571df77f88ec55ce574760d221c5b4551e0a179d361aad35f98/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7375756b69692f39312d646179732d616c676f726974686d2f6173736574732f6465636f64655f737472696e675f737461636b2e706e67

/**
 * @param {string} s
 * @return {string}
 */
var decodeString = function (s) {
    const reg = /[a-zA-Z]+|[0-9]+|\[|\]/g;
    const stack = [];
    const peek = () => stack[stack.length - 1]; // p.s. 不正经栈

    while (reg.lastIndex < s.length) {
        let token = reg.exec(s)[0];
        if (token !== ']') {
            // 数字,字母,左括号通通入栈
            stack.push(token);
        } else {
            // 遇到右括号就开始出栈
            let str = '';
            // [] 中间的就是要重复的模式,把它们全部出栈,拼接起来
            while (peek() !== '[') {
                str = stack.pop() + str;
            }
            // 丢掉左括号
            stack.pop();
            // 左括号前面的一定是模式重复的次数
            const num = +stack.pop();
            // 把复制操作后的字符串放回栈中,作为外层 [] 模式的一部分
            stack.push(str.repeat(num));
        }
    }
    return stack.join('');
};
asterqian commented 3 years ago

思路

看到有括号的操作首先想起栈

代码

string decodeString(string s) {
    stack <int> nums;
    stack <string> str;
    int num = 0;
    string res = "";
    for (int i = 0; i < s.size(); ++i) {
        if (s[i] >= '0' && s[i] <= '9') {
            num = num * 10 + s[i] - '0';
        } else if (s[i] == '[') {
            nums.push(num);
            num = 0;
            str.push(res);
            res = "";
        } else if (s[i] == ']') {
            int time = nums.top();
            nums.pop();
            for(int j = 0; j < time; ++j) {
                str.top() += res;
            }
            res = str.top();
            str.pop();
        } else {
            res += s[i];
        }
    }
    return res;
}

复杂度分析

时间复杂度: O(N) 遍历一次,N为s的长度, worst case O(N^2)
空间复杂度: O(2N) 两个stack
yibenxiao commented 3 years ago

394. 字符串解码

思路

平铺直叙

遇到的问题

代码

class Solution:
    def decodeString(self, s: str) -> str:
        # res用来模拟栈
        res=[]
        ans=""
        # flag=0代表没有[]未处理
        flag=0

        Len=len(s)
        for i in range(Len):
            # 如果是字母且不处于[]中,直接放入答案中
            if s[i].isalpha() and flag==0:
                ans+=s[i]
                continue

            # 如果是字母且不等于],直接压入栈
            if s[i]!="]":
                res.append(s[i])

            # flag值的设定,以及处理一个[]
            if s[i]=="[":
                flag+=1
            elif s[i]=="]":
                flag-=1

                # 找到最近的一个[
                index=0
                for j in range(len(res)-1,-1,-1):
                    if res[j]=="[":
                        index=j
                        break

                # t代表[]的字母
                t=""
                for j in range(index+1,len(res)):
                    if res[j].isdigit()==False:
                        t+=res[j]
                # 栈内多余的元素删除
                del res[index:len(res)]
                # 解决数字问题,例如12,231之类的
                count=index-1
                while True:
                    if res[count].isdigit():
                        count-=1
                    else:
                        break
                    if count<0:
                        break
                # 字母需要重复多少次
                num=0
                for j in range(count+1,index):
                    num=num*10+int(res[j])
                t=t*num

                # 删除使用过的数字,例如3,34之类的,也可以写成 del res[count+1:index]
                Len1=len(res)-index+count+1
                while len(res)!=Len1:
                    del res[count+1]

                # 直接放入答案,还是压入栈
                if flag!=0:
                    for j in t:
                        res.append(j)
                else:
                    ans=ans+t

        return ans

复杂度

时间复杂度:O(N^2),但我感觉速度可能要稍微快一点。可能是分析的有问题

空间复杂度:O(N)

last-Battle commented 3 years ago

思路

关键点

代码

C++ Code:


class Solution {
public:
    string decodeString(string s) {
        string res;
        stack<int> stN;
        stack<string> stS;
        int num = 0;

        for (auto& v : s) {
            // 持续处理数字
            if (isGigit(v)) {
                num = num * 10 + (v - '0');
            } 
            // 遇到 "[" 就把维护的数字和字符串各自入栈
            else if (v == '[') {
                cout << "num: " << num << endl;
                stN.push(num);
                num = 0;

                stS.push(res);
                res.clear();
            } else if (v == ']') {
                // 重复次数
                int repeatTimes = stN.top();
                stN.pop();

                string tmp = stS.top();
                stS.pop();
                for (int i = 1; i <= repeatTimes; ++i) {
                    tmp += res;
                }

                res = tmp;
            } 
            // 维护当前处理到的字符串
            else {
                res += v;
            }
        }

        return res;
    }

    bool isGigit(const char& c) {
        return c >= '0' && c <= '9';
    }
};

复杂度分析

令 n 为数组长度。

fzzfgbw commented 3 years ago

思路

代码

func decodeString(s string) string {
    var stack []uint8
    for i := range s {
        if s[i] != ']' {
            stack = append(stack, s[i])
        } else {
            var left int
            var dup []uint8
            var times int
            var mul = 1
            for j := len(stack) - 1; j >= 0; j-- {
                if stack[j] == '[' {
                    left = j + 1
                    for i2 := range stack[left:] {
                        dup = append(dup,stack[left:][i2])
                    }
                    j--
                    for  j >= 0 && '0' <= stack[j] && stack[j] <= '9' {
                        times += int(stack[j]-48) * mul
                        mul *= 10
                        j--
                    }

                    stack = stack[:j+1]
                    for times>0 {
                        stack  = append(stack,dup...)
                        times--
                    }
                    break

                }

            }

        }
    }
    var res string
    for i := range stack {
        res+=string(stack[i])
    }
    return res
}

复杂度分析

joriscai commented 3 years ago

思路

代码

javascript

/**
 * @param {string} s
 * @return {string}
 */
var decodeString = function(s) {
  const stack = []
  let ret = ''
  for (let i = 0; i < s.length; i++) {
    const cur = s[i]
    if (cur !== ']') {
      stack.push(cur)
      continue
    }

    // 找括号内的字符串
    let sub = ''
    while(stack[stack.length - 1] !== '[') {
      sub = stack.pop() + sub
    }
    // remove [
    stack.pop()

    // 找括号前的数字
    let top = stack[stack.length - 1]
    let num = ''
    while(!isNaN(Number(top))) {
      num = stack.pop() + num
      top = stack[stack.length - 1]
    }

    // 重复对应的字符串
    sub = sub.repeat(Number(num))
    stack.push(...sub)
  }
  return stack.join('')
};

复杂度分析

Socrates2001 commented 3 years ago

C implementation

#define MAX_STACK_SIZE 3000

char * decodeString(char * s){
    int len = strlen(s);
    char * strStack = malloc(sizeof(char) * MAX_STACK_SIZE);
    int top = -1;

    for(int i=0; i<len; i++)
    {
        char c = s[i];
        if(c != ']')
            strStack[++top] = c;
        else
        {
            char * tmpStack = malloc(sizeof(char) * MAX_STACK_SIZE);
            int tmpTop = -1;
            while(strStack[top] != '[') //将相应字符串逆序放入中转栈
            {
                tmpStack[++tmpTop] = strStack[top];
                top--;
            }
            top--; //相当于是将‘[’出栈

            char * cpyStr = malloc(tmpTop + 2); //之所以加2,是因为当前的tmpTop值为字符串长度-1,还有一个1是给‘\0’用的
            for(int j=tmpTop; j>=0; j--)
                cpyStr[tmpTop - j] = tmpStack[j]; //该循环完成后顺便也将tmpStack里的字符逆序了,即还原成原有顺序
            cpyStr[++tmpTop] = '\0';

            int timesOfStr = 0;
            int exp = 0;
            while(top>=0 && strStack[top] >= '0' && strStack[top] <= '9') //计算相应字符串的倍数
            {
                timesOfStr += (strStack[top] - '0') * pow(10, exp);
                top--;
                exp++;
            }

            int l = strlen(cpyStr);
            for(int j=0; j<timesOfStr; j++) //翻倍相应字符串
                for(int n=0; n<l; n++)
                    strStack[++top] = cpyStr[n];
            free(tmpStack);
            free(cpyStr);
        }
    }   
    strStack[++top] = '\0';
    return strStack;       
}
rebel-ly commented 3 years ago

思路

自己虽然想到了用两个栈,一个存放数据,一个存放字符串,但是没做下去,看了一篇优秀题解,就主要讲一下他的做法吧。 同样,主要是使用两个栈,一个用于存放数据,一个用于存放字符串; 但是需要注意,只有确定数据是完整的乘积后才存入栈中,字符串也同理,只有是完整的字符串才存入。因此,设置了一个整形num用来代表当前不够完整的数字,以及一个字符串item存放不完整的字符。 开始读取: 1)最简单的: 当读取的字节是’0‘到’9‘的时候(注意读出来的是String型),就把他放到num这个数字临时存储地,需要注意前面进去的需要乘以10再加上当前的数字;(将字符型转化为十进制数字) 当读取的字节是普通字符型(即非数字,非[ 非])的时候,直接放到item这个字符串临时存储地中。 2)处理读取到【】的情况: 当读取的字节为[ 的时候,意味着前面临时存入的num已经是完整的了,可以存入栈中; 同时已经完成的item也可以存入栈中;然后再将两个临时存储地初始化; 当读取字节为]的时候,意味着一个字符串读完了,那么就可以进行乘法处理了(从num_stack中取出刚刚放进去的完整num,作为当前item的倍数进行处理),最后将当前完成的item(之前已经存到item栈中)加到之前已经完成的item后面(字符串可以直接相加而相连)

代码

class Solution {
    public String decodeString(String s) {
     LinkedList<String> stack_item=new LinkedList<String>();
     LinkedList<Integer> stack_num=new LinkedList<Integer>();
     int num=0;
     StringBuilder item= new StringBuilder();
     for(int i =0;i<s.length();i++){
         Character c=s.charAt(i);
         if(c=='['){
             stack_item.addFirst(item.toString());
             stack_num.addFirst(num);
             num=0;
             item=new StringBuilder();
         }
         else if(c==']'){
             StringBuilder temp=new StringBuilder();
             int cur_num=stack_num.pop();
             for(int j =0; j<cur_num; j++){
                 temp.append(item);
             }
             item =new StringBuilder(stack_item.pop()+temp);
         }
         else if(c>='0'&&c<='9'){
             num=num*10+Integer.parseInt(c+"");
         }
         else{
             item.append(c);
         }
     }
     return item.toString();
    }
}

复杂度分析

时间复杂度o(n) 空间复杂度o(n)

Socrates2001 commented 3 years ago

对昨天的越界修改

C implementation

typedef struct {
    int topOfStack;
    int capacity;
    int * array;

} CustomStack;

CustomStack* customStackCreate(int maxSize) {
    CustomStack * s = malloc(sizeof(CustomStack));
    if(s == NULL)
    {
        printf("Out of space!");
        return NULL;
    }
    s->array = malloc(sizeof(int) * maxSize);
    if(s->array == NULL)
    {
        printf("Out of space!");
        return NULL;
    }
    s->capacity = maxSize;
    s->array[s->topOfStack] = -1;

    return s;
}

void customStackPush(CustomStack* obj, int x) {
    if(obj->topOfStack != obj->capacity-1)
    {
        obj->array[++obj->topOfStack] = x;
    }

}

int customStackPop(CustomStack* obj) {
    if(obj->topOfStack == -1)
    {
        printf("Empty stack!");
        return -1;
    }
    return obj->array[obj->topOfStack--];
}

void customStackIncrement(CustomStack* obj, int k, int val) {
    int i;

    if(k >= obj->capacity)
        for(i=0; i<obj->capacity; i++)
            obj->array[i] += val;
    else
        for(i=0; i<k; i++)
            obj->array[i] += val;
}

void customStackFree(CustomStack* obj) {
    if(obj != NULL)
    {
        free(obj->array);
        free(obj);
    }
}

/**
 * Your CustomStack struct will be instantiated and called as such:
 * CustomStack* obj = customStackCreate(maxSize);
 * customStackPush(obj, x);

 * int param_2 = customStackPop(obj);

 * customStackIncrement(obj, k, val);

 * customStackFree(obj);
*/