Open azl397985856 opened 1 year ago
利用栈 后入先出的思想
class Solution:
def decodeString(self, s: str) -> str:
stack = []
res = ""
multi = 0
for item in s:
if item == '[':
stack.append([res, multi])
res = ""
multi = 0
elif item == ']':
last_res, cur_multi = stack.pop()
res = last_res + cur_multi * res
elif '0' <=item <= '9':
multi = multi * 10 + int(item)
else:
res += item
return res
-时间复杂度 O(n) n是数组s的长度 -空间复杂度 O(n)
''' class Solution: def decodeString(self, s: str) -> str: ans = '' stack = [] cur_num = 0
for i in range(len(s)):
if s[i].isdigit():
cur_num = cur_num*10 + int(s[i])
elif s[i] == '[':
stack.append((ans,cur_num))
ans = ''
cur_num = 0
elif s[i] == ']':
cur_str, n = stack.pop()
ans = cur_str + ans *n
else:
ans += s[i]
return ans
''' O(N)
class Solution {
public String decodeString(String s) {
int N = s.length();
Stack<String> stack = new Stack<>();
for(int i = 0 ; i < N ; i ++){
String repeatStr = "";
String num = "";
String newString = "";
String cur = s.substring(i , i + 1);
if(!cur.equals("]") ){
stack.push(s.substring(i , i+1));
}else{
while(!stack.isEmpty() && !stack.peek().equals("[")){
repeatStr = stack.pop() + repeatStr;
}
stack.pop();// pop :[
while(!stack.isEmpty() && stack.peek().matches("[0-9]")){
num = stack.pop() + num;
}
for(int j = 0 ; j < Integer.valueOf(num) ; j++){
newString += repeatStr;
}
//把新字符串压回栈中
for(int j = 0 ; j < newString.length() ; j++){
stack.push(newString.substring(j , j + 1));
}
}
}
String res = "";
while(!stack.isEmpty()){
res = stack.pop() + res;
}
return res;
}
}
time O(n)
space O(n)
from collections import deque
class Solution:
def decodeString(self, s: str) -> str:
stack = deque()
k = ""
for i in range(len(s)-1, -1, -1):
if s[i] in "0123456789":
k += s[i]
else:
if k != "":
n = int(k[::-1])
temp = []
# pop until ] or end
while stack:
c = stack.popleft()
if c == "]":
break
else:
if c != "[":
temp.append(c)
# repeate k time
for _ in range(n):
# push back
for c in temp[::-1]:
stack.appendleft(c)
# clear k
k = ""
stack.appendleft(s[i])
if k != "":
# repeate
n = int(k[::-1])
temp = []
# pop until ] or end
while stack:
c = stack.popleft()
if c == "]":
break
else:
if c != "[":
temp.append(c)
# repeate k time
for _ in range(n):
# push back
for c in temp[::-1]:
stack.appendleft(c)
return "".join(stack)
time O(len(string)) space O(len(string)
/**
TC: O(n), SC: O(n)
*/
// Method 1: iterative
class Solution1 {
public String decodeString(String s) {
int multi = 0;
StringBuilder sb = new StringBuilder();
Deque<Integer> multi_stack = new ArrayDeque<>();
Deque<String> chars_stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c >= '0' && c <= '9') { // 1. 倍数
multi = multi * 10 + (c - '0');
} else if (c >= 'a' && c <= 'z') { // 2. 字符
sb.append(c);
} else if (c == '[') { // 3. 入栈
multi_stack.addLast(multi); // 接下来[sb]要重复的次数
chars_stack.addLast(sb.toString()); // 之前的sb
multi = 0; // 重置临时变量
sb = new StringBuilder();
} else { // if (c == ']') // 4. 出栈
StringBuilder tmp = new StringBuilder();
int cur_multi = multi_stack.pollLast();
for (int i = 0; i < cur_multi; i++)
tmp.append(sb); // sb * multi次
sb = new StringBuilder(chars_stack.pollLast() + tmp); // 把之前的和这一次的连起来
}
}
return sb.toString();
}
}
// Method 2: recursive
// 先解析数字 x, 解析到了左括号 [,递归向下解析后面的内容,遇到对应的右括号就返回 ]
// [] 解析结束后, 再继续 解析] 右边的内容
class Solution {
int i = 0;
public String decodeString(String s) {
int count = 0;
StringBuilder sb = new StringBuilder();
while (i < s.length()) {
char c = s.charAt(i);
i++;
if (Character.isLetter(c)) {
sb.append(c);
} else if (Character.isDigit(c)) {
count = count * 10 + (c - '0');
} else if (c == ']') {
break;
} else if (c == '[') {
String repeat = decodeString(s);
while (count > 0) {
sb.append(repeat);
count--;
}
}
}
return sb.toString();
}
}
class Solution(object):
def decodeString(self, s):
# 两个栈,一个进数字,一个进字母,反括号出栈
stack = [];curNum=0;curString=''
for c in s:
if c == '[':
stack.append(curString)
stack.append(curNum)
curString = ''
curNum = 0
elif c == ']':
num = stack.pop()
prevString = stack.pop()
curString = prevString + num*curString
elif c.isdigit():
curNum = curNum*10 + int(c)
else:
curString += c
return curString
将每个字符入栈 ,当遇到 ']'
时出栈,直至遇到 '['
,'['
前的所有数字出栈,即为 k
,将出栈得到的括号内所有字符重复 k
次,入栈。
class Solution:
def decodeString(self, s: str) -> str:
stack = []
res = ""
for i in s:
if i == "]":
tmp = stack.pop()
ch = ""
while tmp != "[": # "[" 之后的字符为当前要处理的子串
ch = tmp + ch
tmp = stack.pop()
time = 0
c = 0 # 进位,因为数字取值为 [1, 300],需要考虑 10 以上的重复情况
while stack and stack[-1].isdigit(): # "[" 之前的数字为当前子串要重复的次数
t1 = stack.pop()
time += int(t1) * 10 ** c
c += 1
ch = ch * time
stack.append(ch) # 处理完的子串入栈
else:
stack. append (i)
if stack:
res = "".join(i for i in stack)
return res
class Solution {
int ptr;
public String decodeString(String s) {
LinkedList<String> stk = new LinkedList<String>();
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<String>();
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();
}
}
如果不是']',就把当前字符放入 stack 中,否则就把从 stack pop 出 string 和 repeat time,最后再把结果放在栈里面
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for char in s:
if char != "]":
stack.append(char)
else:
temp = ""
count = ""
while len(stack) != 0 and stack[-1] != "[":
temp = stack.pop() + temp
stack.pop()
while len(stack) != 0 and stack[-1].isdigit():
count = stack.pop() + count
stack.append(temp * int(count))
return "".join(stack)
time O(N)
space O(N)
# ###思想:想法是栈,如果每次一个新的[,就入栈之前的字符串,当遇到],便进行计算
###代码:
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
循环字符串s 非 "]" 默认全部入栈 遇到"]"时 维护strs和repeat两个空字符串 先while循环获取所有字符串,条件为stack[-1] != 'a strs = stack.pop() + strs 执行一次stack.pop() 删掉“[” 再次while循环,条件为栈存在且栈顶为数字类型的字符串(“3[a]”场景,必须判断栈不为空) repeat = stack.pop() + repeat 现在栈中压入int(repeat) * strs即可
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)
双O(N)
字符串解码
输入:s = "3[a]2[bc]"
输出:"aaabcbc"
括号内嵌套括号,需要从内向外生成与拼接字符串,和栈先入后出的特性对应。
class Solution
{
public:
string decodeString(string s)
{
vector<string> strstk;
vector<int> numstk;
int num = 0;
string str = "";
for (char c : s)
{
if (c >= '0' && c <= '9')
{
num *= 10;
num += (c - '0');
}
else if (c == '[')
{
numstk.push_back(num);
strstk.push_back(str);
num = 0;
str = "";
}
else if (c == ']')
{
int numtmp = numstk.back();
string strtmp = strstk.back();
numstk.pop_back();
strstk.pop_back();
for (int i = 0; i < numtmp; i++)
{
strtmp = strtmp + str;
}
str = strtmp;
}
else
{
str += c;
}
}
return str;
}
};
使用栈维护当前【】进出
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
let res = ""
let stack = [];
let multi = 0;
for(let i = 0; i < s.length;i++){
const item = s[i];
const isNum = !isNaN(Number(item));
const isLBrackets = item === "["
const isRBrackets = item === "]"
if(isNum){
multi = Number(`${multi}${item}`);
}else if(isLBrackets){
stack.push([multi,res])
res = "";
multi = 0
}else if(isRBrackets){
const stackItem = stack.pop();
res = stackItem[1] + res.repeat(stackItem[0])
}else{
res += item
}
}
return res
};
function decodeString(s: string): string {
let res = ''
let count = 0
let stack: [string, number][] = []
const sArr = s.split('')
for (const c of sArr) {
if (c === '[') {
stack.push([res, count])
count = 0
res = ''
} else if (c === ']') {
const ans = stack.pop()!
const chars = ans[0]
const times = ans[1]
let temp = ''
for (let i = 0; i < times; i++) {
temp += res
}
res = chars + temp
} else if (c <= '9' && c >= '0') {
count = count * 10 + parseInt(c)
} else {
res += c
}
}
return res
};
class Solution {
public:
string decodeString(string s) {
stack
int index = 0;
string curRes = "";
while(index < s.size())
{
if(s[index] >= '0' && s[index] <= '9')
{
int count = 0;
while(s[index] >= '0' && s[index] <= '9')
{
count = 10 * count + (s[index] - '0');
index++;
}
int_S.push(count);
}
else if(s[index] == '[')
{
string_S.push(curRes);
curRes = "";
index++;
}
else if(s[index] == ']')
{
string tempStr = string_S.top();
int repeatCount = int_S.top();
string_S.pop();
int_S.pop();
while(repeatCount > 0)
{
tempStr.append(curRes);
repeatCount--;
}
curRes = tempStr;
index++;
}
else
{
curRes += s[index];
index++;
}
}
return curRes;
}
};
code
class Solution {
public String decodeString(String s) {
Deque<Character> deque = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c != ']') deque.addFirst(c);
else {
StringBuilder sb = new StringBuilder();
while (!deque.isEmpty() && Character.isLetter(deque.getFirst()))
sb.insert(0, deque.removeFirst());
String sub = sb.toString();
deque.removeFirst(); // remove '['
sb = new StringBuilder();
while (!deque.isEmpty() && Character.isDigit(deque.getFirst()))
sb.insert(0, deque.removeFirst());
int count = Integer.parseInt(sb.toString());
for (char ch : sub.repeat(count).toCharArray())
deque.addFirst(ch);
}
}
StringBuilder sb = new StringBuilder();
while (!deque.isEmpty())
sb.append(deque.removeLast());
return sb.toString();
}
}
num
栈记录重复次数 ; str
栈记录要重复的字符 ; n
为当前数字, ans
为解码后的字符
c >= '0' && c <= '9'
时 , 更新数字 n
c == 'a' && c <= 'z'
时, 更新 ans
c == '['
时, 为了保留当前信息, 处理[
后信息, 故将 num
压入当前数字, n
置为 0 ; str
压入当前字符, ans = ""
c == ']'
时, ans
已经为最近的[
和当前]
内的字符, 得到重复次数 t = num.top()
,
将当前字符按照 t
添加到外层字符 str.top()
后, 完成了部分解码, 更新 ans
, 将栈内元素弹出class Solution {
public:
string decodeString(string s) {
stack<int> num;
int n = 0;
stack<string> str;
string ans = "";
for (char c : s) {
if (c >= '0' && c <= '9') {
n = n * 10 + c - '0';
} else if (c == '[') {
num.push(n);
n = 0;
str.push(ans);
ans = "";
} else if (c == ']') {
int t = num.top();
num.pop();
for (int i = 0; i < t; i++) {
str.top() += ans;
}
ans = str.top();
str.pop();
} else {
ans += c;
}
}
return ans;
}
};
复杂度分析
[
和]
时和思路 1 不同
c == '['
时, 递归处理后续字符, 得到返回值 sub
, 按次数添加sub
, n
置为0c == ']'
时, 说明此级别的 '[]'
内字符已处理完class Solution {
public:
string helper(stack<char> &stack) {
int n = 0;
string ret = "";
while (!stack.empty()) {
char c = stack.top();
stack.pop();
if (c >= '0' && c <= '9') {
n = n * 10 + c - '0';
} else if (c == '[') {
string sub = helper(stack);
for (int i = 0; i < n; i++) {
ret += sub;
}
n = 0;
} else if (c == ']'){
break;
} else {
ret += c;
}
}
return ret;
}
string decodeString(string s) {
stack<char> stack;
for (int i = s.size() - 1; i >= 0; i--)
stack.push(s[i]);
string ret = helper(stack);
return ret;
}
};
复杂度分析
思路
java 好像对双引号or单引号很敏感,单引号的时候做character比较会有error 代码
class Solution {
public String decodeString(String s) {
String str = "";
Stack<String> letter = new Stack<>();
Stack<Integer> nums = new Stack<>();
String num = "";
for(int i=0; i<s.length(); i++){
if(Character.isDigit(s.charAt(i))){
num= num + s.charAt(i);
System.out.println("[get num " + num);
}else if(s.charAt(i) == '['){
if(num.length()>0){
nums.push(Integer.parseInt(num));
System.out.println("[[nums push "+ Integer.parseInt(num));
num = "";
}
letter.push(" ");
}else if(s.charAt(i) == ']'){
String sub = "";
while(letter.peek() != " "){
sub = letter.pop() + sub;
}
letter.pop();
if(nums.size() >0){
letter.push(sub.repeat(nums.pop()));
System.out.println("repeat "+ sub);
}else{
letter.push(sub);
System.out.println("purer push "+ sub);
}
}else{
letter.push(String.valueOf(s.charAt(i)));
System.out.println("final else"+ s.charAt(i));
}
}
while(!letter.isEmpty()){
str= letter.pop() + str;
}
return str;
}
}
时间复杂度:O(N) 空间复杂度:O(N)
用stack存储,四个cases
class Solution:
def decodeString(self, s: str) -> str:
stack = []
current_string = ""
k = 0
for char in s:
if char == "[":
# Just finished parsing this k, save current string and k for when we pop
stack.append((current_string, k))
# Reset current_string and k for this new frame
current_string = ""
k = 0
elif char == "]":
# We have completed this frame, get the last current_string and k from when the frame
# opened, which is the k we need to duplicate the current current_string by
last_string, last_k = stack.pop(-1)
current_string = last_string + last_k * current_string
elif char.isdigit():
k = k * 10 + int(char)
else:
current_string += char
return current_string
当遇到左括号时,需要用栈保存前面的解码结果,即用到一个字符串栈,同时需要保存前面的次数,即用到一个数量栈;遇到右括号时,数量栈顶为当前字符串的重复次数。
class Solution {
public String decodeString(String s) {
Deque<String> cStack = new ArrayDeque<>();
Deque<Integer> numStack = new ArrayDeque<>();
int num = 0;
String ans = "";
for (char c : s.toCharArray()) {
if (Character.isDigit(c)) {
num = num * 10 + c - '0';
}
else if (Character.isLetter(c)) {
ans += c;
}
else if (c == '[') {
numStack.push(num);
num = 0;
cStack.push(ans);
ans = "";
}
else if (c == ']') {
int cnt = numStack.pop();
String str = cStack.pop();
for (int i = 1; i <= cnt; i++) {
str += ans;
}
ans = str;
}
}
return ans;
}
}
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();
}
}
Time: O(n) Space: O(n)
双栈,一个栈存放数字,一个栈存放字母
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for c in s:
if c == "]":
tmpstr = ""
numstr = ""
while stack and stack[-1] != "[":
char = stack.pop()
tmpstr = char + tmpstr
stack.pop()
while stack and stack[-1].isdigit():
num = stack.pop()
numstr = num + numstr
stack.append(int(numstr) * tmpstr)
else:
stack.append(c)
return "".join(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),递归会更新索引,因此实际上还是一次遍历 s; 空间复杂度 O(N),极端情况下递归深度将会达到线性级别。
使用栈,遍历字符串,将字符数字和‘【’入栈,直到碰到‘】’,开始出栈,将‘【’之前的字符出栈存在restr里面,然后将‘【’之后的数字出栈存在num中,然后将num倍的restr入栈,直到遍历结束
class Solution:
def decodeString(self, s: str) -> str:
stk = []
for x in s:
if x==']':
restr = ''
num = ''
while stk and stk[-1]!='[':
restr = stk.pop()+restr
stk.pop()
while stk and stk[-1].isnumeric():
num = stk.pop()+num
stk.extend(restr*int(num))
else:
stk.append(x)
return ''.join(stk)
class Solution:
def decodeString(self, s: str) -> str:
result = ''
string_stack = []
data = 0
for i in s:
if(i.isdigit()):
data = data*10 + int(i)
elif(i == '['):
string_stack.append([data, result])
result = ''
data = 0
elif(i.isalpha()):
result += i
elif(i == ']'):
result = string_stack[-1][1] + string_stack[-1][0] * result
string_stack.pop()
return result
/**
利用栈的思想解题
设置两个变量:1.res 最终结果字符串 2.num 用来计数当前字符需要重复多少次
构造两个栈:1.字符栈 strStack,表示需要重复的字符 2.数字栈,需要重复的次数
如果当前 str === 数字,推入数字栈
如果当前 str === [,strStack、numStack 入栈,num,res 清 0
如果当前 str === ],strStack、numStack 出栈,形成一次字符串
其他情况 把字符加到 res 中
*/
/**
* @param {string} s
* @return {string}
*/
var decodeString = function (s) {
let numStack = [],strStack = [],res = '',num = 0;
for (let str of s) {
if (!isNaN(str)) {
num = num * 10 + parseInt(str);
} else if (str === '[') {
strStack.push(res);
numStack.push(num);
res = '';
num = 0;
} else if (str === ']') {
res = strStack.pop() + res.repeat(numStack.pop());
} else {
res += str;
}
}
return res;
};
暂时没做出来,C++的string用得不是很习惯
class Solution {
public:
string decodeString(string s) {
string res_str;
string tmp_str;
stack <int> stk;
int i(0);
int n(0);
//int k(0), count(0);
while(i < s.length()){
if((s[i]-'0' >= 0) && (s[i]-'0' <= 9)) stk.push(s[i++]);
else if(s[i] == '[') {
stk.push(s[i++]);
n++;
}
else if(s[i] == ']') {
string tmp;
while(stk.top() != '['){
//tmp
string tmp3;
tmp3 += stk.top();
tmp.insert(0, tmp3);
stk.pop();
}
tmp_str.insert(0, tmp);
//cout << tmp_str << endl;
stk.pop();
n--;
int k(0), count(0);
while(!stk.empty() && (stk.top()-'0' >= 0) && (stk.top()-'0' <= 9)){
int tmpn = stk.top() -'0';
k += tmpn*pow(10,count++);
stk.pop();
}
string tmp2(tmp_str);
k--;
while(k){
tmp_str += tmp2;
k--;
}
if(!n) {
res_str.append(tmp_str);
tmp_str.clear();
}
++i;
}
else {
if (stk.empty()) res_str += s[i++];
else stk.push(s[i++]);
}
}
return res_str;
}
};
算法流程: 1、构建辅助栈 stack, 遍历字符串 s 中每个字符 c; 1.1当 c 为数字时,将数字字符转化为数字 multi,用于后续倍数计算; 1.2当 c 为字母时,在 res 尾部添加 c; 1.3当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置 1.3.1记录此 [ 前的临时结果 res 至栈,用于发现对应 ] 后的拼接操作; 1.3.2记录此 [ 前的倍数 multi 至栈,用于发现对应 ] 后,获取 multi × [...] 字符串。 1.3.3进入到新 [ 后,res 和 multi 重新记录。 1.4当 c 为 ] 时,stack 出栈,拼接字符串 res = last_res + cur_multi * res,其中: 1.4.1last_res是上个 [ 到当前 [ 的字符串,例如 "3[a2[c]]" 中的 a; 1.4.2cur_multi是当前 [ 到 ] 内字符串的重复倍数,例如 "3[a2[c]]" 中的 2。 2、返回字符串 res。
代码:java
class Solution {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList
复杂度分析: 时间复杂度 O(N) 空间复杂度 O(N)
利用栈的思想,数字、字母和中括号分开,数字、字母和左括号直接进,遇到右括号的时候出栈,然后一直到遇到左括号停止,反转一下就是我们的字母队列,再去栈里面找数字就是重复的次数,然后根据新的字符串再进栈,如此循环往复即可
class Solution {
int ptr;
public String decodeString(String s) {
LinkedList<String> stk = new LinkedList<String>();
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<String>();
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(n)
空间复杂度:O(n)
C++ Code:
class Solution {
public:
string decodeString(string s) {
vector<pair<string, string>>st;
string nowStr, nowNum;
for(int i = 0; i < s.size(); i++){
if(s[i] >= 'a' && s[i] <= 'z'){
nowStr += s[i];
}else if(s[i] >= '0' && s[i] <= '9'){
nowNum += s[i];
}else if(s[i] == '['){
st.push_back(make_pair(nowStr, nowNum));
nowStr.clear();
nowNum.clear();
}else{
string tmp;
for(int j = 0; j < atoi(st.back().second.c_str()); j++)
tmp += nowStr;
nowStr = st.back().first + tmp;
st.pop_back();
}
}
return nowStr;
}
};
复杂度分析
令 n 为数组长度。
循环 + 栈
/*
// @lc code=start /**
@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(''); };
时间复杂度:$O(S)$,S 是解析后字符串的长度。 空间复杂度:$O(S)$,S 是解析后字符串的长度。
递归,返回内部字符串 和 计算到了哪个位置;每次遇到[ 就进入下层,遇到 ] 就发返回;
class Solution {
public String decodeString(String s) {
char[] str = s.toCharArray();
return process(str, 0).res;
}
private Info process(char[] str, int index){
StringBuilder sb = new StringBuilder();
int count = 0;
while(index < str.length){
char c = str[index];
if(c >= '0' && c <= '9'){
count = count * 10 + (c - '0');
}else if(c == '['){
Info info = process(str, index + 1);
while(count > 0){
sb.append(info.res);
count--;
}
index = info.index;
}else if(c == ']'){
return new Info(sb.toString(), index);
}else {
sb.append(c);
}
index++;
}
return new Info(sb.toString(), index);
}
}
class Info{
String res;
Integer index;
Info(String res, Integer index){
this.res = res;
this.index = index;
}
}
O(n), O(1)
class Solution: def decodeString(self, s: str) -> str: stk = [] for x in s: if x==']': restr = '' num = '' while stk and stk[-1]!='[': restr = stk.pop()+restr stk.pop() while stk and stk[-1].isnumeric(): num = stk.pop()+num stk.extend(restr*int(num)) else: stk.append(x) return ''.join(stk)
最后写的脑袋晕晕沉沉,总算是ac了
维护两个stack,一个是数字栈,一个是字符串栈,遍历给定的字符串char c = s.charAt(i)
:
c 是数字
题目中数字没有限定是个位数,因此需要保留并计算
c == '['
此时记录数字完成,开始记录区间内的字符串,因此需要完成:
c 是字母
将字母append
到当前记录的字符串中
c == ']'
此时,小区间的字符串记录完成,需要进行解码操作:
""
)直到遍历完成
class Solution {
public String decodeString(String s) {
Stack<Integer> numStack = new Stack<>();
Stack<StringBuffer> stringStack = new Stack<>();
StringBuffer result = new StringBuffer();
int multi = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
multi = 10 * multi + c - '0';
} else if (c == '[') {
stringStack.push(result);
numStack.add(multi);
result = new StringBuffer();
multi = 0;
} else if (Character.isAlphabetic(c)) {
//记录当前小段的 string
result.append(c);
} else if (c == ']') {
// decode
StringBuffer temp = stringStack.pop();
multi = numStack.pop();
for (int j = 0; j < multi; j++) temp.append(result);
multi = 0;
result = temp;
}
}
return result.toString();
}
}
class Solution { public: string src; size_t 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] == ']') {
// String -> EPS
return "";
}
char cur = src[ptr]; int repTime = 1;
string ret;
if (isdigit(cur)) {
// String -> Digits [ String ] String
// 解析 Digits
repTime = getDigits();
// 过滤左括号
++ptr;
// 解析 String
string str = getString();
// 过滤右括号
++ptr;
// 构造字符串
while (repTime--) ret += str;
} else if (isalpha(cur)) {
// String -> Char String
// 解析 Char
ret = string(1, src[ptr++]);
}
return ret + getString();
}
string decodeString(string s) {
src = s;
ptr = 0;
return getString();
}
};
思路
利用一个数字栈与一个符号栈来处理,首先遍历整个字符串,如果当前的字符为数字,字母或者左括号,直接进栈,如果当前的字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,取出栈顶的数字,根据字符串构造出新的字符串并进栈
代码
class Solution { public: string decodeString(string s) { stack<int> st_num; //数字栈 string symbol; int num=0; for(int i=0;i<s.size();i++) { if(s[i]>='0'&&s[i]<='9'){ num=s[i]-'0'+num*10; }else if(s[i]=='['){ st_num.push(num); num=0; symbol+=s[i]; }else if(s[i]==']'){ int j=symbol.size()-1; string tmp_string; while(symbol[j]!='[') { tmp_string+=symbol[j]; symbol.pop_back(); j--; } symbol.pop_back(); int tmp_num=st_num.top(); st_num.pop(); reverse(tmp_string.begin(),tmp_string.end()); for(int k=0;k<tmp_num;k++) { symbol+=tmp_string; } }else{ symbol+=s[i]; } } return symbol; } };
遍历数组,
var decodeString = function(s) {
let stack = [];
let len = s.length;
let i = 0;
while(i < len) {
let char = s[i];
if (char === '[') {
stack.push('[');
i++;
}
else if (/[0-9]/.test(+s[i])) {
let strNum = s[i];
i++;
while(/[0-9]/.test(+s[i])) {
strNum += s[i];
i++;
}
stack.push(strNum)
}
else if (char === ']') {
let str = stack.pop();
let cur = stack.pop();
while(true) {
if (cur === '[') break;
str = cur + str;
cur = stack.pop();
}
const num = +stack.pop();
const strList = Array(num).fill().map(() => str).join('');
stack.push(strList);
i++;
}
else {
stack.push(s[i]);
i++;
}
}
return stack.join('');
};
栈的使用
JS的一些语法复习:
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
let m = "";
let stack = [];
let res = "";
for(let i=0;i<s.length;i++){
let asc = s[i].charCodeAt();
// 数字 更新m 直接拼接
if (asc>=48 && asc<=57){
m += s[i];
} else if(asc>=97 && asc<=122){
// 字母 更新res
res += s[i];
} else if(s[i]==='['){
// 入栈[res,m] 置空这两个
stack.push([res,+m]);
res = '';
m = '';
} else if(s[i]===']'){
// 出栈
let [beforeRes,multi] = stack.pop();
res = beforeRes+ res.repeat(multi);
}
}
return res;
};
空间:O(N) 时间:O(N)
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() };
}
}
class Solution {
public:
string decodeString(string s) {
string res = "";
int num = 0;
stack<int> nums;
stack<string> lesserStrs;
int len = s.size();
for(int i = 0;i < len;i++)
{
if(s[i] >= '0' && s[i] <= '9')
{
num = num * 10 + (s[i] - '0');
}
else if(s[i] >= 'a' && s[i] <= 'z')
{
res = res + s[i];
}
else if(s[i] == '[')
{
lesserStrs.push(res);
res = "";
nums.push(num);
num = 0;
}
else if(s[i] == ']')
{
int n = nums.top();
nums.pop();
for(int i = 0;i < n;i++)
{
lesserStrs.top() = lesserStrs.top() + res;
}
res = lesserStrs.top();
lesserStrs.pop();
}
}
return res;
}
};
};
复杂度分析
模拟栈,并且插入一个 #
号键作为标识符
func decodeString1(s string) string {
ans := []rune{}
i := true
for _, elem := range s {
if elem >= '0' && elem <= '9' && i {
ans = append(ans, '#', elem)
i = false
} else if elem == '[' {
i = true
ans = append(ans, elem)
} else if elem == ']' {
i = true
tmpStr := ""
amountStr := ""
flag := false
for len(ans) > 0 {
popElem := ans[len(ans)-1]
ans = ans[:len(ans)-1]
if popElem == '#' {
break
} else if popElem == '[' {
flag = true
} else if flag {
amountStr = string(popElem) + amountStr
} else {
tmpStr = string(popElem) + tmpStr
}
}
amount := 1
if amountStr != "" {
amount, _ = strconv.Atoi(amountStr)
}
str := ""
for index := 0; index < amount; index++ {
str += tmpStr
}
ans = append(ans, []rune(str)...)
} else {
ans = append(ans, elem)
}
}
return string(ans)
}
class Solution:
def decodeString(self, s: str) -> str:
stack, cstr, num = [], "", 0
for i in s:
if "0" <= i <= "9":
num = num*10 + int(i)
elif i == "[":
stack.append((cstr,num))
cstr, num = "", 0
elif i == ']':
_cstr,_num = stack.pop()
cstr = _cstr + cstr * _num
else:
cstr += i
return cstr
O(n)
O(n)
用栈实现
package issue9
import (
"strconv"
"strings"
)
func decodeString(s string) string {
ptr := 0
var stk []string
var getDigits func() string
getDigits = func() string {
// 获取数字
ret := ""
for ; s[ptr] >= '0' && s[ptr] <= '9' && ptr < len(s); ptr++ {
ret += string(s[ptr])
}
return ret
}
var getString func(v []string) string
getString = func(v []string) string {
return strings.Join(v, "")
}
for ptr < len(s) {
cur := s[ptr]
if cur >= '0' && cur <= '9' { // 获取数字
digits := getDigits()
stk = append(stk, digits)
} else if (cur >= 'a' && cur <= 'z' || cur >= 'A' && cur <= 'Z') || cur == '[' {
stk = append(stk, string(cur))
ptr++
} else { // 右花括号
var sub []string
for stk[len(stk)-1] != "[" {
sub = append(sub, stk[len(stk)-1])
stk = stk[:len(stk)-1] // 出栈
}
stk = stk[:len(stk)-1] // 将 "[" pop 出栈
// 逆序
for i := 0; i < len(sub)/2; i++ {
sub[i], sub[len(sub)-i-1] = sub[len(sub)-i-1], sub[i]
}
repTime, _ := strconv.Atoi(stk[len(stk)-1])
stk = stk[:len(stk)-1] // 将数字 pop 出栈
t := strings.Repeat(getString(sub), repTime)
stk = append(stk, t) // 重新入栈
ptr++
}
}
return getString(stk)
}
用栈实现类似计算器的操作
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';
}
else if((s[i] >= 'a' && s[i] <= 'z') ||(s[i] >= 'A' && s[i] <= 'Z'))
{
res = res + s[i];
}
else if(s[i] == '[')
{
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();
strs.pop();
}
}
return res;
}
};
时间复杂度:O(n) 空间复杂度:O(n)
通过栈实现。
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';
}
else if((s[i] >= 'a' && s[i] <= 'z') ||(s[i] >= 'A' && s[i] <= 'Z'))
{
res = res + s[i];
}
else if(s[i] == '[')
{
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();
strs.pop();
}
}
return res;
}
};
复杂度分析
利用两个栈,一个存当前字符,一个存当前数量,遍历字符串,遇到字母,加入当前字符,遇到数字字符,当前数字10加上当前数字字符,遇到‘[’,将当前字母和数字入栈,归0,遇到’]‘,将栈顶字母弹出,栈顶字母+栈顶数量当前字符串=累计字符串;然后继续。
class Solution {
public:
string decodeString(string s) {
int n=s.size();
stack<string> stackstr;
stack<int> stacknum;
string curstr="";
int curnum=0;
for(int i=0;i<n;i++){
if(s[i]>='0'&&s[i]<='9') curnum=curnum*10+(s[i]-'0');
if(s[i]>='a'&&s[i]<='z') curstr+=s[i];
if(s[i]=='['){
stackstr.push(curstr);
stacknum.push(curnum);
curstr="";
curnum=0;
}
if(s[i]==']'){
string temp=curstr;
for(int i=0;i<stacknum.top()-1;i++) curstr+=temp;
curstr=stackstr.top()+curstr;
stackstr.pop();
stacknum.pop();
}
}
return curstr;
}
};
复杂度分析
/**
* @param {string} s
* @return {string}
*/
var decodeString = function(s) {
let stack = []; // 定义存储字符串的栈
let str = ""; // 定义最终返回的字符串
let num = ""; // 定义字符串重复的次数
const length = s.length;
for (let i = length - 1; i >= 0; i--) {
console.log("s[i]", stack, i);
if (s[i] >= "0" && s[i] <= "9") {
// 解析出连续的数字
while (s[i] >= "0" && s[i] <= "9") {
num += s[i];
i--;
console.log("num", num);
}
stack.push(
str.repeat(
Number(
num
.split("")
.reverse()
.join("")
)
)
); // 拼接字符
str = "";
num = ""; //清空计数
i++;
} else if (s[i] === "[") {
// 遇到"["时,将后续字符出栈
let curStr = stack.pop();
while (curStr !== "]") {
str += curStr;
curStr = stack.pop(); // 拼接出栈的字符串 "["后跟着的一定是数字
}
} else {
// 将字符 或 "]"入栈
stack.push(s[i]);
}
}
return stack.reverse().join("");
};
class Solution {
public String decodeString(String s) {
//声明一个栈,存放数字
Stack<Integer> stackNum = new Stack<>();
//声明一个栈,存放字符
Stack<StringBuffer> stackStr = new Stack<>();
//记录数字
int num=0;
StringBuffer buff = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
if(Character.isDigit(s.charAt(i))){
num=num*10+s.charAt(i)-'0';
}else if(s.charAt(i)=='['){
//先将数字入栈
stackNum.push(num);
//把字符存起来
stackStr.push(buff);
//数字归0
num=0;
buff=new StringBuffer();
}else if(s.charAt(i)==']'){
//取出数字栈顶元素
Integer pop = stackNum.pop();
//取出栈顶的字符栈
StringBuffer str = stackStr.pop();
for (int j = 0; j < pop; j++) {
str.append(buff.toString());
}
buff=str;
}else{
buff.append(s.charAt(i));
}
}
return buff.toString();
}
}
把字符压到栈里,遇到 ] 出栈到 [ 组成字符,继续出栈到非数字,组成数字,拼接字符串,当作一个完整字符,压栈,继续遍历
var decodeString = function(s) {
const stack = [];
for (let i = 0; i < s.length; i++) {
if (s[i] !== ']') {
stack.push(s[i]);
continue;
}
let temStr = '';
while (stack[stack.length - 1] !== '[') {
temStr = stack.pop() + temStr;
}
stack.pop();
let numStr = '';
while (stack.length && isNumber(stack[stack.length - 1])) {
numStr = stack.pop() + numStr;
}
const res = temStr.repeat(Number(numStr));
stack.push(res);
}
return stack.join('')
};
const isNumber = (chr) => {
const num = Number(chr);
return num >=0 && num <=9;
}
时间复杂度:O(n), 空间复杂度:O(n)
模拟栈
class Solution {
int ptr;
public String decodeString(String s) {
LinkedList<String> stk = new LinkedList<String>();
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<String>();
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();
}
}
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"