Remove all adjacent duplicates using loops - python

I'm trying to solve this problem. I have seen other solutions that involve lists and using recursion but I'm interested in learning how to solve this with loops and I can't seem to get the right output.
(i.e. no regular expressions, no tuples, no methods of string, etc.)
input: caaabbbaacdddd
expected output:empty string
input:abbabd
expected output:bd
below is my code i have found other methods to solve this problem im just looking for the most basic solution for this.
answer = input("enter a string: ")
new_answer = ""
#while answer != new_answer:
if answer == "":
print("goodBye!")
#break
p = ""
for c in answer:
if p != c:
new_answer += p
p = c
else:
p = c
print(new_answer)
the commented out part is to make the whole program loop through to verify thier is no more duplicates.

The simplest loop-based solution would be:
result = ""
for i in answer:
if result == "" or result[-1] != i:
result += i
You could also use itertools.groupby which does what you're looking for:
print("".join([i for i in map(lambda x: x[0], itertools.groupby(answer))])

Try this! Only issue in your logic is that you are not removibg the character which is being repeated once its added tk the new_answer.
count = 0
for c in answer:
if p != c:
new_answer += p
p = c
else:
new_answer = new_answer.replace(c,””,count)
p = c
count += 1
print(new_answer)
Simplifying it even more without replace function:
count = 0
for c in answer:
if p != c:
new_answer += p
p = c
else:
if count == 0:
new_answer =“”
else:
new_answer=new_answer[:count-1]
count -=1
p = c
count += 1
print(new_answer)

I would do like this with javascript ( i know it's not python, but same logic):
let answer = 'acacbascsacasceoidfewfje';
for(i=0;i<answer.length;i++){
if(obj[answer.substr(i,1)] === undefined){
obj[answer.substr(i,1)] = 1
}else{
obj[answer.substr(i,1)]++;
}
}
JSON.stringify(obj)
Results:
"{"a":4,"c":4,"b":1,"s":2,"e":2,"o":1,"i":1,"d":1,"f":1,"w":1,"j":1}"

It seems you are just comparing the current character with the immediate previous character. You can use the in operator:
if char in String
for all 26 characters
You could also make a dictionary for all 26 characters if you can use that (since you are only using loops)

public class RemoveAdjacentDuplicates {
public static void main(String[] args) {
System.out.println(removeDuplicates("abbabd"));
}
public static String removeDuplicates(String S) {
char[] stack = new char[S.length()];
int i = 0;
for(int j = 0 ; j < S.length() ; j++) {
char currentChar = S.charAt(j);
if(i > 0 && stack[i-1] == currentChar) {
i--;
}else {
stack[i] = currentChar;
i++;
}
}
return new String(stack , 0 , i);
}
}
Results of the program are :
input: caaabbbaacdddd
output:empty string
input:abbabd
output:bd

Related

I just need to turn solution of JavaScript problem into Python code using the same approach

I'm stuck on turning this JS anagram problem into Python solution using the same approach.
Here is the problem:
Here is the JavaScript solution:
if (first.length !== second.length) {
return false;
}
const lookup = {};
for (let i = 0; i < first.length; i++) {
let letter = first[i];
// if letter exists, increment, otherwise set to 1
lookup[letter] ? (lookup[letter] += 1) : (lookup[letter] = 1);
}
for (let i = 0; i < second.length; i++) {
let letter = second[i];
// can't find letter or letter is zero then it's not an anagram
if (!lookup[letter]) {
return false;
} else {
lookup[letter] -= 1;
}
}
return true;
}
console.log(validAnagram('anagram', 'nagaram'));
And here is my Python code using the same approach:
if len(first) != len(second):
return False
lookup = {}
for char in first:
letter = first[char]
if lookup[letter]:
lookup[letter] += 1
else:
lookup[letter] = 1
for char in second:
letter = second[char]
if not lookup[letter]:
return False
else:
lookup[letter] -= 1
return True
print(valid_anagram("anagram", "nagaram"))
This is the error I'm getting when I run my Python solution:
letter = first[char] TypeError: string indices must be integers
Here's the same solution, that uses dict to count letters like your Java code:
from collections import Counter
def valid_anagram( str1, str2 ) :
return Counter(str1) == Counter(str2)
testing:
>>> valid_anagram('anagram', 'nagaram')
True
>>>
I wrote below, and I write here again, the whole point of using python is not reinventing the wheel and use existing libraries to make the code compact, fast and easy to understand.
Take for example your code:
for char in first:
letter = first[char]
if lookup[letter]:
lookup[letter] += 1
else:
lookup[letter] = 1
This can be rewritten as:
lookup = dict()
for letter in first:
if lookup[letter]:
lookup[letter] += 1
else:
lookup[letter] = 1
Or, better yet:
lookup = Counter()
for letter in first:
lookup[letter] += 1
Or, even better:
lookup = Counter( first )
So why waste time and space....
You are attempting to pass in a string to get the index instead of passing in an integer.
first = "hello"
for char in first:
print(char)
Output:
h
e
l
l
o
To get the index use this:
for char in range(len(first)):
print(char)
Output:
0
1
2
3
4
Here is a simpler solution
def valid_anagram(str1, str2):
list_str1 = list(str1)
list_str1.sort()
list_str2 = list(str2)
list_str2.sort()
return (list_str1 == list_str2)

Find longest sequence of 0's in the integer list

A = [1,2,0,0,3,4,5,-1,0,2,-1,-3,0,0,0,0,0,0,0,0,-2,-3,-4,-5,0,0,0]
Return initial and ending index of longest sequence of 0's in the list.
As, longest sequence of 0's in above list is 0,0,0,0,0,0,0,0 so it should return 12,19 as starting and ending index.Please help with some one line python code.
I tried :
k = max(len(list(y)) for (c,y) in itertools.groupby(A) if c==0)
print(k)
which return 8 as the max length.
Now, how to find start and end index of longest sequence?
you can first use enumerate to zip the item with index,
and then itertools.groupby(list,operator.itemgetter(1)) to group by item,
filter only 0s using list(y) for (x,y) in list if x == 0,
and at last max(list, key=len) to get the longest sequence.
import itertools,operator
r = max((list(y) for (x,y) in itertools.groupby((enumerate(A)),operator.itemgetter(1)) if x == 0), key=len)
print(r[0][0]) # prints 12
print(r[-1][0]) # prints 19
You can try this:
A = [1,2,0,0,3,4,5,-1,0,2,-1,-3,0,0,0,0,0,0,0,0,2,-3,-4,-5,0,0,0]
count = 0
prev = 0
indexend = 0
for i in range(0,len(A)):
if A[i] == 0:
count += 1
else:
if count > prev:
prev = count
indexend = i
count = 0
print("The longest sequence of 0's is "+str(prev))
print("index start at: "+ str(indexend-prev))
print("index ends at: "+ str(indexend-1))
Output:
The longest sequence of 0's ist 8
index start at: 12
index ends at: 19
A nice concise native python approach
target = 0
A = [1,2,0,0,3,4,5,-1,0,2,-1,-3,0,0,0,0,0,0,0,0,2,-3,-4,-5,0,0,0]
def longest_seq(A, target):
""" input list of elements, and target element, return longest sequence of target """
cnt, max_val = 0, 0 # running count, and max count
for e in A:
cnt = cnt + 1 if e == target else 0 # add to or reset running count
max_val = max(cnt, max_val) # update max count
return max_val
Now that you have the length, find that k-length sequence of 0's in the original list. Expanding the stuff you'll eventually work into one line:
# k is given in your post
k_zeros = [0]*k
for i in range(len(A)-k):
if A[i:i+k] == k_zeros:
break
# i is the start index; i+k-1 is the end
Can you wrap this into a single statement now?
Ok, as one long disgusting line!
"-".join([sorted([list(y) for c,y in itertools.groupby([str(v)+"_"+str(i) for i,v in enumerate(A)], lambda x: x.split("_")[0]) if c[0] == '0'],key=len)[-1][a].split("_")[1] for a in [0,-1]])
It keeps track of indices by turning [1,2,0...] into ["1_0","2_1","0_2",..] and then doing some splitting and parsing.
Yes it's very ugly and you should go with one of the other answers but I wanted to share
This solution i submitted in Codility with 100 percent efficieny.
class Solution {
public int solution(int N) {
int i = 0;
int gap = 0;
`bool startZeroCount = false;
List<int> binaryArray = new List<int>();
while (N > 0)
{
binaryArray.Add(N % 2);
N = N / 2;
i++;
}
List<int> gapArr = new List<int>();
for (int j = i-1; j >= 0; j--)
{
if (binaryArray[j] == 1)
{
if(startZeroCount)
{
gapArr.Add(gap);
gap = 0;
}
startZeroCount = true;
}
else if(binaryArray[j] == 0)
{
if (startZeroCount)
gap++;
}
}
gapArr.Sort();
if (gapArr.Count != 0)
return gapArr[gapArr.Count - 1];
else return 0;enter code here
}
}
A = [1,2,0,0,3,4,5,-1,0,2,-1,-3,0,0,0,2,-3,-4,-5,0,0,0,0]
count = 0
prev = 0
indexend = 0
indexcount = 0
for i in range(0,len(A)):
if A[i] == 0:
count += 1
indexcount = i
else:
if count > prev:
prev = count
indexend = i
count = 0
if count > prev:
prev = count
indexend = indexcount
print("The longest sequence of 0's is "+str(prev))
print("index start at: "+ str(indexend-prev))
print("index ends at: "+ str(indexend-1))
To also consider if longest 0's sequecnces are at the end.
Output
The longest sequence of 0's is 4
index start at: 18
index ends at: 21
If you would like to completely avoid Python iteration you can do it with Numpy. E.g., for very long sequences, using for loops may be relatively slow. This method will use pre-compiled C for-loops under the hood. The disadvantage is that you have multiple for-loops here. Nonetheless, overall, below algorithm should be a speed gain on longer sequences.
import numpy as np
def longest_sequence(bool_array):
where_not_true = np.where(~bool_array)[0]
lengths_plus_1 = np.diff(np.hstack((-1,where_not_true,len(bool_array))))
index = np.cumsum(np.hstack((0,lengths_plus_1)))
start_in_lngth = np.argmax(lengths_plus_1)
start = index[ start_in_lngth]
length = lengths_plus_1[start_in_lngth] - 1
return start, length
t = np.array((0,1,0,1,1,1,0,0,1,1,0,1))
print(longest_sequence(t==0))
print(longest_sequence(t==1))
p = np.array((0,0,0,1,0,1,1,1,0,0,0,1,1,0,1,1,1,1))
print(longest_sequence(p==0))
print(longest_sequence(p==1))

Difference between two products nearest to zero: non brute-force solution?

In a science museum in Norway I came across the following mathematical game:
The goal is to place the 10 digits from 0 to 9 such that the difference between the two products is nearest to zero. (The 246 is the current lowest score).
Back home I wrote the following brute-force code:
import time
from itertools import permutations
def form_number(x, y, z, a, b):
# not explicitly stated, but presume that leading zeroes are not allowed
if x == 0 or a == 0:
return 0
return ((100 * x) + (10 * y) + z) * ((10 * a) + b)
def find_nearest_zero(*args):
assert len(args) == 10
return form_number(*args[:5]) - form_number(*args[5:])
if __name__ == '__main__':
start = time.time()
count = 0
for p in permutations(range(10), 10):
result = find_nearest_zero(*p)
if result == 0:
count += 1
print '{}{}{} * {}{} = {n}'.format(*p[:5], n=form_number(*p[:5]))
print '{}{}{} * {}{} = {n}'.format(*p[5:], n=form_number(*p[5:]))
print
print 'found {} solutions'.format(count)
print time.time() - start
If we don't allow leading zeroes, then this prints 128 possible solutions in about 12 seconds.
But I'm left wondering, is there an algorithm or a better way to solve this in a non-brute force way?
If you assume there is a solution with difference 0, you can do via prime factors.
If ab - cd = 0, then the prime factors of ab and cd must be the same. You can start the search by going through all 3-digit primes (there are only 143) and see whether they have a multiple that only contains disjunctive digits. If this is the case you have your 2 three-digit numbers and only have to check the 2-digit ones.
If you don't find a solution, continue with the 2-digit primes and look for 2-or-3-digit multiples with disjunct digits. Then you only have to do the permutations for the remaining 2 numbers, which is a lot less.
This one assumes a difference of zero is possible (although it could be adapted to finding the minimum/s by sorting — thank you, m69, for that idea — each group of 120 permutations and using binary search, adding a factor of (log2 120) to the time complexity): hash the multiples for all 10 choose 5 * 5! combinations of three-digit times two-digit numbers, where the key is the sorted five-digit combination. Then if a reciprocal key (one that contains the other five digits) points to an equal multiple, output that match. Altogether 30,240 combinations are checked.
JavaScript code:
function choose(ns,r){
var res = [];
function _choose(i,_res){
if (_res.length == r){
res.push(_res);
return;
} else if (_res.length + ns.length - i == r){
_res = _res.concat(ns.slice(i));
res.push(_res);
return
}
var temp = _res.slice();
temp.push(ns[i]);
_choose(i + 1,temp);
_choose(i + 1,_res);
}
_choose(0,[]);
return res;
}
function missingDigits(str){
var res = "";
for (var i=0; i<=9; i++){
if (str.indexOf(i) === -1){
res += i;
}
}
return res;
}
var digitsHash = {};
function permute(digits){
var stack = [[String(digits[0])]];
for (var i=1; i<5; i++){
var d = digits[i],
perms = stack.shift(),
_perms = [];
for (var j=0; j<perms.length; j++){
var temp = perms[j];
for (var k=0; k<=perms[0].length; k++){
if (d == 0 && (k == 0 || k == 3)){
continue;
}
var _temp = temp;
_temp = temp.split("");
_temp.splice(k,0,d);
_temp = _temp.join("")
_perms.push(_temp);
}
}
stack.push(_perms);
}
var reciprocalKey = missingDigits(stack[0][0]),
key = stack[0][0].split("");
key.sort();
key = key.join("");
digitsHash[key] = {};
for (var i=0; i<stack[0].length; i++){
var mult = Number(stack[0][i].substr(0,3)) * Number(stack[0][i].substr(3,2));
digitsHash[key][mult] = stack[0][i];
if (digitsHash[reciprocalKey] && digitsHash[reciprocalKey][mult]){
console.log(stack[0][i].substr(0,3) + " * " + stack[0][i].substr(3,2)
+ ", " + digitsHash[reciprocalKey][mult].substr(0,3) + " * "
+ digitsHash[reciprocalKey][mult].substr(3,2));
}
}
}
var fives = choose([1,2,3,4,5,6,7,8,9,0],5);
for (var i=0; i<fives.length; i++){
permute(fives[i]);
}
12 seconds is too much for my taste. My C++ brute force attack took ~430ms without any heuristics or deep optimizations. Anyway you need to add some heuristics for example:
Bitwidth of multiplication result is around the sum of bitwidth of the operands.
So you need to test only the same bit width combinations of the results. for example if a*b are like this:
1xx * 9x dec = 1 xxxx xxxx * 1001 xxxx bin -> 17 bit
so test only c*d combinations that lead to 17 bit results too for example
4xx * 2x dec = 100 xxxx xxxx * 10 xxxx bin -> 17 bit
to make it more clear:
dec bin bits
0 0000 0
1 0001 1
2 0010 2
3 0011 2
4 0100 3
5 0101 3
6 0110 3
7 0111 3
8 1000 4
9 1001 4
If highest digit of a,b,c,d is a0,b0,c0,d0 then:
bits(a0)+bits(b0) = bits(c0)+bits(d0)
This will eliminate a lot of iterations. It is similar to subset sum problem. The speed up is from 2177280 iterations to 420480 iterations but also adds some overhead.
There are 126 ways to split 10 digits into 2 sets of 5 without duplicates. For each set of 5 digits, there are 120 ways (permutations) to arrange them into the form ab*cde, or 72 ways if the group contains zero and a leading zero is not allowed. That means a brute-force algorithm would need to check 126 × 120 × 72 = 1,088,640 possibilities.
However, for each pair of sets of 5 digits, if you generate the permutations in the order so that the resulting products are ordered from small to large, you can find the smallest difference of products in 120 + 72 = 192 steps (or fewer depending on how much the ranges overlap) instead of 120 × 72 = 8640. The maximum total becomes 24,192 instead of 1,088,640, which is 45 times less.
(In practice, only 12,574 product differences are calculated, and the first zero-difference result is found after 6679 steps).
You take the permutations with the smallest product for each set, calculate their difference, and store it if it is smaller than the minimum found so far. Then, you replace the permutation whose product is smallest by the next permutation in the list for that set (but stay on the same permutation for the other set) and calculate their difference, and so on, until you reach the end of one of the sets.
In the JavaScript code example below I'm using the product as the index of a sparse array (like a dictionary that can be read in order) to create an ordered list of permutations and their products (because I couldn't immediately find a simple way to generate them in order).
Array.prototype.remove = function() { // returns first element of sparse array
for (var key in this) {
if (!this.hasOwnProperty(key)) return false;
var value = this[key];
delete this[key];
return {prod: key, perm: value};
}
}
function NorwegianMath() {
var div = [1,1,1,1,1,0,0,0,0,0]; // which numbers 0-9 go in set 0 or 1
var result, min = 99999;
while (div[0]) { // keep zero in group 1 to avoid duplicates
var set = [[],[0]];
for (var i = 1; i < 10; i++) set[div[i]].push(i); // distribute over sets
var dict = [[],[]];
for (var i = 0; i < 2; i++) {
permute(set[i], dict[i]); // generate permutations for each set
}
var x = dict[0].remove(), y = dict[1].remove(); // start with smallest
while (x && y) {
var diff = Math.abs(x.prod - y.prod);
if (diff < min) {
result = {x: x.perm, y: y.perm, d: diff}; // store new minimum
/* if (diff == 0) return result */ // possible early exit here
min = diff;
}
if (x.prod < y.prod) x = dict[0].remove();
else y = dict[1].remove(); // replace smallest premutation with next
}
revLexi(div); // get next distribution into 2 sets of 5
}
return result;
function permute(s, dict) {// there are better permutation algorithms out there
for (var a = 0; a < 5; a++) {
if (s[a] == 0) continue;
for (var b = 0; b < 5; b++) {
if (a == b) continue;
for (var c = 0; c < 5; c++) {
if (a == c || b == c || s[c] == 0) continue;
for (var d = 0; d < 5; d++) {
if (a == d || b == d || c == d) continue;
for (var e = 0; e < 5; e++) {
if (a == e || b == e || c == e || d == e) continue;
var p = (s[a]*10 + s[b]) * (s[c]*100 + s[d]*10 + s[e]);
dict[p] = "" + s[a] + s[b] + "*" + s[c] + s[d] + s[e];
}
}
}
}
}
}
function revLexi(seq) { // next binary sequence (reverse lexicographical)
var max = true, pos = seq.length, set = 1;
while (pos-- && (max || !seq[pos])) if (seq[pos]) ++set; else max = false;
if (pos < 0) return false;
seq[pos] = 0;
while (++pos < seq.length) seq[pos] = set-- > 0 ? 1 : 0;
return true;
}
}
var result = NorwegianMath();
document.write("|" + result.x + " - " + result.y + "| = " + result.d);
As a heuristic you could compute the square root of 12345 (about 111) and go on from there, searching for the nearest values to 123 and 45 which you can create with the remaining numbers. I did not implement this but it could be a more intelligent approach.
Another example:
sqrt(36189) -> About 190
Remaining numbers: 24570
Try to find numbers close to 190 which you can create with these numbers. Such as 70 and 245. This should however be harder to implement.
Distance between 361 * 89 and 245 * 70: 14979

decode string algorithm implementation for advice

Working on below algorithm puzzle to decode a string containing numbers into characters. Post full problem statement and reference code. Actually I referred a few solutions, and it seems all solutions I found decode from back to the front, and I think decode from front to end should also be fine, just wondering if any special benefits or considerations why for this problem, it is better to decode from back to front? Thanks.
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).
The number of ways decoding "12" is 2.
public class Solution {
public int numDecodings(String s) {
int n = s.length();
if (n == 0) return 0;
int[] memo = new int[n+1];
memo[n] = 1;
memo[n-1] = s.charAt(n-1) != '0' ? 1 : 0;
for (int i = n - 2; i >= 0; i--)
if (s.charAt(i) == '0') continue;
else memo[i] = (Integer.parseInt(s.substring(i,i+2))<=26) ? memo[i+1]+memo[i+2] : memo[i+1];
return memo[0];
}
}
thanks in advance,
Lin
There will be no difference whether you decode the string from front-to-back or back-to-front if you break it into sub-strings and store their results.
This implements front-to-back approach:
def decode_string(st):
result_dict = {st[0]:1}
for i in xrange(2,len(st)+1):
if int(st[i-1]) == 0:
if int(st[i-2]) not in [1,2]:
return "Not possible to decode"
result_dict[st[:i]] = 0
else:
result_dict[st[:i]] = result_dict[st[:i-1]]
if int(st[i-2:i]) < 27 and st[i-2] != '0':
result_dict[st[:i]] = result_dict[st[:i]] + result_dict.get(st[:i-2],1)
return result_dict[st]
print decode_string("125312")
result_dict contains all the possibilities for incremental sub-strings. Initialize with first character
Special check for '0' character because the only acceptable values for 0 are 10 and 20. So break from the loop if input contains something else
Then for each index check whether the combination with the previous index is a character (combination < 27) or not. If true, add the result of string upto index-2 to it.
Store the result of each incremental sub-string in the dictionary
Result:
The result_dict contains values like this:
{'12': 2, '12531': 3, '1': 1, '125312': 6, '125': 3, '1253': 3}
So result_dict[st] gives the required answer
Using Lists is a better idea
def decode_string(st):
result_list = [1]
for i in xrange(2,len(st)+1):
if int(st[i-1]) == 0:
if int(st[i-2]) not in [1,2]:
return "Not possible to decode"
result_list.append(0)
else:
result_list.append(result_list[i-2])
if int(st[i-2:i]) < 27 and st[i-2] != '0':
if i>2:
result_list[i-1] = result_list[i-1] + result_list[i-3]
else:
result_list[i-1] = result_list[i-1] + 1
print result_list
return result_list[-1]
print decode_string("125312")

How to return all valid combinations of n-pairs of parentheses?

def paren(n):
lst = ['(' for x in range(n)]
current_string = ''.join(lst)
solutions = list()
for i in range(len(current_string)+1):
close(current_string, n, i, solutions)
return solutions
def close(current_string, num_close_parens, index, solutions):
"""close parentheses recursively"""
if num_close_parens == 0:
if current_string not in solutions:
solutions.append(current_string)
return
new_str = current_string[:index] + ')' + current_string[index:]
if num_close_parens and is_valid(new_str[:index+1]):
return close(new_str, num_close_parens-1, index+1, solutions)
else:
return close(current_string, num_close_parens, index+1, solutions)
def is_valid(part):
"""True if number of open parens >= number of close parens in given part"""
count_open = 0
count_close = 0
for paren in part:
if paren == '(':
count_open += 1
else:
count_close += 1
if count_open >= count_close:
return True
else:
return False
print paren(3)
The above code is my attempt at solving the stated problem. It gives sufficient solutions for n<3, but otherwise, it doesn't give out all the solutions. For example, when n=3, it outputs ['()()()', '(())()', '((()))'] leaving out '()(())'. How do I modify the code to output all the possible solutions correctly?
Here's a recursive generator that yields all valid solutions. Unlike the other answers, this one never calculates duplicated or invalid strings that need to be filtered out. This is pretty much the same algorithm as in this answer to a previous question, though it doesn't need a non-recursive helper function:
def paren(left, right=None):
if right is None:
right = left # allows calls with one argument
if left == right == 0: # base case
yield ""
else:
if left > 0:
for p in paren(left-1, right): # first recursion
yield "("+p
if right > left:
for p in paren(left, right-1): # second recursion
yield ")"+p
If it doesn't have to be done using recursion, this seems to work:
from itertools import permutations
def valid(test):
open, close = 0, 0
for c in test:
if c == '(':
open += 1
elif c == ')':
close += 1
if close > open:
return False
return True
def paren(n):
perms = set(''.join(p) for p in permutations('(' * n + ')' * n))
return [s for s in perms if valid(s)]
I am new to dynamic programming and recursion, but here is my solution without recursion. Please let me know why it wont work or if this is an acceptable solution:
class Parenthesis(object):
def __init__(self, parens):
self.parens = parens
self.my_valid_parens = {
1: ['()'],
2: ['()()', '(())']
}
def generate_valid_paren(self):
if self.parens <= 2:
return self.my_valid_parens[self.parens]
i = 3
while i <= self.parens:
new_set = []
for each in self.my_valid_parens[i-1]:
new_set += set([each + '()', '()' + each, '(' + each + ')'])
self.my_valid_parens[i] = list(new_set)
i += 1
if __name__ == '__main__':
num = 4
p = Parenthesis(num)
p.generate_valid_paren()
print p.my_valid_parens[num]
Here is my output for when num = 3 and 4 respectively:
3: ['(()())', '()()()', '()(())', '(())()', '((()))']
4: ['(()())()', '()(()())', '((()()))', '()()()()', '(()()())', '()()(())', '(()(()))', '()(())()', '((())())', '(())()()', '()(())()', '()((()))', '(((())))', '((()))()']
It seems that the task boils down to generating all possible trees with N+1 nodes. Let's assume another pair of parens around the whole string, then for N=3 all possible trees will be
o
|
o ((()))
|
o
|
o
o
/ \ (())()
o o
|
o
o
/ \
o o ()(())
|
o
o ()()()
/|\
o o o
I can't provide you with any code right now (hence CW), but refer to this paper - it seems to deal with this problem exactly.
Using recursion, and much for efficient than itertools.permutations:
def paren(n):
ps = set(['(' * n + ')' * n])
for i in range(1, n):
for a in paren(i):
for b in paren(n-i):
ps.add(a + b)
return ps
Because of the repeated recursion, it can also be made more efficient by using functools.lru_cache.
Or, with built-in memoization,
def paren(n, known={}):
if n in known:
return known[n]
ps = set(['(' * n + ')' * n])
for i in range(1, n):
for f in paren(i, known):
for s in paren(n-i, known):
ps.add(f + s)
known[n] = ps
return ps
For N==3, there are 5 valid combinations: ()()(), ((())), (()()), (())() and ()(()).
The recursive algorithm works like this:
Build the valid strings from left to right by adding either one left
or one right parentheses at a time.
Base case: all left and all right parentheses have been used (left ==
n && right == n). Just return an empty string. Otherwise:
Print a left parenthesis if not all of them have been used
(left < n), and invoke the sub-problem with (n, left + 1, right)
Print a right parentheses only if the number of used right
parentheses is less than the number of used left parentheses (right <
left). Invoke the sub-problem with (n, left, right + 1)
Here is the Java Code:
public static ArrayList<String> parentheses(int n, int left, int right) {
ArrayList<String> results = new ArrayList<String>();
if (left == n && right == n) {
results.add("");
}
if (left < n) {
ArrayList<String> subResults = parentheses(n, left + 1, right);
for (String subResult : subResults) {
String newResult = "(" + subResult;
results.add(newResult);
}
}
if (left > right) {
ArrayList<String> oldResults = parentheses(n, left, right + 1);
for (String oldResult : oldResults) {
String newResult = ")" + oldResult;
results.add(newResult);
}
}
return results;
}
At the end, invoke the recursive function with:
parentheses(n, 0, 0);
Here is my solution
from itertools import permutations
n = 3
input = ("( " * n) + (") " * n)
in_list = [f for f in input.split(" ") if f]
possible_combinations = list(permutations(in_list, n*2))
valid_list = []
def ret_valid(el):
num_open = num_close = 0
for val in el:
if val == "(":
num_open += 1
else:
num_close += 1
if num_close > num_open:
return False
return True
for el in possible_combinations:
if ret_valid(el):
if "".join(el) not in valid_list:
valid_list.append("".join(el))
print(", ".join(valid_list))

Categories

Resources