我在亚马逊的采访中遇到了这个问题。
给定Java中的String作为输入3[a]2[bc]
编写一个函数来解码它,因此输出应为" **aaabcbc**
"
Input 3[a]2[bc] -> aaabcbc
Input 3[2[a]]4[b] -> aaaaabbbb
Invalid Input 3[4] `enter code here`
Invalid Input a[3]
我尝试了以下方法,但不正确,因为它没有解决嵌套元素
String test = "3[a]2[b]5[b]";
Map<Character, Integer> map = new HashMap<>();
char[] characters = test.toCharArray();
for (int i = 0; i < characters.length-1; i++) {
if(characters[i]=='['){
if(map.containsKey(characters[i+1])){
int count = map.get(characters[i+1]);
map.put(characters[i+1], Character.getNumericValue(characters[i-1])+count);
}else{
map.put(characters[i+1], Character.getNumericValue(characters[i-1]));
}
}
}
for (Map.Entry<Character, Integer> c : map.entrySet()) {
for (int i = 0; i < c.getValue(); i++) {
System.out.printf("%s",c.getKey());
}
}
对此有什么正确的解决方案?
是否可以使用封装类来解码这个问题,如果你在格式中仔细观察它的问题,我们可以将它转换为解码器类的对象。 2 [...] 3 [...] 4 [...]
class Decoder{
private int count;// digit example 2[a]3[bc]4[d] the count value will be 2,3,4
private String data; // example a,bc,d
private Decoder decoder; // for nested values example 3[2[a]] in this case decoder will be 2[a]
}
答案 0 :(得分:2)
将2[2[a]3[b]]
等嵌套表达式缩减为aabbbaabbb
可以通过 innermost redux (= reducable expression)来完成。
因此,请继续替换未使用的形式digit[letters]
,直到不能再减少任何形式。
因为这看起来只是一个草图:
String expression = "...";
for (;;) {
boolean reduced = false;
for (int i = 0; i < expression.length(); ++i) {
if (found reducable expression) {
reduced = true;
expression = reduced expression;
break; // Otherwise we would need to correct i.
}
}
if (!reduced) {
break;
}
}
基于模式匹配的具体解决方案。
String expression = "...";
Pattern reduxPattern = Pattern.compile("(\\d+)\\[(\\pL*)\\]");
boolean reducing;
do {
Matcher m = reduxPattern.matcher(expression);
reducing = false;
StringBuffer sb = new StringBuffer();
while (m.find()) {
reducing = true;
int n = Integer.parseInt(m.group(1));
String letters = m.group(2);
String repetition = String.join("", Collections.nCopies(n, letters));
sb.appendReplacement(repetition);
}
m.appendTail(sb);
expression = sb.toString();
} while (reducing);
正如评论中所讨论的那样,基于堆栈的解决方案是优越的,但我发现它的工作量更多。
答案 1 :(得分:1)
可以更清洁,但似乎解决了提到的问题 更新我已更新代码以解决@JimMichel指出的问题 这会考虑数字的多个数字,并且不接受格式错误的输入。
public static String decode(String in) {
Deque<Character> stack = new ArrayDeque<Character>();
Deque<Integer> occurencesStack = new ArrayDeque<Integer>();
StringBuilder result = new StringBuilder();
int brackets = 0;
for(int i = 0; i < in.length(); ++i) {
Character ch = in.charAt(i);
if(ch == '[') {
++brackets;
continue;
}
else if(ch == ']') {
--brackets;
StringBuilder temp = new StringBuilder();
while(!stack.isEmpty()) {
Character top = stack.pop();
temp.append(top);
}
int times = occurencesStack.pop();
if(temp.length() == 0) {
temp = new StringBuilder(result);
result.setLength(0);
for(int j = 0; j < times; ++j) {
result.append(temp);
}
}
else {
temp.reverse();
for(int j = 0; j < times; ++j) {
result.append(temp);
}
temp.setLength(0);
}
}
else if(Character.isDigit(ch)) {
StringBuilder nb = new StringBuilder();
nb.append(ch);
while(i < in.length() - 1 && Character.isDigit(in.charAt(i + 1))) {
nb.append(in.charAt(i + 1));
++i;
}
if(i < in.length() - 1 && in.charAt(i + 1) == ']') {
throw new IllegalArgumentException("Invalid sequence");
}
occurencesStack.push(Integer.parseInt(nb.toString()));
}
else if(ch >= 'a' && ch <= 'z') {
if(i < in.length() - 1 && in.charAt(i + 1) == '[') {
throw new IllegalArgumentException("Invalid sequence");
}
stack.push(ch);
}
else {
throw new IllegalArgumentException("Invalid character in sequence "+ch);
}
}
if(brackets != 0) {
throw new IllegalArgumentException("Unmatched brackets!");
}
return result.toString();
}
答案 2 :(得分:1)
考虑一下如果添加一些运算符会发生什么。也就是说,"3[a]2[bc]"
变为3*[a] + 2*[bc]
。如果您重新定义*
运算符以表示&#34;重复,&#34;并且+
运算符表示&#34;连接&#34;。
使用Shunting yard algorithm,您可以将字符串解析为后缀形式:3 a * 2 bc +
。分流码可轻松处理嵌套表达式。例如,您的3[2[a]]4[b]
变为3 2 a * * 4 b * +
。关于postfix的好处是它评估起来非常简单。
一旦您确信正确生成后缀表单,您可以编写代码来评估后缀表达式(这非常简单),或者您可以修改您的分流码算法以在输出阶段进行评估。也就是说,不是将操作数和运算符输出到字符串,而是将操作数推送到堆栈上,无论何时输出运算符,都可以从堆栈中弹出操作数,应用运算符,然后将结果推送到堆栈中。所以你的输出步骤变为:
if (token is an operand)
push token onto stack
else
pop operand2
pop operand1
result = operand1 <operator> operand2
push result onto stack
当你完成解析时,堆栈上应该有一个操作数,你可以输出它。
后缀方法的替代方法是创建binary expression tree,然后对其进行评估。另一种选择是写一个recursive descent parser,虽然除非你最近一直在处理表达式解析,否则在面试过程中你可能很难得到它。
答案 3 :(得分:0)
作为问题的假设是含糊不清的:
对于第二种情况,3 [2 [a]] - > 3 [aa] - &gt; aaaaaa
对于第三种情况,如果整数在方括号内 - 用户将 通常提供输入和解码。
对于第四种情况,如果整数在方括号之外,则从输出中删除此字符串。
请试试这段代码。我在评论中询问了一些问题,请澄清它们。
import java.util.Random;
import java.util.Scanner;
public class MyClass {
private static String code = "3[a]2[bc]";
private static class Pair {
int s = 0;
int e = 0;
}
private static Pair getPair() {
char[] chars = code.toCharArray();
Pair pair = new MyClass.Pair();
int pointer = 0;
for (char c : chars) {
if (c == '[') {
pair.s = pointer;
}
if (c == ']') {
pair.e = pointer;
break;
}
pointer = pointer + 1;
}
if (pair.e > (pair.s + 1) || pair.s !=0) {
return pair;
}else{
return null;
}
}
private static boolean parseInteger(String s)
{
try {
Integer.parseInt(s);
return true;
} catch(NumberFormatException e) {
return false;
}
}
private static void decode(Pair pair){
String pattern = code.substring(pair.s+1, pair.e);
String patternCount = code.substring(pair.s-1, pair.s);
if(!parseInteger(patternCount)) {
code = code.replace(code.substring(pair.s-1, pair.e+1) , "");
}else if(parseInteger(pattern)){
Scanner scanner = new Scanner(System.in);
System.out.println("Enter Code for : "+code.substring(pair.s-1, pair.e+1) );
String replacement = "";
pattern = scanner.nextLine();
for(int i = 0 ; i < Integer.parseInt(patternCount);i++){
replacement = replacement + pattern;
}
code = code.replace(code.substring(pair.s-1, pair.e+1) , replacement);
}else{
String replacement = "";
for(int i = 0 ; i < Integer.parseInt(patternCount);i++){
replacement = replacement + pattern;
}
code = code.replace(code.substring(pair.s-1, pair.e+1) , replacement);
}
}
public static void main(String[] args) {
boolean decoding = false;
do{
Pair pair = getPair();
decoding = pair != null ? true : false;
if(decoding){
decode(pair);
}
}while(decoding);
System.out.println(code);
}
}
答案 4 :(得分:0)
我使用递归尝试了这个问题,我认为这是解码这个问题的正确方法:
示例:如果我们有一个字符串2 [3 [abc]] 2 [xy],那么在一个级别解码它
1级:3 [abc] 3 [abc] 2 [xy]
2级:abcabcabc3 [abc] 2 [xy]
3级:abcabcabcabcabcabc2 [xy]
4级:abcabcabcabcabcabcxyxy
演示代码如下:
private static void decode(String value) {
int startBracket=0;
int endBracket=0;
int encodedCount=0;
int startIndex=0;
String result="";
StringBuilder temp=new StringBuilder();
char[] data = value.toCharArray();
for (int i = 0; i < data.length; i++) {
if(data[i]=='['){
if(encodedCount==0){
encodedCount=Character.getNumericValue(data[i-1]);
startIndex=i;
}
startBracket++;
continue;
}
if(data[i]==']'){
endBracket++;
}
if(startBracket==endBracket && startBracket!=0 && endBracket !=0){
System.out.println(encodedCount);
result=value.substring(0,startIndex-1);
String expandedTarget=value.substring(startIndex+1,i);
String remainingEncodedValue = value.substring(i+1,value.length());
System.out.println(expandedTarget);
System.out.println(remainingEncodedValue);
for (int j = 1; j <= encodedCount; j++) {
temp.append(expandedTarget);
}
if(remainingEncodedValue.length()>1)
temp.append(remainingEncodedValue);
System.out.println("Decoded Result : "+result + temp.toString());
decode(result + temp.toString());
break;
}
}
}