I am trying to come up with a code for the valid parentheses problem (https://leetcode.com/problems/valid-parentheses/) but I am having trouble understanding the logic of this problem.
This is my pseudocode
Iterate over characters in the string.
Get the current element.
Check if current element is == next element.
if it is, return true, else return false.
This was my solution but it doesn't work.
class Solution(object):
def isValid(self,s):
# iterate through the index in the string
for i in range(0,len(s)-1)):
# if the current index is equal to the next index, return true
if(s[i] == s[i+1]):
return True
I asked this question earlier and got the feedback that my code looking for places where the same symbol appears twice in a way. Whereas, I want my code to match up pairs of brackets.
Could someone help me understand the logic of this problem?
Here's how I would approach it:
class Solution(object):
def isValid(self, s):
stack = []
for char in s:
if "(" == char:
stack.append(")")
elif "{" == char:
stack.append("}")
elif "[" == char:
stack.append("]")
elif not stack or stack.pop() != char:
return False
return not stack
def test_is_valid(s, expected):
result = is_valid(s)
print(repr(s), result)
assert result == expected
is_valid = Solution().isValid
test_is_valid("()", True)
test_is_valid("()[]{}", True)
test_is_valid("(]", False)
test_is_valid("", True)
test_is_valid("{", False)
test_is_valid("}", False)
test_is_valid("[{([])}]", True)
Output:
'()' True
'()[]{}' True
'(]' False
'' True
'{' False
'}' False
'[{([])}]' True
Related
I wrote a regex code which compares two strings. It recognises a special character '?' that allows zero or more instances of previous character. It works fine until there are two or more occasions of '?' in the string. And I can't make out why.
def single_character_string(a, b) -> "return True if characters match":
"""check if two characters match"""
if len(a) == 0:
return True
elif len(b) == 0:
return False
else:
if a == '.':
return True
else:
if a == b:
return True
else:
return False
def meta_question_result(temp):
if len(temp) >= 2:
if temp[1] == '?':
k_1 = temp.replace(temp[0: 2], '') # no char
k_2 = temp.replace(temp[1], '') # char
return k_1, k_2
def check_pair_by_pair(template, check_string) -> "Strings are of Equal length! " \
"return True if lines are identical":
"""check if two strings match symbol by symbol. template may be less than string, the opposite
is False"""
if not template: # exit from recursion
return True
if not check_string: # exit from recursion
return False
if meta_question_result(template):
t_1, t_2 = meta_question_result(template)
if single_character_string(t_1[0], check_string[0]):
return check_pair_by_pair(t_1[1:], check_string[1:])
if single_character_string(t_2[0], check_string[0]):
return check_pair_by_pair(t_2[1:], check_string[1:])
else:
return False
elif single_character_string(template[0], check_string[0]):
return check_pair_by_pair(template[1:], check_string[1:])
else:
return False
reg, st = input().split("|")
print(check_pair_by_pair(reg, st))
reg = "co?lou?r"
st = "colour"
gives True as expected,
reg = "co?lou?r"
st = "clor"
gives True as expected,
but...
reg = "co?lou?r"
st = "color"
gives False. I expected True.
Found the bag.
Replace method replaces all instances of '?'. So the second '?' was replaced also and program didn't see it.
I should add an argument 'count' to replace method that is equal to 1.
k_1 = temp.replace(temp[0: 2], '', 1) # no char
Given a string that contains only the following => ‘{‘, ‘}’, ‘(‘, ‘)’, ‘[’, ‘]’. At some places there is ‘X’ in place of any bracket. Determine whether by replacing all ‘X’s with appropriate bracket, is it possible to make a valid bracket sequence.
Examples:
Input : S = "{(X[X])}"
Output : Balanced
Input : S = "[{X}(X)]"
Output : Not balanced
I tried to work it out like this, and it works for examples above. But it doesn't work for all examples eg. (it should be balanced but it says it's not)
Input: S = "([X}])"
Output: Not balanced
I tried to work it out but i can't find a solution. Please help.
class Stack:
def __init__(self):
self.data = []
def insert(self, x):
self.data.append(x)
def empty(self):
return len(self.data) == 0
def remove(self):
if self.empty():
raise ValueError('Stack is empty.')
self.data.pop()
def top_element(self):
if self.empty():
raise ValueError('Stack is empty.')
return self.data[-1]
def is_matching(a, b):
if a == "(" and b == ")":
return True
elif a == "[" and b == "]":
return True
elif a == "{" and b == "}":
return True
elif a == "X":
return True
return False
def is_balanced(expression,elements=Stack(),ind=0):
if ind == len(expression):
return elements.empty()
pre_brackets = "([{"
post_brackets = ")]}"
char = expression[ind]
if char in pre_brackets:
elements.insert(char)
return is_balanced(expression,elements,ind+1)
elif char in post_brackets:
if elements.empty() :
return False
if not is_matching(elements.top_element(), char):
return False
elements.remove()
return is_balanced(expression,elements,ind+1)
elif char == "X":
temp = Stack()
temp.insert(char)
result = (is_balanced(expression,temp,ind+1))
if result:
return True
if elements.empty():
return False
elements.remove()
return is_balanced(expression,elements,ind+1)
expression = "([X}])"
if expression == "":
print("No brackets in expression!")
elif len(expression) % 2 != 0:
print("Not balanced")
elif is_balanced(expression):
print("Balanced")
else:
print("Not Balanced")
You can do it by recursively testing all possible replacements for an X:
def can_be_balanced(expr):
pairs = "{}[]()"
opening_brackets = pairs[::2]
closing_brackets = pairs[1::2]
closer = {o:c for o, c in zip(opening_brackets, closing_brackets)}
opener = {c:o for o, c in zip(opening_brackets, closing_brackets)}
stack = []
for item in expr:
if item in opening_brackets:
# we append opening brackets to the stack
stack.append(item)
elif item in closing_brackets:
if not stack or stack[-1] != opener[item]:
# the closing bracket doesn't match the top of the stack
return False
else:
# if it does, we remove the matching opening bracket
stack.pop()
elif item == 'X':
# X could be any of the opening brackets,
possible = list(opening_brackets)
if stack and stack[-1] in opening_brackets:
# or the closing bracket matching the top of the stack
possible.append(closer[stack[-1]])
for pos in possible:
# we replace this X, the first one remaining in expr
test_expr = expr.replace('X', pos, 1)
if can_be_balanced(test_expr):
# This is just in order to print the working solution we just found,
# you may remove these two lines
if not 'X' in test_expr:
print(test_expr)
return True
# None of the replacements for X gave a balanced expression
return False
else:
raise ValueError(f'Invalid item {item} in {expr}')
# The expression is balanced if and only if the stack ends up empty
return not stack
Testing on your sample data:
tests = [("[{X}(X)]", False),
("{(X[X])}", True),
("([X}])", True),
]
for test in tests:
print(test[0], ': should be', test[1])
print(can_be_balanced(test[0]))
print('-'*20)
correctly outputs (with the balanced expression in case it can be done):
[{X}(X)] : should be False
False
--------------------
{(X[X])} : should be True
{([[]])}
True
--------------------
([X}]) : should be True
([{}])
True
--------------------
Note that a major problem in your code is that you only test the end of the expression, starting at the position of the X. Beware also of the mutable default argument elements=Stack() that would leave you with the remnants of the previous call to the function instead of a fresh, empty Stack object.
I need to write a function that given a string with parenthesis and/or square brackets it is able to evaluate if they appear in the correct order. For example, in this string '([b])(aa)' you can see that every time a parenthesis or square bracket is open, it is closed in the correct position. However, a string like '[(a])' it is not closing the parenthesis or square brackets in the correct order as it should be '[(a)]'.
The function should return True or False depending on this correct position of both elements. I have tried the following code, but this logic seems to be infinite and it is not working if I have more than two parenthesis or square brackets opened.
def parenthesis(string):
for a in range(len(string)):
if string[a] == "(":
for b in range(a,len(string)):
if string[b] == "[":
for c in range(b,len(string)):
if string[c] == "]":
for d in range(c,len(string)):
if string[d] == ")":
return True
elif string[b] == ")":
return True
else:
return False
If I run the function over the string "([b])(aa)" it is returning false as output.
parenthesis("([b])(aa)")
How can I rewrite this function so it evaluates all the parenthesis and square brackets combinations properly?
If a right parenthesis is open before a left, you got -1 and return False
def is_balanced(string):
cnt = 0
for char in string:
if char == '(': cnt += 1
if char == ')': cnt -= 1
if cnt < 0: return False
return True if cnt == 0 else False
This is one of the stack implementations I know:
def is_balanced(s):
stack = []
for char in s:
if char == "(" or char == "{" or char == "[":
stack.append(char)
elif len(stack) <= 0:
return False
elif char == ")" and stack.pop() != "(":
return False
elif char == "]" and stack.pop() != "[":
return False
elif char == "}" and stack.pop() != "{":
return False
if len(stack) == 0:
return True
return False
This version is more DRY than the prior answer:
def is_balanced(parens: str) -> bool:
# Link: https://stackoverflow.com/a/73341167/
parens_map ={'(':')','{':'}','[':']'}
stack = []
for paren in parens:
if paren in parens_map: # is open
stack.append(paren)
elif paren in parens_map.values(): # is close
if (not stack) or (paren != parens_map[stack.pop()]):
return False
return not stack
This is my recursive function named find(text,substring) that will return the substring if the substring is inside the text or return an empty string if substring is not inside the text. Another function named is_string_there(text, string) to test the find function. The function will return True if the string is inside the text or False if the string is not inside the text.
Am I able to cancel out text index and substring index to remove the two (0,0) at the print coding area to reduce my code to make it simpler and easier to understand so i can teach my students
def find(text, substring, text_index, substring_index):
if text_index == len(text) and substring_index != len(substring):
return False
if substring_index == len(substring):
return True
if text[text_index] == substring[substring_index]:
return find(text, substring, text_index+1, substring_index+1)
return False
def oo(text, substring, text_index, substring_index):
if text_index == len(text):
return False
if text[text_index] == substring[substring_index]:
if find(text, substring, text_index, substring_index):
return True
else:
return oo(text, substring, text_index+1, substring_index)
return oo(text , substring, text_index+1, substring_index)
print(oo("I love pie", "pie",0,0))
print(oo("I love pie1", "pie1",0,0))
Well if you want to remove the indexes permanently from the print commands, you could just use a class. This way you can even create other functions to take user input etc and take advantage of class variables for readability. Not sure if if cases should in form if-elif-else though:
class test():
def __init__(self):
self.reset()
self.run()
def reset(self):
self.substring_index = 0 #instead of putting in function they are now class variables
self.text_index = 0
def run(self):#more stuff can be done here
print(self.oo("I love pie","pie"))
self.reset() #reset the class variables for each step
print(self.oo("I love pie1","pie1"))
def find(self,text, substring): #pretty much the same code just using class variables and class methods
if self.text_index == len(text) and self.substring_index != len(substring):
return False
elif self.substring_index == len(substring):
return True
elif text[self.text_index] == substring[self.substring_index]:
self.text_index +=1
self.substring_index +=1
return self.find(text, substring)
else:
return False
def oo(self,text, substring):
if self.text_index == len(text):
return False
elif text[self.text_index] == substring[self.substring_index]:
if self.find(text, substring):
return True
else:
self.text_index +=1
return oo(text, substring)
else:
self.text_index +=1
return self.oo(text , substring)
if __name__=='__main__':
test()
Although just for reference, a super simple way for the problem is actually:
def oo(text,substring):
if substring in text:
return True
else:
return False
AS mentioned in comments:
def oo(text,substring):
if text.find(substring) == 0:
return True
else:
return False
Returns 0 if exists in text, -1 if not.
Interesting expansion possible when considering uppercase or lowercase diffrences. 'A' != 'a'
In your code, you use oo() to check if a character matches, and then calls find() to check if the rest of the characters match. Instead of checking character-by-character, you could use the idea of checking string equality. In your oo() function, you can check if the substring is equal to a splice of the original text. This will reduce your code but will make your find() function obsolete, while still serving as a simple demonstration of recursion.
def oo(text, substring, index):
if index == len(text):
return False
start = index
end = start + len(substring)
if text[start:end] == substring:
return True
else:
return oo(text, substring, index+1)
print(oo("I love pie", "pie",0))
print(oo("I love pie1", "pie1",0))
print(oo("I love pie", "pie1",0))
print(oo("I love pie1", "pie",0))
print(oo("pie", "pie",0))
print(oo("pi", "pie1",0))
print(oo("pie1", "pie",1))
Output:
True
True
False
True
True
False
False
The Task:
Write a program that checks if a word supplied as the argument is an Isogram. An Isogram is a word in which no letter occurs more than once.
Create a method called is_isogram that takes one argument, a word to test if it's an isogram. This method should return a tuple of the word and a boolean indicating whether it is an isogram.
If the argument supplied is an empty string, return the argument and False: (argument, False). If the argument supplied is not a string, raise a TypeError with the message 'Argument should be a string'.
Example:
is_isogram("abolishment")
Expected result:
("abolishment", True)
The Visible test
from unittest import TestCase
class IsogramTestCases(TestCase):
def test_checks_for_isograms(self):
word = 'abolishment'
self.assertEqual(
is_isogram(word),
(word, True),
msg="Isogram word, '{}' not detected correctly".format(word)
)
def test_returns_false_for_nonisograms(self):
word = 'alphabet'
self.assertEqual(
is_isogram(word),
(word, False),
msg="Non isogram word, '{}' falsely detected".format(word)
)
def test_it_only_accepts_strings(self):
with self.assertRaises(TypeError) as context:
is_isogram(2)
self.assertEqual(
'Argument should be a string',
context.exception.message,
'String inputs allowed only'
)
My Solution:
def is_isogram(word):
if type(word) != str:
raise TypeError('Argument should be a string')
elif word == "":
return (word, False)
else:
word = word.lower()
for char in word:
if word.count(char) > 1:
return (word, False)
else:
return (word, True)
But it the function refuses to pass some hidden test: What is wrong with my solution? Is there another elegant way of writing this function?
I'm not sure your search should be case insensitive so perhaps you should remove word = word.lower(), but your main issue is return terminates the function so you current code needs to only return True after all tests have been conducted (i.e. outside of the loop):
for char in word:
if word.count(char) > 1:
return (word, False)
return (word, True)
Anyway, a better way is to use set() to remove all duplicates from your string and then compare the lengths; also use isinstance() to check if word is a string. You can use if w to check for empty strings . You don't need parentheses with return, the comma is enough to return a tuple:
def is_isogram(word):
if isinstance(word,str):
w = word.lower() # assuming you want a case in-sensitive search
return word, len(w) == len(set(w)) if w else False
else:
raise TypeError('Argument should be a string')
Examples:
is_isogram('abolishment')
# ('abolishment', True)
is_isogram('happy')
# ('happy', False)
is_isogram('')
# ('', False)
is_isogram(1)
# TypeError: Argument should be a string
I have tried in this way:
def isogram(n):
if not isinstance(n, str):
return n,False
elif len(n) < 1:
return n,False
n = n.lower()
if len(n) == len(set(n)):
return n,True
else:
return n,False
The second line checks if the input n is a string, if it isn't it returns False.
The line 4 checks if the length of the input is smaller than 1, in that case the input is empty and we cannot check if it is an isogram or not.
'n = n.lower()' in line 6 assures us that the input becomes a string with lowercase letters.
In line 7 we check if the length of the input is equal to the length of the set(n). The function set() converts a collection or a sequence or an iterator object into a set. For example: set('lists') returns {'s', 't', 'l', 'i'}, as you can see the letter 's' which appears twice in 'lists', does not appear in the set. This is useful to check if the length of the set is equal to the length of the input, if there is a letter which appears twice in the input the condition is False.
I hope this explanation makes the script clear.
def is_isogram(string):
if type(string) != str:
raise TypeError('Argument should be a string')
elif string == " ":
return (string, False)
else:
for i in string:
if string.count(i) > 1:
return (string, False)
return (string, True)
The reason for this
"But it the function refuses to pass some hidden test: What is wrong with my solution? Is there another elegant way of writing this function?"
i.e refuses to pass the tests is pretty simple.
elif word == "":
should be
elif word == " ":
as per the unit test
if argument==" " :
return(argument,False)
You are forgetting the whitespace. Hope this helps the next person who comes searching.
This works for me. If there are more than one digit it will be added to a new string. If this new string is empty the function will return True. Else False. Only " if word.count(char) > 1: " won´t do it. At least not for me.
def isagram (word):
if not isinstance(word, str):
return (False, word)
if not word:
return (False, word)
word.lower()
multi_char = ''
for char in word:
if word.count(char) > 1:
multi_char += char
return (False, word) if multi_char else (True, word)
Here is one way to solve the problem:
def is_isogram(argument):
word_seen=set()
if type(argument) != str:
raise TypeError('Argument should be a string')
if argument==" " :
return(argument,False)
argument.lower()
for letter in argument:
if letter in word_seen:
return(argument,False)
word_seen.add(letter)
return (argument,True)
Equivalently, I also tried the following to remove all spaces in strings:
def is_isogram(argument):
word_seen=set()
if type(argument) != str:
raise TypeError('Argument should be a string')
if argument==" " :
return(argument,False)
argument.lower()
argument = ''.join(argument.split())
for letter in argument:
if letter in word_seen:
return(argument,False)
word_seen.add(letter)
return (argument,True)
i solved it here:
def is_isogram(word):
for letter in word:
if word.count(letter) > 1:
return False
else:
return True
print is_isogram("Hello")
def is_Isogram(words):
cover_words = words.lower()
letter_list = []
for letter in cover_words:
if letter.isalpha():
if letter in letter_list:
return False
letter_list.append(letter)
return True
if __name__ == '__main__':
print(is_Isogram('Machine'))
print(is_Isogram('Geeks'))`
This is the last part of your suggested solution:
for char in word:
if word.count(char) > 1:
return (word, False)
else:
return (word, True)
return will end the function, hence the for loop will always exit after counting repetitions of the first letter and never check the other ones.
If your word has a first letter which is unique, the function will return True.
I believe this is a bug and this is my corrected suggestion:
for char in word:
if word.count(char) > 1:
return (word, False)
return (word, True)
import collections
def is_isogram(word):
if not isinstance(word, str):
raise TypeError('Argument should be a string')
most_common = collections.Counter(word).most_common(1)
if most_common:
char, freq = most_common[0]
return (word, freq == 1)
else:
return (word, False)
You just need an extra conditional statement to check if the characters in the word are solely alphabets (i.e. no numbers or symbols) whilst checking if the characters are repeated:
def is_isogram(word):
if type(word) != str:
raise TypeError("Argument should be a string")
if len(word) < 1:
return (word, False)
word = word.lower()
for char in word:
if word.count(char) > 1 or \
char not in "abcdefghijklmnopqrstuvwxyz": # this checks that the char is an alphabet
return (word, False)
return (word, True)
I guess this should help.
i found this correct
def is_isogram(word):
if type(word)!=str:
raise TypeError("Argument should be a String")
elif word.strip()=="":
return(word,False) else:
word =word.lower()
for char in word:
if word.count(char) >1:
return (word ,False)
else:
return(word ,True)