Open azl397985856 opened 3 years ago
class Solution {
public:
string decodeString(string s) {
if(s.empty())
return "";
string ans;
int i = 0;
int len = s.length();
int c = 0;
while (isdigit(s[i]) && i < len)
c = c * 10 + (s[i++] - '0');
int j = i;
if (i < len && s[i] == '[')
{
int open = 1;
while (++j < len && open)
{
if (s[j] == '[') ++open;
if (s[j] == ']') --open;
}
}
else
{
while (j < len && isalpha(s[j]))
++j;
}
if (i == 0)
return s.substr(0, j) + decodeString(s.substr(j));
string ss = decodeString(s.substr(i + 1, j - i - 2));
while (c--)
ans += ss;
ans += decodeString(s.substr(j));
return ans;
}
};
【思路1——用栈来辅助匹配】
栈用来解决括号匹配问题一直可以的,题目中由于涉及字符串的多次拼接,可以开一个存字符串的栈;字符串重复的次数可以再用一个存数字的栈。
初始化 string str = ""
和 int multi = 0
, 从左向右遍历字符串中的元素:
multi
上,因为可能是给多位数字,即用多个数字字符表示一个整数;str
后面;['
左边的这部分字符串是不会发生变化的,那我们把str
压到字符串栈中,再把multi
压到数字栈中;之后再次初始化它们;str
中保存的就是括号内的字符串,因为在遇到左括号时str
已“归零”, 那我们弹出字符串栈的栈顶,就是左括号前面的字符串last_str
,弹出数字栈的栈顶multi
,则当前解码的字符串就等于last_str + str * multi
。string decodeString(string s) {
stack<int> num_stk;
stack<string> str_stk;
int multi = 0;
string str = "";
for(auto ch : s) {
if(isdigit(ch)){
multi = multi * 10 + ch - '0';
}
else if(isalpha(ch)){
str += ch;
}
else if(ch == '[') {
num_stk.push(multi);
str_stk.push(str);
str = "";
multi = 0;
}
else if(ch == ']') {
string last_str = str_stk.top();
str_stk.pop();
int cur_multi = num_stk.top();
num_stk.pop();
while(cur_multi--){
last_str += str;
}
str = last_str;
}
}
return str;
}
时间复杂度: $O(N)$,遍历一次字符串。
空间复杂度: 栈的空间最坏情况下是$O(N)$,如2[2[2[a]]]
。
package com.leetcode;
import java.util.Collections;
import java.util.LinkedList;
/**
* @author Enbing
* @create 2021-09-13 8:30 PM
* @Description
*/
public class T394 {
int ptr;
public String decodeString(String s) {
LinkedList<String> stk = new LinkedList<>();
ptr = 0;
while (ptr < s.length()) {
char cur = s.charAt(ptr);
if (Character.isDigit(cur)) {
//获取一个字母并进栈
String digits = getDigits(s);
stk.addLast(digits);
} else if (Character.isLetter(cur) || cur == '[') {
//获取一个字母并进栈
stk.addLast(String.valueOf(s.charAt(ptr++)));
} else {
++ptr;
LinkedList<String> sub = new LinkedList<>();
while (!"[".equals(stk.peekLast())) {
sub.addLast(stk.removeLast());
}
Collections.reverse(sub);
//左括号出栈
stk.removeLast();
//此时栈顶为当前sub对应的字符串应该出现的次数
int repTime = Integer.parseInt(stk.removeLast());
StringBuffer t = new StringBuffer();
String o = getString(sub);
//构造字符串
while (repTime-- > 0) {
t.append(o);
}
stk.addLast(t.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(S+∣s∣),即 O(S)O(S) 空间复杂度:O(S)
迭代法,遇到 ] 前不断入栈,然后出栈直到遇到数字。遇到数字就重复,再压入栈中。重复出栈操作直到碰到[
class Solution(object):
def decodeString(self, s):
"""
:type s: str
:rtype: str
"""
stack = []
for c in s:
if c== ']':
repstr=''
repcount=''
#遇到 [ 前不断出栈
while stack and stack[-1] != '[':
repstr = stack.pop() + repstr
#pop出'['
stack.pop()
#遇到数字就相加(字符串格式)
while stack and stack[-1].isnumeric():
repcount = stack.pop() + repcount
stack.append(repstr * int(repcount))
#不是]直接入栈
else:
stack.append(c)
return "".join(stack)
时间复杂度:O(n) 空间复杂度:O(n)
思路: 因为方括号可能内嵌,需从最内层decode,可使用一个辅助栈:
class Solution { public String decodeString(String str) {
if (str == null || str.length() == 0) {
return "";
}
Stack<Character> stack = new Stack<>();
for (char c : str.toCharArray()) {
if (c != ']') {
stack.push(c);
// 遇到']'
} else {
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty() && Character.isLetter(stack.peek())) sb.insert(0, stack.pop());
String str = sb.toString();
stack.pop();
sb = new StringBuilder();
while (!stack.isEmpty() && Character.isDigit(stack.peek())) sb.insert(0, stack.pop());
int i= Integer.valueOf(sb.toString());
while (i> 0) {
for (char cc : str.toCharArray()) stack.push(cc);
i--;
}
}
}
StringBuilder res = new StringBuilder();
while (!stack.isEmpty()) res.insert(0, stack.pop());
return res.toString();
}
}
复杂度: Time: O(n^2) Space: O(n)
使用入栈出栈操作,将原字符串解码
var decodeString = function(s) {
let res = '';
let multi = 0;
let stack_multi = [];
let stack_res = [];
for (let i = 0, len = s.length; i < len; i++) {
c = s.charAt(i)
if(c == '[') {
// 把数字和拼接的字母分别压入栈
stack_multi.push(multi)
stack_res.push(res)
multi = 0
res = ''
} else if(c == ']') {
let tmp = ''
// 数字出栈
let cur_multi = stack_multi.pop()
// 数字作为循环次数
for (let i = 0; i < cur_multi; i++) {
tmp += res
}
res = stack_res.pop() + tmp
} else if (c >= '0' && c <= '9') {
multi = multi * 10 + parseInt(c)
} else {
res += c
}
}
return res;
}
数据压栈和出栈
括号套括号的处理
python3
class Solution:
def decodeString(self, s: str) -> str:
stack=[]
num_str = ''
k = 0
for item in s:
if item.isdigit():
# 如果是数字就记录数字
k = k * 10 + int(item)
elif item == '[':
#如果遇到左括号就压入 括号前数字 和 已处理好的字符
stack.append((num_str,k))
num_str=''#记录下一次的 括号内字符 或 普通字符
k=0
elif item==']':
#遇到右括号则弹出,加上当前处理的方括号内字符*存储的K
inner=stack.pop()
num_str = num_str*inner[1]+inner[0]
else:
num_str += item
return num_str
令 n 为数组长度。
class Solution {
public String decodeString(String s) {
Stack
while(count > 0){
for(char ch : sub.toString().toCharArray() ){
stack.push(ch);
}
count--;
}
}
}
StringBuilder sb=new StringBuilder();
while(!stack.isEmpty()){
sb.insert(0,stack.pop());
}
return sb.toString();
}
}
使用栈对字符串进行记录,在出现"]"之前,将"["、数字及字母推入栈中。出现了"]"之后,先找出"["顶部的所有字母,再找出"["底部的数字,将前面找出的字母以数字的倍数推入栈中。然后继续遍历,最终得出结果。
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
if (!s.includes('[')) return s;
const stack = [];
for (let c of s) {
if (c !== ']') {
stack.push(c);
} else {
const temp = [];
let top = stack.pop();
while (top !== '[') {
temp.unshift(top);
top = stack.pop();
}
let count = '';
while (!isNaN(stack[stack.length - 1])) {
count = `${stack.pop()}${count}`;
}
while (count > 0) {
stack.push(...temp);
count--;
}
}
}
return stack.join('');
};
时间复杂度:O(S + |s|) = O(S);
空间复杂度:O(S)
相出了存在子问题,但是不会写代码 去看了答案,第一种理解了,递归子问题代码还是不怎么理解
设置一个栈stack,字符串res和一个整数变量multi,遍历s,当字符是数字时变成整数(单个字符数字大小在0~9,可能连续出现多个),是‘['时将res和multi进栈 ,是‘]’时将之前的res和multi弹出,与当前res相加
''' class Solution: def decodeString(self, s: str) -> str:
stack, res, multi = [], '', 0
for c in s:
if c == '[':
stack.append([res, multi])
res, multi = '', 0
elif c == ']':
last_res, multi = stack.pop()
res = last_res + multi*res
multi = 0
elif '0' <= c <= '9':
multi = multi*10 + int(c)
else:
res += c
return res
''' 时间复杂度:遍历字符串O(N) 空间复杂度:栈+字符串长度=O(N)
- 递归
代码
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)
字符串从前到后用栈进行处理
func decodeString(s string) string {
stack := []string{}
pointer := 0
for pointer < len(s) {
current := s[pointer]
if current >= '0' && current <= '9' {
digits := getDigits(s, &pointer)
stack = append(stack, digits)
} else if (current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z') || current == '[' {
stack = append(stack, string(current))
pointer++
} else {
pointer++
sub := []string{}
for stack[len(stack)-1] != "[" {
sub = append(sub, stack[len(stack)-1])
stack = stack[:len(stack)-1]
}
for i := 0; i < len(sub)/2; i++ {
sub[i], sub[len(sub)-i-1] = sub[len(sub)-i-1], sub[i]
}
stack = stack[:len(stack)-1]
repTime, _ := strconv.Atoi(stack[len(stack)-1])
stack = stack[:len(stack)-1]
t := strings.Repeat(getString(sub), repTime)
stack = append(stack, t)
}
}
return getString(stack)
}
func getDigits(s string, pointer *int) string {
digits := ""
for ; s[*pointer] >= '0' && s[*pointer] <= '9'; *pointer++ {
digits += string(s[*pointer])
}
return digits
}
func getString(v []string) string {
result := ""
for _, s := range v {
result += s
}
return result
}
时间复杂度:O(n) 空间复杂度:O(n)
[TOC]
Decode String
题中方括号成对出现,解题思路类似括号匹配(LC20 有效括号) 可以采用一个stack作为辅助,将非 "]" 都压入stack中,如果遇到 "]" ,则pop出来,判断是否是字符,遇到 "[" 则pop后,开始判断是否是数字,再将字符串按倍数扩展押入stack中
class Solution {
public String decodeString(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()){
if (c != ']'){
stack.push(c);
}else{
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty() && Character.isLetter(stack.peek())){
sb.insert(0, stack.pop());
}
String str = sb.toString();
stack.pop();
sb = new StringBuilder();
while(!stack.isEmpty() && Character.isDigit(stack.peek())){
sb.insert(0, stack.pop());
}
int count = Integer.parseInt(sb.toString());
while(count > 0){
for (char ch : str.toCharArray()){
stack.push(ch);
}
count--;
}
}
}
StringBuilder ans = new StringBuilder();
while(!stack.isEmpty()){
ans.insert(0, stack.pop());
}
return ans.toString();
}
}
复杂度分析
时间复杂度 : O(n)
空间复杂度 : O(n)
使用递归(DFS)后续复习递归补上
//Todo
官方题解
class Solution {
public:
string getDigits(string &s, size_t &ptr) {
string ret = "";
while (isdigit(s[ptr])) {
ret.push_back(s[ptr++]);
}
return ret;
}
string getString(vector <string> &v) {
string ret;
for (const auto &s: v) {
ret += s;
}
return ret;
}
string decodeString(string s) {
vector <string> stk;
size_t ptr = 0;
while (ptr < s.size()) {
char cur = s[ptr];
if (isdigit(cur)) {
// 获取一个数字并进栈
string digits = getDigits(s, ptr);
stk.push_back(digits);
} else if (isalpha(cur) || cur == '[') {
// 获取一个字母并进栈
stk.push_back(string(1, s[ptr++]));
} else {
++ptr;
vector <string> sub;
while (stk.back() != "[") {
sub.push_back(stk.back());
stk.pop_back();
}
reverse(sub.begin(), sub.end());
// 左括号出栈
stk.pop_back();
// 此时栈顶为当前 sub 对应的字符串应该出现的次数
int repTime = stoi(stk.back());
stk.pop_back();
string t, o = getString(sub);
// 构造字符串
while (repTime--) t += o;
// 将构造好的字符串入栈
stk.push_back(t);
}
}
return getString(stk);
}
};
时间复杂度:O(n) 空间复杂度:O(n)
使用栈存储未匹配的字符
class Solution {
public String decodeString(String s) {
char[] ch = s.toCharArray();
int len = ch.length;
Deque<String> stack = new LinkedList<>();
int num = 0;
for (int i = 0; i < len; ++i) {
if (ch[i] != ']') {
if (ch[i] >= '0' && ch[i] <= '9') {
num = num * 10 + ch[i] - '0';
} else if (ch[i] == '[') {
stack.push(num + "");
stack.push(ch[i] + "");
num = 0;
} else {
stack.push(ch[i] + "");
}
} else {
String str = "";
while (!"[".equals(stack.peek())) {
str = stack.pop() + str;
}
stack.pop();
int n = Integer.parseInt(stack.pop());
String res = "";
for (int j = 0; j < n; ++j) {
res += str;
}
stack.push(res);
}
}
String ans = "";
while (!stack.isEmpty()) {
ans = stack.pop() + ans;
}
return ans;
}
}
https://leetcode.com/problems/decode-string/
const decodeString = function (str) {
let stack = [];
let currStr = "";
let currNum = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === "[") {
stack.push(currStr);
stack.push(currNum);
currStr = "";
currNum = 0;
} else if (str[i] === "]") {
let prevNum = stack.pop();
let prevStr = stack.pop();
currStr = prevStr + currStr.repeat(prevNum);
} else if (str[i] >= "0" && str[i] <= "9") {
currNum = currNum * 10 + Number(str[i]);
} else {
currStr += str[i];
}
}
return currStr;
};
时间 O(N) 空间 O(N)
使用栈思想 保存number
class Solution {
public:
string decodeString(string s) {
// 存放[之前的内容字符串内容
stack<string> chars;
//存放[之前的数字内容
stack<int> numbers;
string res = "";
int num = 0;
for (char one : s) {
if (isdigit(one)) {
num = num * 10 + one - '0';
} else if (isalpha(one)) {
res.push_back(one);
} else if (one == '['){
numbers.push(num);
num = 0;
chars.push(res);
res = "";
} else if (one == ']') {
string tmp = res;
for (int i = 0; i < numbers.top() - 1; ++i) {
res += tmp;
}
// 这里需要注意顺序
res = chars.top() + res;
chars.pop();numbers.pop();
}
}
return res;
}
};
时间复杂度 O(n) 只需要遍历一遍 空间复杂度 O(n) 保存numbers 或者字符串
按照官方题解思路
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for c in s:
if c == ']':
repeatStr = ''
repeatCount = ''
while stack and stack[-1] != '[':
repeatStr = stack.pop() + repeatStr
# pop 掉 "["
stack.pop()
while stack and stack[-1].isnumeric():
repeatCount = stack.pop() + repeatCount
stack.append(repeatStr * int(repeatCount))
else:
stack.append(c)
return "".join(stack)
复杂度
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for i in range(len(s)):
if s[i] == "]":
letters = ''
count = ''
while stack and stack[-1] != "[":
letters = stack.pop() + letters
stack.pop()
while stack and stack[-1].isnumeric():
count = stack.pop() + count
stack.append(int(count) * letters)
else:
stack.append(s[i])
return ''.join(stack)
Time and Space: O(n) where n is the length of s
从前往后遍历字符串,依次推入栈中,直到遇到 ]
,就开始解析栈内的字符,直到遇到 [
,就代表字符解析完成了,前方可能有数字或字母,直到遇到非数字,将之前得到数字*字符,得到解析后的字符,推入栈中,继续如此循环
/**
* @param {string} s
* @return {string}
*/
function decodeString(s) {
let stack = [];
for (const i of s) {
// 只要值不等于 "]" ,就只做入栈操作
if (i !== "]") {
stack.push(i);
continue;
}
// 出现 "]" 了,那么他上一个元素必然为字母,那么在遇到 "[" 之前都只做拼接字符串的操作
let str = "";
// 从栈中拿出一个
let value = stack.pop();
while (value !== "[") {
str = value + str;
// 拼接完后在拉一个出来
value = stack.pop();
}
// 匹配到 "[" ,所以跳出了上一个循环,我们在拉一个覆盖掉 "["
value = stack.pop();
//出现 "[" 了,那么他前面的元素肯定是数字或者字母,是数字的话我们就要再次拼接
let num = "";
while (!isNaN(value)) {
num = value + num;
// 继续出栈
value = stack.pop();
}
// 出现新的字母了,上面把它出栈了,现在重新把它装回去,等待再次拼装
stack.push(value);
// 将处理拼接后的字符推入栈中,继续循环
stack.push(str.repeat(num));
}
return stack.join("");
}
复杂度分析
''' 1.所有可能的输入有 -,'[',']',数字,字母 2.做一个s的for循环,当发现是数字时,如果超过一位数,那么就会被乘以10 3.如果是一个字符,就会被添加金curString 4.如果遇到了'[',这是一个新的子串的开始,前面的子串都已经被处理了,所以将当前的curString和curNum附加到栈中, 并且将curString设为空,curNum设为0 5.当遇到']',到达了子串完整的地方,就是开始计算了 '''
class Solution:
def decodeString(self, s: str) -> str:
stack,curNum,curString = [],0,''
for i in s:
if i == '[':
stack.append(curString)
stack.append(curNum)
curString = ''
curNum = 0
elif i == ']':
num = stack.pop()
prevString = stack.pop()
curString = prevString + num*curString
elif i.isdigit():
curNum = curNum*10 + int(i)
else:
curString += i
return curString
目前写出的方法有点耗时,明天优化下, 1、采用递归的方式,每次只解码一个【】内的内容。
class Solution {
public:
string decodeString(string s) {
if (s.empty()) return s;
int idx_left_new = -1;
int idx_left_old = -1;
int idx_right = -1;
string num;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '[') {
idx_left_old = idx_left_new;
idx_left_new = i;
}
if (s[i] == ']') {
idx_right = i;
break;
}
}
int start;
if (idx_left_old == -1) {
for (int i = 0; i < idx_left_new; i++) {
if (s[i] >= '0' && s[i] <= '9') {
start = i; break;
}
}
} else {
for (int i = idx_left_old + 1; i < idx_left_new; i++) {
if (s[i] >= '0' && s[i] <= '9') {
start = i; break;
}
}
}
num = s.substr(start, idx_right - start);
if (idx_left_new <= 0 || idx_right == -1) return s;
if (idx_right - idx_left_new == 1) return s;
string tmp;
for (int i = 0; i < atoi(num.c_str()); i++) {
tmp += s.substr(idx_left_new + 1, idx_right - idx_left_new - 1);
}
string tmp_s;
if (idx_right != s.length() - 1) {
tmp_s = start == 0? tmp + s.substr(idx_right + 1) :
s.substr(0, start) + tmp + s.substr(idx_right + 1);
} else {
tmp_s = start == 0? tmp: s.substr(0, start) + tmp;
}
return decodeString(tmp_s);
}
};
时间复杂度:O(n*k),n表示字符串的长度, k表示'['的个数。
1、用栈的方法解决,只需遍历一次就够了
class Solution {
public:
string decodeString(string s) {
if (s.empty()) return s;
stack<int> numstack;
stack<string> strstack;
string cur = "";
int num = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] >= '0' && s[i] <= '9') {
num = 10 * num + s[i] - '0';
} else if (s[i] == '[') {
numstack.push(num);
num = 0;
strstack.push(cur);
cur.clear();
} else if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) {
cur += s[i];
} else if (s[i] == ']') {
int count = numstack.top();
numstack.pop();
for (int i = 0; i < count; i++) {
strstack.top() += cur;
}
cur = strstack.top();
strstack.pop();
}
}
return cur;
}
};
CPP
class Solution {
public:
string decodeString(string s) {
string res;
for (int i = 0; i < s.size();) {
if (!isdigit(s[i])) res += s[i ++ ];
else {
int j = i;
while (isdigit(s[j])) j++ ;
int t = atoi(s.substr(i, j - i).c_str());
int k = j + 1, sum = 0;
while (sum >= 0) {
if (s[k] == '[') sum ++ ;
if (s[k] == ']') sum -- ;
k ++ ;
}
string str = decodeString(s.substr(j + 1, k - j - 2));
while (t--) res += str;
i = k;
}
}
return res;
}
};
class Solution {
public String decodeString(String s) {
char[] chars = s.toCharArray();
Deque
遍历字符串,对不同情况做出相应操作
1、字符为数字,计算倍数
2、字符为字母,直接加到res
中
3、字符为左括号( '[' )
,进行递归,递归的返回值为当前已遍历到的索引 i
和子字符串tmp
拿到返回值后将tmp
乘以num
后加到res
中,并重置num
4、字符为右括号(']')
,返回当前索引 i
以及在当前递归层的循环过程中生成的子字符串res
5、返回最终字符串res
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)
思路:遇到字符匹配的事情,第一反应就是 用栈 来处理了。本题的关键在于“[” “]”, 这俩是判断入栈 还是 出栈 的关键。 时间复杂度: O(n) 空间复杂度:O(n) (其实用不到这么多空间,O(n) 算是最差的情况了)
def decodeString(self, s: str) -> str:
bracket_stack = []
digit_stack = []
res = ''
n = ''
for e in s:
if e.isdigit():
n+=e
elif e == '[':
bracket_stack.append(res)
digit_stack.append(n)
n = ''
res = ''
elif e == ']':
res = (bracket_stack.pop() + res*int(digit_stack.pop()))
else:
res += e
return res
class Solution {
public:
string decodeString(string s) {
string res;
stack<pair<int, string>> stk;
int count = 0;
for(auto c : s){
if(isdigit(c)){
count = count*10 + (c-'0');
}
else if(c == '['){
stk.push({count,res});
count = 0;
res = "";
}
else if(c == ']'){
auto p = stk.top();
stk.pop();
string tmp = res;
for(int i = 1; i < p.first; i++){
res += tmp;
}
res = p.second + res;
}
else{
res += c;
}
}
return res;
}
};
class Solution:
def decodeString(self, s: str) -> str:
ans = []
for ch in s:
if ch == ']':
cur_stack = []
while ans[-1] != '[':
cur_stack.append(ans.pop())
ans.pop()
order = 1
count = 0
while ans and ans[-1].isnumeric():
count += (int(ans.pop()) * order)
order *= 10
for _ in range(count):
ans.extend(cur_stack[::-1])
else:
ans.append(ch)
return ''.join(ans)
时间:O(N)
空间:O(N)
注意分析遇到数字, 字母,'[', ']' 不同情况时如何处理。因为题目规定好,不会出现3[4],3a 这种情况,可以假定int[alphabet] 这样的顺序。
注意两个字符串, 一个是之前已经处理完毕,需要和现在的正在处理的字符串相加
class Solution:
def decodeString(self, s: str) -> str:
cur_string,times = '',0
stack = []
for char in s:
if char.isdigit():
times = times*10+int(char)
# 因为可能是多位数
elif char == '[':
stack.append(cur_string)
stack.append(times)
times,cur_string = 0,''
elif char == ']':
pre_times = stack.pop()
pre_string = stack.pop()
cur_string = pre_string + pre_times * cur_string
else:
cur_string += char
return cur_string
time complexity: O(N) space complexity: O(N)
class Solution {
public:
string decodeString(string s) {
if(s.length() < 4)
return s;
stack<char> stk;
for(char ch : s){
if(ch != ']')
stk.push(ch); // 除']'外,所有都入栈
else{
// 1. 取出[]内的字符串
string str;
while( !stk.empty() && isalpha(stk.top()) ){
str.insert(0, 1, stk.top());
stk.pop();
}
stk.pop(); // pop '['
// 2. 得到倍数数字
string num;
while( !stk.empty() && isdigit(stk.top()) ){
num.insert(0, 1, stk.top());
stk.pop();
}
int count = stoi(num);
// 3. 根据倍数把字母再push回去
while( count > 0 ){
for( char chr : str){
stk.push(chr);
}
count--;
}
}
}
// 取出栈里的所有char
string ans;
while( !stk.empty() ){
ans.insert(0, 1, stk.top());
stk.pop();
}
return ans;
}
};
用栈接入字符串,遍历字符串,当匹配到字母和'['的时候就入栈保存,当匹配到']'的时候则保存当前的结果,最后得出结果
const isNumber = (str: string) => /\d/.test(str);
const isLetter = (str: string) => /[a-z]/.test(str);
function decodeString(str: string): string {
if (str.length === 0) return "";
const stack = [];
const len = str.length;
let index = 0;
let repeatStr = "";
while (index < len) {
if (isLetter(str[index]) || str[index] === "[") {
stack.push(str[index]);
} else if (isNumber(str[index])) {
if (isNumber(stack[stack.length - 1])) {
stack[stack.length - 1] += str[index];
} else {
stack.push(str[index]);
}
} else if (str[index] === "]") {
let prevValue = stack.pop();
while (prevValue !== "[") {
repeatStr = prevValue + repeatStr;
prevValue = stack.pop();
}
if (isNumber(stack[stack.length - 1])) {
stack[stack.length - 1] = repeatStr.repeat(stack[stack.length - 1]);
} else {
stack.push(repeatStr);
}
repeatStr = "";
}
index++;
}
return stack.join("");
}
时间复杂度: O(n) 空间复杂度: O(n)
class Solution: def decodeString(self, s: str) -> str: stack = [] cur_num = 0 cur_str="" for c in s: if c.isdigit(): cur_num = cur_num10+int(c) elif c is "[": stack.append(cur_str) stack.append(cur_num) cur_str = '' cur_num = 0 elif c is "]": temp_num = stack.pop() temp_str = stack.pop() cur_str = temp_str + temp_num cur_str else: cur_str+=c return cur_str
思路:使用栈将带有数字的转为为字符串
`string decodeString(string s) {
int n = s.size();
vector
for (int i = 0; i<n; i++)
{
char c = s[i];
if (c == ']')
{
vector<string> subStr;
while (stk.back() != "[")
{
subStr.push_back(stk.back());
stk.pop_back();
}
stk.pop_back();
string strNum = "";
while (stk.size()>0&&stk.back()<="9"&&stk.back()>="0")
{
strNum = strNum+stk.back();
stk.pop_back();
}
reverse(strNum.begin(), strNum.end());
int k = stoi(strNum);
//stk.pop_back();
reverse(subStr.begin(), subStr.end());
string tmp = "";
for (int j = 0; j<subStr.size(); j++)
{
tmp += subStr.at(j);
}
string tmp1 = "";
while (k--)
{
tmp1 = tmp1 + tmp;
}
stk.push_back(tmp1);
}
else
{
stk.push_back(string(1,c));
}
}
string result = "";
for (int m = 0; m<stk.size(); m++)
{
result += stk.at(m);
}
return result;
}`
时间复杂度:O(n); 空间复杂度:O(n)
class Solution {
public String decodeString(String s) {
Stack<Character> stack = new Stack();
int repeatTimes = 0;
char[] sChars = s.toCharArray();
for (char sChar: sChars){
if (sChar == ']'){
char a = stack.pop();
List<Character> temp = new ArrayList();
while (a != '['){
temp.add(a);
a = stack.pop();
}
Collections.reverse(temp);
List<Character> times = new ArrayList();
char n = stack.pop();
while (n >= '0' && n <='9'){
times.add(n);
if (stack.isEmpty()){
break;
}
n = stack.pop();
}
if (!(n >= '0' && n <= '9')){
stack.push(n);
}
Collections.reverse(times);
for (char ch: times){
repeatTimes = repeatTimes * 10 + ch - '0';
}
for (int i = 0; i < repeatTimes; i++){
for (char ch: temp){
stack.push(ch);
}
}
repeatTimes = 0;
}else {
stack.push(sChar);
}
}
StringBuilder ans = new StringBuilder();
for (char ch: stack){
ans.append(ch);
}
return ans.toString();
}
}
写复杂了,但是打卡时间过了,直接交 O(N) O(N)
没注意到第2个 testcase 有嵌套,只考虑了没有嵌套的情况 \ 用 res, curString, curMultiplier 分别记录遍历到 s[i] 时的 最后结果,当前substring,以及当前substring需要重复的次数 \ 逢 '[' 记录multiplier \ 逢 ']' 将 curString 乘以倍数后append到 res,重置 curString, curMultiplier \
class Solution {
public String decodeString(String s) {
if ("".equals(s)) {
return "";
}
StringBuilder res = new StringBuilder("");
StringBuilder curString = new StringBuilder("");
StringBuilder curMultiplier = new StringBuilder("0");
boolean isNumber = true;
int multiplier = 0;
for (int i = 0; i < s.length(); i++) {
char curChar = s.charAt(i);
//System.out.println("isNumber: " + isNumber);
if (curChar == '[') {
multiplier = Integer.parseInt(curMultiplier.toString());
// curMultiplier = new StringBuilder("0");
//System.out.println("multiplier: " + curMultiplier + ", " + multiplier);
isNumber = false;
continue;
}
if (curChar == ']') {
res.append(multiplyString(multiplier, curString.toString()));
isNumber = true;
//System.out.println("curString: " + curString.toString());
curMultiplier = new StringBuilder("0");
curString = new StringBuilder("");
continue;
}
if (isNumber) {
curMultiplier.append(curChar);
//System.out.println("multiplier in isNumber: " + curMultiplier);
continue;
} else {
curString.append(curChar);
continue;
}
}
return res.toString();
}
private String multiplyString(int num, String s) {
StringBuilder res = new StringBuilder("");
for (int i = 1; i <= num; i++) {
res.append(s);
}
return res.toString();
}
}
时间: O(n) \ 空间: O(n)
代码
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)
由括号匹配问题联想到此题亦可以使用栈来解决,主要思路为
]
字符进栈]
字符开始出栈
[
字符public class CustomStack {
private Stack<Integer> originStack = new Stack<>();
private int[] incrementArr;
private int maxSize;
public CustomStack(int maxSize) {
this.maxSize = maxSize;
incrementArr = new int[maxSize];
}
public void push(int x) {
if (originStack.size() >= maxSize) {
return;
}
originStack.push(x);
// 新元素入栈,清空之前增量数组中的缓存值
incrementArr[originStack.size() - 1] = 0;
}
public int pop() {
if (originStack.isEmpty()) {
return -1;
}
int index = originStack.size() - 1;
int origin = originStack.pop();
if (index > 0) {
incrementArr[index - 1] = incrementArr[index - 1] + incrementArr[index];
}
return origin + incrementArr[index];
}
public void increment(int k, int val) {
if (k <= 0 || originStack.isEmpty()) {
return;
}
int index = Math.min(originStack.size(), k) - 1;
incrementArr[index] += val;
}
public int pop1() {
if (originStack.empty()) {
return -1;
}
int index = originStack.size() - 1;
int origin = originStack.pop();
// pop时,需要pop栈顶 + 增量数组当前值
return origin + incrementArr[index];
}
public void increment1(int k, int val) {
if (k <= 0) {
return;
}
int capacity = Math.min(originStack.size(), k);
for (int i = 0; i < capacity; i++) {
incrementArr[i] += val;
}
}
}
时间复杂度为O(N) 只遍历了一遍字符串,所以时间复杂度为O(N)
字符'['
作为入栈标志,字符']'
作为出栈标志。每次出栈时拼接当前k[encoded_string]
与上一个包含该k[encoded_string]
的k[encoded_string]
的剩余部分,可假设最开始的字符串s
由一个[]
包裹,且已经完成入栈操作。即由最内层[]
向外进行解码。
关键点:
res, multi = '', 0
。res = last_res + res * cur_multi
# https://leetcode-cn.com/problems/decode-string/solution/decode-string-fu-zhu-zhan-fa-di-gui-fa-by-jyd/
class Solution:
def decodeString(self, s: str) -> str:
stack, res, multi = [], '', 0
for c in s:
if c == '[':
stack.append([multi, res])
res, multi = '', 0
elif c == ']':
cur_multi, last_res = stack.pop()
res = last_res + res * cur_multi
elif '0' <= c <= '9':
multi = multi * 10 + int(c)
else:
res += c
return res
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
let stack = [];const reg = /[a-zA-Z]+|[0-9]+|\[|\]/g;;
while(reg.lastIndex < s.length) {
let count = reg.exec(s)[0]
if (count !== ']') {
stack.push(count)
} else {
let cha = stack.pop(), str = '';
while(cha !== '[') {
str = cha + str
cha = stack.pop()
}
stack.push(str.repeat(+stack.pop()))
console.log(stack)
}
}
return stack.join('')
};
class Solution {
public String decodeString(String s) {
Deque<Integer> numstack = new LinkedList<>();
Deque<String> sstack = new LinkedList<>();
StringBuilder res = new StringBuilder("");//结果
int mult = 0;//倍数
for(Character ch : s.toCharArray()){
if(ch == '['){
numstack.addLast(mult);
sstack.addLast(res.toString());
mult = 0;
res = new StringBuilder("");
}else if(ch == ']'){
int cur_mult = numstack.removeLast();
StringBuilder tempsb = new StringBuilder("");
for(int i=0;i<cur_mult;i++){
tempsb.append(res.toString());
}
res = new StringBuilder(sstack.removeLast() +tempsb.toString() );
}else if(ch >= '0' && ch <= '9'){
mult = mult * 10 + Integer.parseInt(ch + "");
}else{
res.append(ch);
}
}
return res.toString();
}
}
时间复杂度:遍历一次,O(n)
空间复杂度:应该也是O(n) 自己独立做不出。。要加油啊
class Solution {
private:
string src;
int ptr;
int getDigits(){
int ret = 0;
while(ptr < src.size() && isdigit(src[ptr])){
ret = ret * 10 + src[ptr++] - '0';
}
return ret;
}
string getString() {
if (ptr == src.size() || src[ptr] == ']'){
return "";
}
char cur = src[ptr];
int cnt = 1;
string res;
if (isdigit(cur)) {
cnt = getDigits();
++ptr;
string str = getString();
++ptr;
while(cnt--){
res += str;
}
} else if (isalpha(cur)){
res = string(1, src[ptr++]);
}
return res + getString();
}
public:
string decodeString(string s) {
src = s;
ptr = 0;
return getString();
}
};
使用两个栈一个存放数字,一个存放字符串
class Solution {
public String decodeString(String s) {
Stack<Integer> intStack = new Stack();
Stack<StringBuilder> strStack = new Stack();
StringBuilder pattern = new StringBuilder();
int number = 0;
for (char ch : s.toCharArray()) {
if (Character.isDigit(ch)) {
number = number * 10 + ch - '0';
} else if (ch == '[') {
intStack.push(number);
strStack.push(pattern);
number = 0;
pattern = new StringBuilder();
} else if (ch == ']') {
StringBuilder temp = pattern;
pattern = strStack.pop();
for (int i = intStack.pop(); i > 0; i--) pattern.append(temp);
} else pattern.append(ch);
}
return pattern.toString();
}
}
思路
自己没有做出来,参考了题解,重点标记
代码
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for i in s:
if i == ']':
strs = ''
repeat = ''
while stack[-1] != '[':
strs = stack.pop() + strs
stack.pop()
while stack and stack[-1].isdigit():
repeat = stack.pop() + repeat
stack.append(int(repeat) * strs)
continue
stack.append(i)
return ''.join(stack)
复杂度
对字符串,数字, 左括号分别建立各自的栈, 遍历字符如各自的栈,字符为右括号时,每个栈分别弹出,计算重复字符串,若左括号栈不为空,得到的字符串继续入字符串栈,否则append到结果中。注意入栈时字符和字母的连续性,需要保留前一个字符做判断,判断是新入栈还是拼接到栈顶元素。同时建立辅助栈,记录数字前面一个字符,在字符串重复计算完后,判断是新入栈还是拼接到字符串栈的栈顶元素。
class Solution {
public String decodeString(String s) { StringBuilder sb = new StringBuilder();
char[] chs = s.toCharArray();
Stack<Character> bucks = new Stack();
Stack<Integer> nums = new Stack();
Stack<Character> numPres = new Stack();
Stack<String> letters = new Stack();
boolean isDigitBreak = false;
boolean isLetterBreak = false;
Character preChar = null;
for(int i = 0; i < chs.length; i ++){
char c = chs[i];
if(bucks.isEmpty() && Character.isLetter(c)){
sb.append(String.valueOf(c));
isDigitBreak = false;
isLetterBreak = true;
preChar = c;
}else if(Character.isDigit(c)){
int num = Integer.valueOf(String.valueOf(c));
if(preChar != null && Character.isDigit(preChar)){
int pre = nums.pop();
nums.push(pre*10+num);
}else{
nums.push(num);
numPres.push(preChar);
}
preChar = c;
}else if(Character.isLetter(c)){
String sc = String.valueOf(c);
if(preChar != null && Character.isLetter(preChar)){
String pre = letters.pop();
letters.push(pre+sc);
}else{
letters.push(sc);
}
preChar = c;
}else if(c == '['){
bucks.push(c);
preChar = c;
}else if(c == ']'){
bucks.pop();
int num = nums.pop();
Character numPre = numPres.pop();
String letter = letters.pop();
StringBuilder sbTemp = new StringBuilder();
while(num>0){
sbTemp.append(letter);
num--;
}
String temp = sbTemp.toString();
if(bucks.isEmpty()){
sb.append(temp);
}else{
if(numPre != null && (Character.isLetter(numPre))){
String pre = letters.pop();
letters.push(pre+temp);
}else{
letters.push(temp);
}
}
}
}
return sb.toString();
}
}
外层的解码需要等待内层解码的结果。
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
let numStack = []
let strStack = []
let num = 0
let result = ''
for (const char of s) {
if (!isNaN(char)) {
num = num * 10 + Number(char)
} else if (char === '[') {
strStack.push(result)
result = ''
numStack.push(num)
num = 0
} else if (char === ']') {
let repeatTime = numStack.pop()
result = strStack.pop() + result.repeat(repeatTime)
} else {
result += char
}
}
return result
};
时间复杂度 O(N),N 是解析后字符串的长度 空间复杂度 O(N)
难度中等
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: 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"
strs.top() += s[i]
#include <iostream>
using namespace std;
#include <bits/stdc++.h>
/*
迭代实现思路:
借助两个栈 stack <string> strs 和 stack <int> nums;
并且将结果保存到字符串 ans 里面
遍历 s:
1. 如果遇到数字则开始记录数字
2. 如果遇到字母则 strs.top() += s[i]
3. 如果遇到 [ 则将记录的数字入栈,将其后面的字符串入栈直到遇到不是字母的东西
4. 如果是 ‘ ] ' 则将栈顶的 nums.top( ) 倍的 strs.top( )加入到栈顶的后一个元素后面然后让其成为新的栈顶
*/
string decodeString(string s)
{
stack<int> nums;
stack<string> strs;
int multi = 0;
string res = "";
int i = 0;
strs.push(res);
while(i < s.length())
{
if (s[i] <= '9' && s[i] >= '0') //情况1
{
multi = 10 * multi + s[i] - '0';
i++;
}
if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) //情况2
{
string to_be_added = strs.top();
strs.pop();
to_be_added += s[i];
strs.push(to_be_added);
i++;
}
if (s[i] == '[')
{
nums.push(multi);
i++;
multi = 0;
string temp = ""; //清零很重要
while ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) //将 [ 后面的字符部分入栈,
{
temp += s[i];
++i;
}
strs.push(temp);
temp = "";//养成习惯,用来记录的变量用完后就清零(例如cnt,flag那些)
}
if(s[i] == ']')
{
string to_be_multiplied = strs.top();
strs.pop();
string to_be_added = strs.top();
strs.pop();
for (int i = 0; i < nums.top(); i++)
{
to_be_added += to_be_multiplied;
}
strs.push(to_be_added);//现在top就是相对来说最内层的了
nums.pop();
++i;//这里一开始漏
}
}
return strs.top();
}
//test drive
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
string input = "";
cin >> input;
cout << decodeString(input)<<endl;
return 0;
}
时间复杂度和空间复杂度均为 O( n )
class Solution:
def decodeString(self, s: str) -> str:
num_stack = []
num_val = 0
result = ""
for ele in s:
if ele.isdigit():
num_val = num_val * 10 + int(ele)
elif ele == "[":
num_stack.append([result, num_val])
result, num_val = "", 0
elif ele == "]":
top = num_stack.pop()
result = top[0] + result * top[1]
else:
result += ele
return result
class Solution {
public:
string getDigits(string &s, size_t &ptr) {
string ret = "";
while (isdigit(s[ptr])) {
ret.push_back(s[ptr++]);
}
return ret;
}
string getString(vector <string> &v) {
string ret;
for (const auto &s: v) {
ret += s;
}
return ret;
}
string decodeString(string s) {
vector <string> stk;
size_t ptr = 0;
while (ptr < s.size()) {
char cur = s[ptr];
if (isdigit(cur)) {
// 获取一个数字并进栈
string digits = getDigits(s, ptr);
stk.push_back(digits);
} else if (isalpha(cur) || cur == '[') {
// 获取一个字母并进栈
stk.push_back(string(1, s[ptr++]));
} else {
++ptr;
vector <string> sub;
while (stk.back() != "[") {
sub.push_back(stk.back());
stk.pop_back();
}
reverse(sub.begin(), sub.end());
// 左括号出栈
stk.pop_back();
// 此时栈顶为当前 sub 对应的字符串应该出现的次数
int repTime = stoi(stk.back());
stk.pop_back();
string t, o = getString(sub);
// 构造字符串
while (repTime--) t += o;
// 将构造好的字符串入栈
stk.push_back(t);
}
}
return getString(stk);
}
};
两个栈解法 一个栈放倍数,一个栈放字母
var decodeString = function(s) {
let numStack = []; // 存倍数的栈
let strStack = []; // 存 待拼接的str 的栈
let num = 0; // 倍数中转站
let result = ''; // 字符串中转站
for(const char of s){
if(!isNaN(char)){ // 遇到数字
num = num * 10 + (+char); // 计算倍数
}else if(char === '['){ // 遇到 [
strStack.push(result); // result字符串入栈
result = ''; // 入栈后清零
numStack.push(num); // 倍数num入栈
num = 0; // 倍数入栈后清零
}else if(char === ']'){ // 遇到 ],两个栈顶出栈
let repeatTimes = numStack.pop(); // 获取倍数
result = strStack.pop() + result.repeat(repeatTimes); // 构建子串
}else{
result += char; // 遇到字母,拼接给result串
}
}
return result;
};
开括号前面的为数字,闭括号前面的为字符,遇到开括号前面可能大于个位数,用10*拼接
/**
* @param {string} s
* @return {string}
*/
var decodeString = function (s) {
let numStack = [];
let strStack = [];
let num = 0;
let result = "";
for (let char of s) {
if (!isNaN(char)) {
num = num * 10 + Number(char);
} else if (char === "[") {
numStack.push(num);
num = 0;
strStack.push(result);
result = "";
}else if(char ==="]"){
let repeatNum = numStack.pop();
result = strStack.pop() + result.repeat(repeatNum);
}else{
result += char;
}
}
return result;
};
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"