I have a task to remove duplicates from given string (classic interview question), but this one is a bit different, the end result should be in the smallest lexicographical order possible among other. For example, cbacdcbc => acdb, bcabc => abc. I saw several related problems in SO, but I could not find the answer.
Edit: Here is my code so far (not working properly):
public static String removeDuplicateCharsAlphbetically(String str) {
int len = str.length();
if (len<2) return str;
char[] letters = str.toCharArray();
int[] counts = new int[26];
for (char c : letters) {
counts[c-97]++;
}
StringBuilder sb = new StringBuilder();
for (int i=0;i<len-1;i++) {
if (letters[i]==letters[i+1]) continue;
if (counts[letters[i]-97]==1) {
sb.append(letters[i]);
} else if (counts[letters[i]-97] != 0) {
if (letters[i]<letters[i+1] && counts[letters[i]-97] == 1) {
sb.append(letters[i]);
counts[letters[i]-97]=0;
} else {
counts[letters[i]-97]--;
}
}
}
return sb.toString();
}
EDIT2: I am sorry for not putting link of the question earlier. here is the link:
This can be done in O(StringLenght) time.
String lenght = N;
Time Complexity O(N) , single scan of the string.
Space Complexity O(26)
Solution:
Create an array of Alphabet letters which will store pointer to doubly link list Node .
ListNode* array[26]; // Initialized with NULL value.
Create an empty linkedlist , which will represent the solution string at any point of time, in reverse order.
Scan the string and for each letter , check the letter ,ltr, check array[ltr-'a']
.... a.) if it is NULL , it means , it is first occurence and add it to the linked list . ... b.) If array is pointing to any node listNodeltr , it means letter is already in result
i. check value for previous listNode to listNodeltr, in linklist ,
If value of listNodeltr->prev->val < listNode->val , it means removing the current node from this position will make the result lexographically smaller .
So remove listNodeLtr from the current postion in linkedList and add it to the end.
Else, current postion of ltr is find and continue.
cbacdcbc
[a]->[b]->[c]
cbacdcbc
[c]->[a]->[b]
cbacdcbc
[d]->[c]->[a]->[b]
cbacdcbc
[b]->[d]->[c]->[a]
cbacdcbc
[b]->[d]->[c]->[a]
print linklist in reverse order : acdb.
First, let's create a set of all distinct letters of the string s. The size of this set is the length of the answer and the number of steps in our algorithm.
We will add one letter to the answer on each step with the following greedy approach:
On every step iterate through the remaining letters in alphabetical order and for every letter l:
Find the first occurrence of l in s. Let's name it lpos.
If the substring s[lpos, end] contains all remaining letters then add l to the result, replace s with s[lpos+1, end] and go to the next step with reduced remaining letters set.
Implementation with some optimizations to achieve better time complexity:
public String removeDuplicateLetters(String s) {
StringBuilder result = new StringBuilder();
int[] subsets = new int[s.length()];
int subset = 0;
for (int i = s.length() - 1; i >= 0; i--) {
char ch = s.charAt(i);
subset = addToSet(subset, ch);
subsets[i] = subset;
}
int curPos = 0;
while (subset != 0) {
for (char ch = 'a'; ch <= 'z'; ++ch) {
if (inSet(subset, ch)) {
int chPos = s.indexOf(ch, curPos);
if (includes(subsets[chPos], subset)) {
result.append(ch);
subset = removeFromSet(subset, ch);
curPos = chPos + 1;
break;
}
}
}
}
return result.toString();
}
private boolean inSet(int set, char ch) {
return (set & (1 << (ch - 'a'))) != 0;
}
private boolean includes(int set, int subset) {
return (set | subset) == set;
}
private int addToSet(int set, char ch) {
return set | (1 << (ch - 'a'));
}
private int removeFromSet(int set, char ch) {
return set & ~(1 << (ch - 'a'));
}
Runnable version: https://ideone.com/wIKi3x
Observation 1: the first letter of the output is the least letter such that all other letters appear to the right of its leftmost appearance in the string.
Observation 2: the remaining letters of the output are a subsequence of the letters to the right of the leftmost appearance of the first letter.
This suggests a recursive algorithm.
def rem_dups_lex_least(s):
if not s:
return ''
n = len(set(s)) # number of distinct letters in s
seen = set() # number of distinct letters seen while scanning right to left
for j in range(len(s) - 1, -1, -1): # len(s)-1 down to 0
seen.add(s[j])
if len(seen) == n: # all letters seen
first = min(s[:j+1])
i = s.index(first) # leftmost appearance
return first + rem_dups_lex_least(''.join(c for c in s[i+1:] if c != first))
Build the result by going backwards from end of the input to start. On each step:
If new letter is encountered, prepend it to result.
If duplicate is encountered, then compare it with the head of result. If head is greater, remove duplicate from the result and prepend it instead.
LinkedHashSet is good both for storing result set and its internal order.
public static String unduplicate(String input) {
Character head = null;
Set<Character> set = new LinkedHashSet<>();
for (int i = input.length() - 1; i >= 0; --i) {
Character c = input.charAt(i);
if (set.add(c))
head = c;
else if (c.compareTo(head) < 0) {
set.remove(c);
set.add(head = c);
}
}
StringBuilder result = new StringBuilder(set.size());
for (Character c: set)
result.append(c);
return result.reverse().toString();
}
I have this algorithm to generate all combinations of well-formed parentheses.
Can someone explain the core concept of the algorithm? I tried debugging through it, but I still can't seem to grasp the underlying concept behind the algorithm.
Additionally, any general advice for how one can come up with such an algorithm for this problem, i.e how did one even get so clever to solve it this way, or what practice one has to do to reach this stage.
Problem:
Given n pairs of parentheses, write a function to generate
all combinations of well-formed parentheses. For example, given n = 3, a solution set is:
“((()))”, “(()())”, “(())()”, “()(())”, “()()()”
Code:
public ArrayList<String> generateParenthesis(int n) {
ArrayList<String> solutions = new ArrayList<String>();
recursion(n, new String(), solutions);
return solutions;
}
private void recursion(int n, String str, ArrayList<String> sol) {
if(str.length() == 2 * n)
sol.add(str);
else {
int left = 0;
int right = 0;
for(int i = 0; i < str.length(); ++i) {
if(str.charAt(i) == '(')
left++;
if(str.charAt(i) == ')')
right++;
}
if(left == right)
recursion(n, str + "(", sol);
else if(right < left) {
if(left < n)
recursion(n, str + "(", sol);
recursion(n, str + ")", sol);
}
}
}
It helps me to see visually how the calls are being stacked. I added a parameter String depth to the call and printed out depth + str on each call, adding four spaces to each depth parameter for a new call. This gives us a good view of the call order.
Here's the code for it:
recursion(3, new String(), solutions, "");
//...
private static void recursion(int n, String str, ArrayList<String> sol, String depth) {
System.out.println(depth + str);
//...
if(left == right)
recursion(n, str + "(", sol, depth + " ");
else if(right < left) {
if(left < n)
recursion(n, str + "(", sol, depth + " ");
recursion(n, str + ")", sol, depth + " ");
}
And here's what it prints out:
(
((
(((
((()
((())
((()))
(()
(()(
(()()
(()())
(())
(())(
(())()
()
()(
()((
()(()
()(())
()()
()()(
()()()
Each level of recursion adds another indent to the output. If two outputs are at the same level of indentation, then they were both called from the same level of recursion.
Here's another visual:
Note that each node is a deeper level of recursion and each time a child node comes straight down out of a parent node, it doesn't split into two recursive paths. That is, the parent node only calls recursion once.
Recursion can definitely mess with your head. Here's another approach which might be easier to follow:
void generate() {
ArrayList<String> results = new ArrayList<String>();
generateParentheses(4, 0, new StringBuilder(), results);
System.out.println(results);
}
void generateParentheses(final int remaining, final int openCount, final StringBuilder s, final List<String> results) {
if (remaining == 0 && openCount == 0) {
results.add(s.toString());
return;
}
if (openCount > 0) { // we can close the open one
s.append(")");
generateParentheses(remaining, openCount-1, s, results);
s.setLength(s.length()-1); // pop the last char off
}
if (remaining > 0) { // start a new one
s.append("(");
generateParentheses(remaining-1, openCount+1, s, results);
s.setLength(s.length()-1); // pop the last char off
}
}
Output is [()()()(), ()()(()), ()(())(), ()(()()), ()((())), (())()(), (())(()), (()())(), (()()()), (()(())), ((()))(), ((())()), ((()())), (((())))]
This goes at the problem from the other end. How do you come up with these patterns?
Start with the number of pairs (remaining).
There are only two possibilities: open or closed. An open parentheses can only be appended if there are some remaining to append. A close parentheses can only be appended if there is a corresponding opening parentheses to close.
So you just need to keep a count of how many remaining you have, and how deep into parentheses you are. Let recursion handle the rest.
Here's my attempted breakdown of the provided algorithm:
if(str.length() == 2 * n)
sol.add(str);
You know you're done if the string length is twice the number of pairs of parentheses. Why?
Because each pair of parentheses is 2 characters long, having n pairs of parentheses means you have 2 * n characters total (i.e. length / 2 == number of parentheses)
int left = 0;
int right = 0;
for(int i = 0; i < str.length(); ++i) {
if(str.charAt(i) == '(')
left++;
if(str.charAt(i) == ')')
right++;
}
This loops through the string character by character and does some tests and changes left and right depending on whether the particular character is a opening or closing parentheses. Based on that, can you figure out what left and right are at the end of the loop?
left and right are the number of opening/closing parentheses in the string, respectively
if(left == right)
recursion(n, str + "(", sol);
else if(right < left) {
if(left < n)
recursion(n, str + "(", sol);
recursion(n, str + ")", sol);
}
If left == right, then you call the same function, except you tack on an opening parenthesis onto the existing string. Why add a parenthesis, and why is it an opening parenthesis?
You know you're not done, because if you were you would have triggered the first if statement. Because adding a closed parenthesis would result in ill-formed parenthesis because there is no unclosed opening parenthesis (remember, left == right), the next logical step is to add an opening parenthesis.
If right < left, you know that you have at least one unclosed opening parenthesis. So you want to do another check.
if(left < n)
recursion(n, str + "(", sol)
Why do this check? If left < n, then you know that if you close all the open parentheses you won't have enough pairs (n pairs of parentheses have n opening parentheses). So might as well add another opening parenthesis!
The last statement has an implicit else associated with it. If left is not < n, then you know adding another left parenthesis would put you over the requested number of pairs. So add a closing parenthesis and continue.
The core concept:
1)X:If a string has more closing parentheses than opening ones, adding more parentheses to the right won't make it a well-formed combination.
2)All well-formed combinations have equal number of opening and closing parentheses. Hence, each type can be found exactly n times
3)If the number of closing ones is less than the number of the opening ones, then we can always make a consequence well-formed, by adding more closing parentheses.
This algorithm builds the combination, adding new symbols to the right
public ArrayList<String> generateParenthesis(int n) {
ArrayList<String> solutions = new ArrayList<String>();
recursion(n, new String(), solutions);
return solutions;
}
private void recursion(int n, String str, ArrayList<String> sol) {
//If we got a sting long enough, we return it. This means a) We generate all
//strings only once. b)If a string of length 2*n is created, then it is correct. Other
//code should satisfy these conditions
if(str.length() == 2 * n)
sol.add(str);
else {
int left = 0;
int right = 0;
for(int i = 0; i < str.length(); ++i) {
if(str.charAt(i) == '(')
left++;
if(str.charAt(i) == ')')
right++;
}
//left and right are now numbers of parentheses in the string.
//Opening and closing respectively.
if(left == right)//On each step we maintain the condition X
//that the number of closing brackets is less or equal to the number of opening.
//Therefore, is their numbers are equal we can only add opening ones
recursion(n, str + "(", sol);
else if(right < left) { // if X is maintained and we can add
//both types
if(left < n)// The number of opened should be no more than n,
//according to 2)
recursion(n, str + "(", sol);
recursion(n, str + ")", sol);//The number of closing ones is
//limited by X by the number of opening ones, which is limited by n => the number of
//the closed ones is limited by n => we can add them as long as it doesn't violate X
}
}
}
I wrote my own recursive parentheses generator in a different style. It basically builds up a String, but at each recursive call, a new String is created so that the backtracking is correct. I hope someone finds it helpful.
import java.util.ArrayList;
import java.util.List;
public class GenerateParentheses {
// N: The max number of matching parentheses. This value does not change.
// usedL, usedR : Number of left and right parentheses already used in 'current' string.
// current: the current string being built.
// depth: recursion depth, used for pretty-printing
public static void generate(int N, int usedL, int usedR, String current, List<String> result, int depth) {
System.out.printf("%susedL=%d, usedR=%d, current='%s'\n",
getIndentation(depth), usedL, usedR, current);
if (usedL == N && usedR == N) {
// We've used up all the available parentheses (up to N),
// so add the current built string to the result.
result.add(current);
return;
}
if (usedL < N) {
// Add another left parenthesis "(".
String newCurrent = current + "(";
generate(N, usedL + 1, usedR, newCurrent, result, depth+1);
}
if (usedR < N && usedL > usedR) {
// Add another right parenthesis ")" if there are already
// used left parentheses.
String newCurrent = current + ")";
generate(N, usedL, usedR + 1, newCurrent, result, depth+1);
}
}
// Utility function used for pretty-printing.
private static String getIndentation(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
return sb.toString();
}
public static void main(String argv[]) {
int N = 3;
int usedL = 0;
int usedR = 0;
String current = "";
List<String> result = new ArrayList<String>();
int depth = 0;
generate(N, usedL, usedR, current, result, depth);
for (String s : result) {
System.out.printf("%s\n", s);
}
}
}
Here is the output:
usedL=0, usedR=0, current=''
usedL=1, usedR=0, current='('
usedL=2, usedR=0, current='(('
usedL=3, usedR=0, current='((('
usedL=3, usedR=1, current='((()'
usedL=3, usedR=2, current='((())'
usedL=3, usedR=3, current='((()))'
usedL=2, usedR=1, current='(()'
usedL=3, usedR=1, current='(()('
usedL=3, usedR=2, current='(()()'
usedL=3, usedR=3, current='(()())'
usedL=2, usedR=2, current='(())'
usedL=3, usedR=2, current='(())('
usedL=3, usedR=3, current='(())()'
usedL=1, usedR=1, current='()'
usedL=2, usedR=1, current='()('
usedL=3, usedR=1, current='()(('
usedL=3, usedR=2, current='()(()'
usedL=3, usedR=3, current='()(())'
usedL=2, usedR=2, current='()()'
usedL=3, usedR=2, current='()()('
usedL=3, usedR=3, current='()()()'
((()))
(()())
(())()
()(())
()()()
How you get to the solution will be easier to see as you get more experience with recursion.
Idea: well-formed parentheses are always going to start with a left paren, have an equal number of left & right, and when reading left to right the following will always be true left >= right
Therefore when making a recursive solution, we'll use a simple rule: prefer to open left paren and let the nature of the recursive function unwinding take care of the rest
private void recursion(int n, String str, ArrayList<String> sol) {
if(str.length() == 2 * n)
sol.add(str);
We have n pairs, add the solution & return
else {
int left = 0;
int right = 0;
for(int i = 0; i < str.length(); ++i) {
if(str.charAt(i) == '(')
left++;
if(str.charAt(i) == ')')
right++;
}
Count up the number of left & right parens
if(left == right)
recursion(n, str + "(", sol);
str is currently balanced & since we prefer left over right, add a left
else if(right < left) {
This could just be an else, right will never be > left. Either way, it means that we're currently unbalanced, there is at least 1 more left than right.
if(left < n)
recursion(n, str + "(", sol);
Check if you can add another left, again because prefer left over right
recursion(n, str + ")", sol);
}
}
Add our right paren. This will either close the paren added in the line above it, or if that wasn't executed, it will close an earlier left (remember that we're in this block because it's currently unbalanced)
Here's a more simpler and intuitive solution to your problem.
Again, this follows the recursion idea but it is easier to read and more efficient than the one you posted.
public void generateParantheses(int n){
helper(n,0,0,"");
}
public void helper(int n, int open, int close, String result){
if(result.length()==2*n) {
// easy enough to understand? one open and one close for each n?
System.out.println(result);
return;
}
if(open<n){
//start off with all n open parantheses
helper(n, open+1, close, result+"(" );
}
if(close<open){
// now check if we can add closing parantheses on top of open in this condition
helper(n, open, close+1, result+")");
}
}
public static void findParenthisis(String s , int left ,int right){
if(left==right && left == 0){
System.out.println(s);
}
if(left > 0){
findParenthisis(s+'(',left-1,right);
}
if(left < right){
findParenthisis(s + ')',left,right-1);
}
}
void generateParenthesis(int open, int close, int position, int n, char[] str) {
/*
* open = open parenthesis
* close = close parenthesis
* position = 2*n (length of combination of valid parenthesis
* n = pair of parenthesis
* Algorithm:
* 1.Check if position == 2*n -- Yes, print the str
* 2.check if open is less than n
* If true, add a open parenthesis into str and call the function recursively by
* incrementing open by 1 and position by 1
* 3.check if close < open
* If true , add a close parenthesis and call the function recursively by
* incrementing close by 1 and position by 1*/
if(position ==str.length) {
for(int i=0;i<str.length;i++) {
System.out.print(str[i]);
}
System.out.println();
return;
}
if(open < n) {
str[position] = '(';
generateParenthesis(open+1,close,position+1,n,str);
}if(close< open) {
str[position]=')';
generateParenthesis(open,close+1,position+1,n,str);
}
}
I think I found a very intuitive solution that gets inspiration from a similar problem. Imagine you have a grid of size n x n. You want to move from the left-down corner to the right-upper corner. Every move to the right can be interpreted as a ( and every move up as ). The simplest case would be a grid of 1x1. There are two ways to go: RU (right then up) and UR (up then right) the first one corresponds to () and the second one )(. The second case is invalid so we discard all the paths from the upper triangle of the grid. For n=4 :
The problem can be solved recursively. We should start from R=0, U=0. Once we get to R=n, U=n we are done and should add the partial_solution to the solutions. There are two cases:
When R<n we still can move right and increment R.
When U<R notice we can only go up as much as we stay under the diagonal. In this case we can still move up and increment U.
def move(R, U, n, solutions, partial_solution):
if R == n and U == n:
solutions.append(partial_solution)
return
if R < n:
move(R + 1, U, n, solutions, partial_solution + '(')
if U < R:
move(R, U + 1, n, solutions, partial_solution + ')')
solutions = []
n=4
move(0, 0, n, solutions, '')
print(solutions)
Additional:
Note that this formulation also helps us to understand the number of ways we can form the parenthesis. Going from R=0, U=0 to R=n, U=n requires a string of R's and U's with the property that we should have exactly n R's and n U's. For example for n=3:
RRRUUU, RRURUU, URURUR, URRRUU, ...
It's a combinatorial problem and the number of ways is combination(2n, n). But we have to consider removing the upper triangle. This leaves us with 1/(n+1) * combination(2n, n) which is the Catalan number of n.
`class Solution:
def generateParenthesis(self, n):
# Backtracking
result_list = list()
stack = list()
def create_parenthesis(left_count, right_count):
if left_count == n and right_count == n:
result_list.append("".join(stack))
if left_count < n:
print("Appending ( to stack")
stack.append("(")
before_spacing = (left_count + right_count) * "\t"
print(before_spacing + "".join(stack))
create_parenthesis(left_count+1, right_count)
print("Popping from left_count < n")
stack.pop()
if left_count > right_count:
print("Appending ) to stack.")
stack.append(")")
before_spacing = (left_count + right_count) * "\t"
print(before_spacing + "".join(stack))
create_parenthesis(left_count, right_count+1)
print("Popping from left_count > right_count")
stack.pop()
create_parenthesis(0, 0)
return result_list`
print(Solution().generateParenthesis(n=3))
Output:
output
class Solution:
def generateParenthesis(self, n: int) -> list[str]:
stack = []
res = []
def back_Move(openPar,closedPar):
if openPar == closedPar==n:
res.append("".join(stack))
return
if openPar<n:
stack.append("(")
back_Move(openPar+1,closedPar)
stack.pop()
if closedPar<openPar:
stack.append(")")
back_Move(openPar,closedPar+1)
stack.pop()
back_Move(0,0)
return res
So im working on java codingbat and this is the question:
Given a string, look for a mirror image (backwards) string at both the beginning and end of the given string.
In other words, zero or more characters at the very begining of the given string, and at the very end of the string in reverse order (possibly overlapping).
For example:
the string "abXYZba" has the mirror end "ab". mirrorEnds("abXYZba") → "ab" mirrorEnds("abca") → "a" mirrorEnds("aba") → "aba" .
My code passed all the test except for the other test, which is not specified. I dont know what's wrong with it.
public String mirrorEnds(String string) {
String input = string, mirror = "";
int length = string.length();
for (int n = 0; n < (length+1) / 2; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}else if(length%2 == 1 && n == (length - 1)/2){
// System.out.println("length/2 = " );
return input;
}
else {
mirror += input.charAt(n);
}
}
return mirror;
}
You were correct in not needing to go though the entire word, but your logic is more complex than it needs to be, making it harder to find and fix the problem. The root cause of the test failure is in the last return statement. It must return string if the loop completes without breaking. You can fix your code by changing break; to return mirror; and changing the last return mirror; to return input;
The test that is failing is one like this:
mirrorEnds("abba") -> "abba"
A much simpler version of your code can be created like this:
public String mirrorEnds(String string) {
int len = string.length();
for (int i=0; i < len/2; ++i)
if (string.charAt(i) != string.charAt(len - 1 - i))
return string.substring(0, i);
return string;
}
mirrorEnds("abba")?
Anyways, I'm sure you could come up with a better question name than "some weird stuff"...
Since you are dividing n by 2 in your loop termination condition, it will end when halfway through the word. This is enough to tell the word is a palindrome, but not enough to build your output correctly. You have a condition handling palindrome with odd numbers of letter, but not even numbers of letters. I believe the failing test will be of the form "abba", where I believe what you have will return "ab", instead of "abba".
If you change you loop to:
for (int n = 0; n < length; n++) {
I believe it should be doing what you want. This also makes the short circuit case unnecessary, so:
for (int n = 0; n < length; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}
else {
mirror += input.charAt(n);
}
}
The first test I tried was with the string "abba" which fails. It returns ab, and not abba. As femtoRgon mentioned, you're not going through the entire word, which may some times be necessary. femtoRgon's solution works, as well as taking a slightly different approach to iterating through the word as follows:
public String mirrorEnds(String string) {
boolean matches = true;
StringBuilder mirrorEnd = new StringBuilder();
int index = 0;
while (matches && index < string.length()) {
if (string.charAt(index) == string.charAt(string.length() - index - 1))
mirrorEnd.append(string.charAt(index));
else
matches = false;
index++;
}
return mirrorEnd.toString();
}
public String mirrorEnds(String string) {
String comp="";
for(int i=0; i<string.length(); i++){
if(string.charAt(i)==string.charAt(string.length()-(i+1)))
comp= comp+ string.charAt(i);
else break;
}
return comp;
}