技术是开源的,知识是共享的。
前言
数据结构与算法,是程序员的内功修炼。甚至有开发者还提出了程序=数据结构+算法
。
少侠我之前参加校招的时候,也是凭借在手撕代码环节出色的算法解题思路获得面试官的称赞并击败众多竞争者最后拿到字节跳动等大厂的offer。
为了保持算法心经的日臻纯熟,我暗下决心,决定开始写互联网数据结构与算法相关的文章,希望能帮助各位读者在以后的手撕代码中游刃有余,对面试官进行360°的反击,让一同面试的同僚瞠目结舌,疯狂收割互联网大厂offer!
文章中虽然应用了夸张的修辞手法,但我们应该始终保持一颗谦逊的心。希望和大家怀着虚怀若谷的心态,共同学习进步。
问题描述
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: (encoded_string)[k],表示其中括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的括号总是符合格式要求的。
示例 1:
输入:s = “(a) [3] (bc) [2]”
输出:“aaabcbc”
示例 2:
输入:s = “(a( c )[2]) [3]”
输出:“accaccacc”
问题分析
这道题目思路清晰直观,双层for循环依次遍历就行了,看见没,简单粗暴,一气呵成。好了,本篇到这里就要跟大家说再见了。
依次遍历,这个想法很直观,但是时间复杂度也很可观!是O(n2),我们在面试、开发中一定要尽可能的规避平方次的时间复杂度,很可怕,甚至容易导致服务器宕机。
那么有没有什么好的思路呢?当然有啦,且听我娓娓道来。
解决方案
思路
这道题其实思路并不难想,因为很容易知道要用栈来解决,但是细节处会有很多不少地方要去注意和深究,首先是栈的使用,很多人会用两个栈,一个数字栈,一个字符串栈,我这里的解法就只用一个栈,因为只用一个栈,所以不是字符栈,而是字符串栈stack
读到)时,用一个while循环将(和)之间的字符串读出,我这里用了StringBuffer来提高字符串拼接性能,读出后将(pop删去,然后开始读数字num了,注意数字可能是很多位数字,这里处理方法很多,我就直接用parseInt将字符串转化为数字了,然后是将上述字符串复制num倍,这样处理后再将字符串放回栈中即可,至于其他情况,直接将其转化为字符串压入栈中即可,最后出栈的时候要注意,字符串的总体顺序是反的,故要用insert拼接而不是append
代码
class Solution {
public String decodeString(String s) {
StringBuffer sb = new StringBuffer();
Stack<Character> stack = new Stack<>();
for (int i = 0; i != s.length(); i++) {
char c = s.charAt(i);
stack.push(c);
if (c == ']') {
char n;
String repeated = "";
stack.pop();
while ((n = stack.pop()) != '[') {
repeated = n + repeated;
}
int repeatedNum = Integer.valueOf(repeated);
stack.pop();
String repeatedStr = "";
while ((n = stack.pop()) != '(') {
repeatedStr = n + repeatedStr;
}
for (int j = 0; j != repeatedNum; j++) {
char[] chars = repeatedStr.toCharArray();
for (char c1 : chars) {
stack.push(c1);
}
}
}
}
while (!stack.isEmpty()) {
sb.insert(0, stack.pop());
}
return sb.toString();
}
}
算法执行效率
看看时候算法的运行时间与内存占用,是不是感觉好很多了呢?
小结
正如谚语所说,条条道路通罗马,每个题目的解决方案不会是唯一的,所以拓宽思路,尝试多种解方案,对于数据结构和算法的认知以及使用都是大有裨益的。别人会的你也会,别人不会的你还会,岂不快哉?