LeetCode: Decode String
https://leetcode.com/problems/decode-string/, this problem looked much simpler than it actually was. Code wise it was not that complicated, but it turned out being a fairly "special case" code with many different conditions being handled. It was neither a linear straightforward string manipulation solution, nor a base-case-induction stack-based one. It was a hybrid, which made the code hard to follow IMO.
Here is the problem:
The approach will be a recursive one, similar to a math expression evaluate code, but with some basic string manipulation along the way. As you can see in the code down below it does become hard to quite follow with the few too many special cases. Slightly better than 50% of the other submissions. Cheers, Marcelo.
public class Solution
{
public string DecodeString(string s)
{
//Base case
if (String.IsNullOrEmpty(s)) return s;
//Case when the string has no numbers
string retVal = "";
int index = 0;
while (index < s.Length && s[index] >= 'a' && s[index] <= 'z')
retVal += s[index++].ToString();
//Case when the string has a multiplying factor
int factor = 0;
while (index < s.Length && s[index] >= '0' && s[index] <= '9')
factor = 10 * factor + (int)(s[index++] - '0');
if (factor > 0)
{
//For the brackets, need to handle the nested ones
int nOpen = 1;
index++;
int beginIndex = index;
while (nOpen > 0)
{
if (s[index] == '[') nOpen++;
if (s[index] == ']') nOpen--;
if (nOpen > 0) index++;
}
//Call recursively for the brackets
string temp = s.Substring(beginIndex, index - beginIndex);
string subRetVal = DecodeString(temp);
//The multiplying factor
for (int i = 0; i < factor; i++)
retVal += subRetVal;
//Now remember that the string may continue, in which case another recursive call is needed
if (index + 1 < s.Length)
retVal += DecodeString(s.Substring(index + 1));
}
//Finally, the return
return retVal;
}
}
Here is the problem:
Given an encoded string, return it's decoded string.
The encoding rule is:
k[encoded_string]
, where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer.
You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.
Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won't be input like
3a
or 2[4]
.
Examples:
s = "3[a]2[bc]", return "aaabcbc". s = "3[a2[c]]", return "accaccacc". s = "2[abc]3[cd]ef", return "abcabccdcdcdef".
The approach will be a recursive one, similar to a math expression evaluate code, but with some basic string manipulation along the way. As you can see in the code down below it does become hard to quite follow with the few too many special cases. Slightly better than 50% of the other submissions. Cheers, Marcelo.
{
public string DecodeString(string s)
{
//Base case
if (String.IsNullOrEmpty(s)) return s;
//Case when the string has no numbers
string retVal = "";
int index = 0;
while (index < s.Length && s[index] >= 'a' && s[index] <= 'z')
retVal += s[index++].ToString();
//Case when the string has a multiplying factor
int factor = 0;
while (index < s.Length && s[index] >= '0' && s[index] <= '9')
factor = 10 * factor + (int)(s[index++] - '0');
if (factor > 0)
{
//For the brackets, need to handle the nested ones
int nOpen = 1;
index++;
int beginIndex = index;
while (nOpen > 0)
{
if (s[index] == '[') nOpen++;
if (s[index] == ']') nOpen--;
if (nOpen > 0) index++;
}
//Call recursively for the brackets
string temp = s.Substring(beginIndex, index - beginIndex);
string subRetVal = DecodeString(temp);
//The multiplying factor
for (int i = 0; i < factor; i++)
retVal += subRetVal;
//Now remember that the string may continue, in which case another recursive call is needed
if (index + 1 < s.Length)
retVal += DecodeString(s.Substring(index + 1));
}
//Finally, the return
return retVal;
}
}
It's a good one for testing stack understanding - checking if parenthesis are balanced is passé :) In general I try to avoid using implicit stack via recursion, since it can potentially overflow and is usually more expensive in terms of CPU and memory. Here is my dumb 0ms C++ solution:
ReplyDeleteclass Solution {
public:
string decodeString(const string& str) {
stack s;
s.push("");
stack reps;
int k = 0;
for (char ch : str) {
if (isdigit(ch)) {
k = k*10 + (ch-'0');
} else if (ch == '[') {
reps.push(k);
s.push("");
k = 0;
} else if (ch == ']') {
string expanded;
for (int i = 0; i < reps.top(); ++i) expanded.append(s.top());
reps.pop();
s.pop();
s.top().append(expanded);
} else {
s.top().append(1, ch);
}
}
return s.top();
}
};