I failed an interview earlier this morning on this question, and haven't been able to figure out why. Can anyone help me out?
An expression consisting of operands and binary operators can be written in Reverse Polish Notation (RPN) by writing both the operands followed by the operator. For example, 3 + (4 * 5) can be written as "3 4 5 * +".
You are given a string consisting of x's and *'s. x represents an operand and * represents a binary operator. It is easy to see that not all such strings represent valid RPN expressions. For example, the "x*x" is not a valid RPN expression, while "xx*" and "xxx**" are valid expressions. What is the minimum number of insert, delete and replace operations needed to convert the given string into a valid RPN expression?
5
x
xx*
xxx**
*xx
xx*xx**
OUTPUT
0
0
0
2
0
Code so far:
import fileinput
def solution (rpn):
xs = 0
numReplaces = 0
numDeletes = 0
numInserts = 0
for i in xrange(len(rpn)):
if rpn[i] == 'x':
xs += 1
elif rpn[i] == '*':
if xs > 1:
xs -= 1
elif xs == 1:
if numDeletes > 0:
numReplaces += 1
numDeletes -= 1
else:
if i == len(rpn)-1:
numInserts += 1
else:
numDeletes += 1
else:
if numDeletes > 1:
numDeletes -= 2
numReplaces += 2
else:
numDeletes += 1
while xs > 1:
if xs > 2:
numReplaces += 1
xs -= 2
if xs == 2:
numInserts += 1
xs -= 1
return numReplaces + numDeletes + numInserts
first = True
for line in fileinput.input():
if first:
numCases = int(line)
first = False
else:
print solution(line)
I think the way to start is that RPM evaluation can be performed easily by maintaining a stack of operands. For a valid input string, when you hit an operator, you pop the last two values off the stack, apply the operator and push the result back on to the stack.
Therefore, we need to find the value added by each of the "fixes":
Insert
Operand: you hit an operator, and there is only one item on the stack
Operator: You finish the string and there are multiple items left on the stack
Delete
Operand: you are at the end of the string. Adding operators will have the same result
Operator: there is only one item on the stack, adding an operand will have the same result. If the stack is empty, delete the operator
Replace
Operator -> operand: There is only one operand on the stack
Operand -> operator: Here be dragons. I believe that this will be useful only when you're out of operators, meaning the stack size is > 1; unfortunately, we don't know if these are direct operands or the result of operations, so we'll just add n-1 operators to condense the stack into a result.
I'm not 100% sure on these, but it sounds like any error condition can be handled by any of these, at equal cost, so:
def count_errors(input_):
def tokenize(input_):
''' for our purposes, each character is a token '''
for char in input_:
yield char
def is_operator(val):
return val == '*'
def is_operand(val):
return val == 'x'
stack = []
error = 0
for token in tokenize(input_):
if is_operand(token):
stack.append(token)
elif is_operator(token):
if len(stack) >= 2:
stack.pop()
stack.pop()
stack.append('x')
elif len(stack) == 1:
stack.pop()
stack.append('x')
errors += 1
else:
errors += 1
if len(stack):
return errors + len(stack) - 1
else:
return errors + 1
Related
I wrote a function:
# given a n x m grid return how many different ways there are to move from top left to
# bottom right by only being able to move right or down
def grid(n, m, memo = {}):
if f'{n},{m}' in memo:
return memo[f'{n},{m}']
if n == 1 and m == 1:
return 1
if n == 0 or m == 0:
return 0
memo[f'{n},{m}'] = grid(n,m-1,) + grid(n-1,m)
return grid(n,m-1,) + grid(n-1,m)
Recently I read a bit about short-circuiting in Python and I am trying to understand it further.
As I understand it does not provide any boost in runtime, just sort of syntax sugar.
For example:
1 < 2 < 3 # is True
1 < 2 and 2 < 3 # is also True
# hence
(1 < 2 < 3) == 1 < 2 and 2 < 3 # is True
I was wondering can I write my function with this kind of short-circuiting in my if statements?
I came up with this:
def grid(n, m, memo = {}):
if f'{n},{m}' in memo:
return memo[f'{n},{m}']
if (n or m) == 1:
return 1
if (n and m) == 0:
return 0
memo[f'{n},{m}'] = grid(n,m-1,) + grid(n-1,m)
return grid(n,m-1,) + grid(n-1,m)
Is there any smarter way of using the short-circuit here?
(1 < 2 < 3) is not short-circuiting - I think you misunderstood the meaning of the term. You are correct that it is merely syntax sugar - although it can produce some very weird results in obscure cases. (1 < 2 < 3) expands to (1 < 2) and (2 < 3) - the middle operand is copied to both and and is used for the joining operator.
Short circuiting occurs when python already knows the answer to a boolean expression, even before calculating both the inputs. For example
def false():
print("false")
return False
def true():
print("true")
return True
print(false() and true())
The output would be
false
False
Because when python sees False and, it already knows that the result is False (because and requires both operands to be True), so it doesn't bother running the second half of the line.
This real short circuiting does result in a performance boost, but since you can't turn off short circuiting, it doesn't really matter ¯\_(ツ)_/¯
if (n or m) == 1 is definitely not the same thing as if n == 1 or m == 1. The first if statement is equivalent to:
value = n
if not value:
value = m
if value == 1:
# do something:
Or expressed more succinctly:
if (n if n else m) == 1:
# do something
In other words, n or m only evaluates m if n is False (or 0 if n is an integer), otherwise the result of the expression is n.
What you want to avoid redundancy is:
if 1 in (n, m): # equivalent to: if 1 is either n or m:
Update: Demo
n = 4
m = 1
if (n or m) == 1:
print('if branch taken')
else:
print('else branch taken')
Prints:
else branch taken
if (n or m) == 1
evaluates to
if (<bool>) == 1 # e.g. if {True,False} == 1
which is probably not what you want, since it is essentially evaluating the truthiness of n or m.
Your existing code already captures the nature of short-circuiting;
if n == 1 and m == 1
will only evaluate the second argument m == 1 iff n == 1, or will otherwise short-circuit.
To your comment
As I understand it does not provide any boost in runtime, just sort of syntax suggar.
Well, actually it does provide a runtime boost if Python is able to skip evaluating what would otherwise be "expensive" conditions to evaluate because it is able to short-circuit early.
While practicing recursion I came across a question to reverse an integer using recursion. I tried to do the question without converting the integer into a string.
I was able to solve the question partially but the output would always come without any of the zeroes from the original input. Below is the code I came up with:
def reverseNumber(n):
if (n//10) == 0:
return n
lastDigit = n%10
ans = reverseNumber(n//10)
nod = 0
for i in str(ans):
nod += 1
return (10**nod)*lastDigit + ans
Upon inspection I could see that this was happening because when lastDigit is 0 it only returned the reversed integer from the recursive call i.e input 4230 will give 324.
But this also meant that all zeroes between the original input would also get removed as we went deeper in the recursive calls.
So please tell me how to modify this code so that zeroes in the original input are not removed while reversing.
You probably need just this:
def rev(n):
if n>0:
return str(n%10)+rev(n//10)
else:
return ''
reverseNumber should return an int and accept positive and negative numbers.
The simplest way to fix your code, without handling negative numbers, is:
def reverseNumber(n):
if n == 0:
return 0
lastDigit = n%10
n //= 10
return int(str(lastDigit) + str(reverseNumber(n))) if n else lastDigit
for test in (0, 123, 120):
print(test, reverseNumber(test))
Prints:
0 0
123 321
120 21
Yes! The reverse of 120 is 21 when you are dealing with int types as opposed to str types.
Another implementation that does handle negative numbers takes a whole different approach:
I have broken this out into two functions. Function rev is a generator function that assumes that it is being called with a positive, non-negative number and will recursively yield successive digits of the number in reverse. reverseNumber will join these numbers, convert to an int, adjust the sign and return the final result.
def reverseNumber(n):
def rev(n):
assert n >= 0
yield str(n % 10)
n //= 10
if n != 0:
yield from rev(n)
if n == 0: return 0 # special case
x = int(''.join(rev(abs(n))))
return x if n >= 0 else -x
tests = [0, 132, -132, 120]
for test in tests:
print(test, reverseNumber(test))
Prints:
0 0
132 231
-132 -231
120 21
For all non-negative n, when n < 10 it is a single digit and already the same as its reverse -
def reverse(n = 0):
if n < 10:
return str(n)
else
return str(n%10) + rev(n//10)
you can also try the following Python3 code. It will cover positive and negative integers to be reversed as integers - not as strings ...
x = int(input("What integer shall be reversed? "))
n = abs(x) # ... to handle negative integers
r = 0 # ... will hold the reversed int.
while n > 0: # Recursion part reversing int.
r = (r * 10) + (n % 10) # using '%' modulo
n = int(n / 10) # and a 'dirty way' to floor
if x < 0: # Turn result neg. if x was neg.
return (r * -1)
else:
return r # Keep result pos. if x was pos.
This approach will leave your zeros in the middle of the integer intact, though it will make any zero at the end of the initial number vanish - rightfully so as integers do not start with a zero. ;))
I have string with only + and -, plus increases some variable, minus respectively decreases it. I should check if variable will be less than 0 or greater than N during processing any symbol of input string.
For example I have input:
N = 10
string = "+++++++++---+-+-+"
Output:
True
Input:
N = 3
string = "+-+-+-++-+++--"
Output:
False
Python solution is:
def check(string, N):
accumulator = 0
for ch in string:
if ch == '+':
accumulator += 1
elif ch == '-':
accumulator -= 1
if accumulator < 0 or accumulator > N:
return False
return True
But I need to implement this using ONLY regular expressions, like this:
def check(string, N):
regex = r'^$' # <-- regex is here
return bool(re.match(regex, string))
Any ideas?
You can add any operator(including parentheses and + - * / ** ) between 9 8 7 6 5 4 3 2 1.
For example,
98*76-5432*1=2016
9*8*7*(6+5-4-3)*(2-1)=2016
I wrote a programme like this
from __future__ import division
s = ['+','-','*','/','','(',')']
def calc(s):
a=s.split()
return eval(''.join(a))
a=['','9','','8','','7','','6','','5','','4','','3','','2','','1.','']
def test(tmp):
if tmp == 20:
try:
z = eval(''.join(a))
if z == 2016:
print ''.join(a)
except:
pass
return
for i in s:
#print a
a[tmp] = i
test(tmp+2)
for j in s:
a[0] = j
test(2)
But it is not right, because there can be multiple operators exist between numbers.
There's a well known trick to questions that involve constructing arithmetic expressions with brackets: often it's easier to use reverse polish notation instead.
Here's code that does this.
# Compute "a op b", returning None if the result
# is no good (eg: 9/0 or too big).
def do_op(a, op, b):
if op == '+':
return a + b
if op == '-':
return a - b
if op == '*':
return a * b
if op == '/':
if b == 0 or a % b != 0:
return None
return a // b
if op == '**':
# Disallow arguments that would result
# in fractions or huge numbers, being careful
# to allow valid results.
if a == 1:
return a
if a == -1:
return -1 if b % 2 else 1
if a == 0 and b == 0:
return None
if b < 0 or b > 20 or a > 10000 or a < -10000:
return None
return a ** b
assert False
# Generates expressions that result in the given target.
# ops is the a record of the operations applied so far,
# stack is the evaluation stack, and num is the first
# digit that we've not pushed yet.
def sums(ops, stack, num, target):
if not num and len(stack) == 1:
if stack[0] == target:
yield ops
return
# If num is 7, say, try pushing 7, 76, 765, 7654, ..., 7654321.
k = num
for i in xrange(num, 0, -1):
for s in sums(ops + [k], stack + [k], i-1, target):
yield s
k = 10 * k + (i - 1)
# If we've less that 2 things on the stack, we can't apply
# any operations.
if len(stack) < 2:
return
# Try each of the possible ops in turn.
for op in ['+', '-', '*', '/', '**']:
result = do_op(stack[-2], op, stack[-1])
if result is None:
continue
for s in sums(ops + [op], stack[:-2] + [result], num, target):
yield s
# Convert a list of operations that represent an expression in RPN
# into infix notation. Every operation is bracketed, even when
# that's redundant.
def to_infix(ops):
stack = []
for p in ops:
if isinstance(p, int):
stack = stack + [p]
else:
stack = stack[:-2] + ['(%s%s%s)' % (stack[-2], p, stack[-1])]
assert len(stack) == 1
return stack[0]
# Starting with an empty stack (and no operations), with 9 as the first
# unused digit, generate all expressions that evaluate to 2016.
for s in sums([], [], 9, 2016):
print to_infix(s)
It takes a few minutes to run, but there's a lot (more than 25000) of valid expressions that evaluate to 2016.
My favorite is (((98*76)-5432)*1).
I dont understand why this is out of range if I initialize j.
This expansion iterates all preceding characters of a slash, and when combined with a space, it is multiplied.
ie
5</ --> 5<5<
5<// --> 5<5<5<
5</ / --> 5<5< 5<5<
Also, is this the best way to accomplish my task?
def ttExpand( program ) :
"""
expand the string manipulation symbols in program into
a TinyTurtle language program.
program -- a TinyTurtle string, possibly with string manipulation symbols
Returns -- a TinyTurtle string after expansion
"""
new_program = ''
array = []
i = 0
j = 0
for ch in program: #while program.index(ch) != len(program) - 1:
if ch == '/':
array.append(program.index(ch))
i += 1
if len(array) == 0:
return program
while j <= len(array):
new_program += (program[:array[j]])
j += 1
return new_program
This doesn't produce the correct result, but it does do what you're trying to do:
#while j <= len(array):
for i in array:
new_program += program[:i] #(program[:array[j]])
It would appear that this approach actually accomplishes what you want:
def tt_expand(program):
'''
expand string manip symbols
Example:
>>> tt_expand('5</')
'5<5<'
>>> tt_expand('5<//')
'5<5<5<'
>>> tt_expand('5</ /')
'5<5< 5<5<'
'''
seen = ''
new_program = ''
prev_token = None
for i, token in enumerate(program):
if token == '/':
if prev_token == ' ':
new_program += new_program.rstrip()
else:
new_program += seen
else:
new_program += token
seen += token
prev_token = token
return new_program
if __name__ == '__main__':
import doctest
doctest.testmod()
The immediate cause is using while j <= len(array): then indexing array with j; sequences have indices starting at 0 and ending len(array) - 1 (usually described as being from 0 (inclusive) to len(array) (exclusive)).
The simple fix that preserves the majority of your code is to change to while j < len(array) so you stop at the last available index in array. That said, you're coding like you've just come from C, indexing instead of iterating.
If you ever find yourself with a loop that is structured like:
i = 0
while i < len(someseq):
item = someseq[i] # or equivalent, where you only use the value retrieved by indexing, not the index itself
what you really want is:
for item in someseq:
In rare cases, you might also need the index (when assigning back to the original sequence) in which case you'd do:
for i, item in enumerate(someseq):
Either of those is markedly faster and simpler than reinventing C-style for loops (rechecking the length on each pass and indexing adds a surprising amount of overhead compared to iterating directly).
You have to do:
while j <= len(array) - 1