For an interview question I made a roman to integer converter:
def romanToInt(self, s):
"""
:type s: str
:rtype: int
"""
mapping = {"I": 1, "V":5, "X":10, "L":50, "C":100, "D":500, "M":1000}
numeral_list = list(s)
num_list = [[mapping[i], -1] for i in numeral_list]
count = 0
i = 0
while(i < len(num_list) - 1):
if num_list[i] < num_list[i + 1]:
count += num_list[i + 1][0] - num_list[i][0]
num_list[i+1][1] = 1
num_list[i][1] = 1
i += 2
else:
count += num_list[i][0]
num_list[i][1] = 1
i += 1
if num_list[-1][1] == -1:
count += num_list[-1][0]
return count
As you can see I sometimes miss the last digit because I didn't want to get an index error. To avoid that I added an extra attribute that would check if the last element was checked or not (in cases where s[len(s)-2] < s[len(s)-1], s[len(s)-1] is checked, but if s[len(s)-2] > s[len(s)-1] then s[len(s)-1] is not checked.
Having an extra check and using extra space just for one element is highly erroneous. Where am I going wrong in my logic?
EDIT: Here was my code before
def romanToInt(self, s):
"""
:type s: str
:rtype: int
"""
mapping = {"I": 1, "V":5, "X":10, "L":50, "C":100, "D":500, "M":1000}
numeral_list = list(s)
num_list = [mapping[i] for i in numeral_list]
count = 0
i = 0
while(i < len(num_list)-1):
if num_list[i] < num_list[i + 1]:
count += num_list[i + 1] - num_list[i]
i += 2
else:
count += num_list[i]
i += 1
return count
It failed on several test cases since it did not count the last digit
What they are looking for before anything else is whether your code is easily readable and maintainable. That's more important than being right, in my opinion, although the interviewer may disagree -- so make it also correct.
Check for invalid inputs. What if they give a string like 'VXQIII'? Do you want to enforce any rules or are you okay with giving 'VVVVV' = 25?
Throw in a unit test or test function for bonus points.
You invent a complicated structure with mysterious code numbers instead of using a clearly named variable like 'has_been_counted'. This makes your code hard to read. Therefore all your code will be hard for other programmers to read and maintain. And when I say other programmers, I mean you, next week, when you can't remember why you did that.
Additionally, that seen flag is unnecessary. You already have an array index telling you what you have and have not seen.
Python specific:
For an interview use pep-8. You can figure out how strict they are about style later, but python people can be pickier about that than most languages.
Self is unused, and it's not shown as being a class member anyway. "print romanToInt('XCIV')" will raise an error.
Speaking of errors, Python people may appreciate catching invalid characters with a try..except around the mapping lookup, and then reraise as ValueError('Not a valid roman numeral'). Maybe a python person can comment on what exception type to use for that, but I think ValueError is the right one.
converting s to a list of characters is unnecessary. You can already iterate a string as a list of characters.
for letter in 'XCIV':
print letter
X
C
I
V
Related
I am trying to implement a solution to the 'n-parenthesis problem'
def gen_paren_pairs(n):
def gen_pairs(left_count, right_count, build_str, build_list=[]):
print(f'left count is:{left_count}, right count is:{right_count}, build string is:{build_str}')
if left_count == 0 and right_count == 0:
build_list.append(build_str)
print(build_list)
return build_list
if left_count > 0:
build_str += "("
gen_pairs(left_count - 1, right_count, build_str, build_list)
if left_count < right_count:
build_str += ")"
#print(f'left count is:{left_count}, right count is:{right_count}, build string is:{build_str}')
gen_pairs(left_count, right_count - 1, build_str, build_list)
in_str = ""
gen_pairs(n,n,in_str)
gen_paren_pairs(2)
It almost works but isn't quite there.
The code is supposed to generate a list of correctly nested brackets whose count matches the input 'n'
Here is the final contents of a list. Note that the last string starts with an unwanted left bracket.
['(())', '(()()']
Please advise.
Here's a less convoluted approach:
memory = {0:[""]}
def gp(n):
if n not in memory:
local_mem = []
for a in range(n):
part1s = list(gp(a))
for p2 in gp(n-1-a):
for p1 in part1s:
pat = "("+p1+")"+p2
local_mem.append(pat)
memory[n] = local_mem
return memory[n]
The idea is to take one pair of parentheses, go over all the ways to divide the remaining N-1 pairs between going inside that pair and going after it, find the set of patterns for each of those sizes, and make all of the combinations.
To eliminate redundant computation, we save the values returned for each input n, so if asked for the same n again, we can just look it up.
I am using Codelite to train myself as I just started learning Python. In the excercise "Smallest Positive Number", I used the code below and some test cases passed, but most of them not. How can I improve my code? (test cases like [1,2,3,4] and repetitive numbers like [5,6,2,4,6].
A = [2,1,-2,5,-6]
m = max(A)
temp = []
index = []
result = []
if m < 1:
print ("1")
elif len(A) == 1:
if A[0] == 1:
print("2")
else:
print("1")
else:
for i in range(len(A)):
if A[i] > 0:
temp.append(A[i])
temp.sort()
print(temp)
for j in range(len(temp)):
index.append(j+1)
if temp[j] != index[j]:
result.append(index[j])
print(min(result))
Thanks!
First you would want to store the smallest positive number. Start it at the first element of the list.
small_positive = A[0]
You would then want to iterate through the input
for number in A:
Then check if the number is positive. The easiest way is to see if it is greater then zero.
if number > 0:
After, check if the number is smaller then the current smallest. If so, overwrite it.
if number < small_positive:
small_positive = number
Lastly, you need to check if there were all negatives in the list. If small_positive is negative after the loop, there were no positives in the list.
if small_positive < 0:
return None
This is the easiest way to understand the solution, but there are many built in functions which are much simpler then this.
A = [2,-2,5,-6]
def small(a,b):
if a >= b: return b
else: return a
positive_list = [ele for ele in A if ele > 0]
res = min(positive_list)
if len(positive_list) == 0:
print("no positive number.")
else:
for i in range(len(positive_list)):
res = small(res, positive_list[i])
print(f"Smallest Positive number : {res}")
by this, yon can easily get a result.
For a start, this wouldn't work for the list [-42]:
m = max(A)
if m < 1:
print ("1")
There's no 1 anywhere in that given list so it should not be reported as the solution. Python would usually give you None in that scenario but the puzzle you've been set may have other ideas. It also wouldn't work with the list [] as max() will complain bitterly about the empty list.
You may think that one or both of those cases are unlikely but that's one of the things that makes the difference between a good coder and a not-so-good one. The former assume their users and testers are psychotic geniuses who know how to break code with near-zero effort :-)
To code it up by yourself, you can use the following pseudo-code(1) as a basis:
num_list = (some list of numbers)
min_pos = nothing
for num in num_list:
if num > 0 and (min_pos is nothing or num < min_pos): # >= ?
min_pos = num
print(min_pos)
Of course, if you're learning Python rather than learning programming, you should probably just use the facilities of the language, things will be much easier:
pos_list = [item for item in the_list if item > 0] # >= ?
min_pos = min(pos_list) if len(pos_list) > 0 else None
print(min_pos)
And, if you consider zero to be positive, make sure you use >= 0 instead of > 0, in both code blocks above where indicated.
Both of these snippets will successfully handle lists with no positive numbers, giving you a sentinel value (Python None or pseudo-code nothing).
(1) Yes, it looks a bit like Python but that's only because Python is the ultimate pseudo-code language :-)
I am trying to get the first capital letter in the string but I am getting an index out of range error I don't know if it is my base case for the recursion. Please can someone help me
This is my code:
def firstCapital(str, i):
if (str[i] == None):
return 0
if (str[i].isupper()):
return str[i]
return firstCapital(str, i + 1)
name = "geoRge"
res = firstCapital(name, 0)
if (res == 0):
print("No uppercase letter")
else:
print(res)
str[i] will raise this index out of range exception if i is greater or equal to the length of str. You should change your base case to:
if (i >= len(str)):
return 0
The line if (str[i] == None): doesn't do what you want it to do. This seems like it's trying to check if your index is off the end of the string, but strings in Python don't have None after the last real character. Rather, you get exactly the exception you describe when you try to index past the end.
Instead, you should be comparing i to len(str), which is the length of the string as a number. Since indexes start at zero, an index equal to len(str) is just past the end, so you probably want:
if i >= len(str):
return 0
I'd also double check if returning zero is what you want to do there. If you find a capital letter, you're returning it from your other conditional case. It's not always ideal to return different types in different situations, as it can be tricky for the caller to know what APIs they can use on the result. Returning an empty string, or None might make more sense than returning a number.
using str[i]==None will 'force' python to determine the value of str[i], which doesn't exist, thus the index out of range error. You can determine that you reached the end of the string using len(str) and i instead:
def firstCapital(str, i):
if i>len(str)-1: #Instead of str[i]==None
return 0
if str[i].isupper():
return str[i]
return firstCapital(str, i + 1)
input : ('Ali',0)
Output: 'A'
Input: ('lia',0)
Output:0
here is my code:
def string_match(a, b):
count = 0
if len(a) < 2 or len(b) < 2:
return 0
for i in range(len(a)):
if a[i:i+2] == b[i:i+2]:
count = count + 1
return count
And here are the results:
Correct me if I am wrong but, I see that it didn't work probably because the two string lengths are the same. If I were to change the for loop statement to:
for i in range(len(a)-1):
then it would work for all cases provided. But can someone explain to me why adding the -1 makes it work? Perhaps I'm comprehending how the for loop works in this case. And can someone tell me a more optimal way to write this because this is probably really bad code. Thank you!
But can someone explain to me why adding the -1 makes it work?
Observe:
test = 'food'
i = len(test) - 1
test[i:i+2] # produces 'd'
Using len(a) as your bound means that len(a) - 1 will be used as an i value, and therefore a slice is taken at the end of a that would extend past the end. In Python, such slices succeed, but produce fewer characters.
String slicing can return strings that are shorter than requested. In your first failing example that checks "abc" against "abc", in the third iteration of the for loop, both a[i:i+2] and b[i:i+2] are equal to "c", and therefore count is incremented.
Using range(len(a)-1) ensures that your loop stops before it gets to a slice that would be just one letter long.
Since the strings may be of different lengths, you want to iterate only up to the end of the shortest one. In addition, you're accessing i+2, so you only want i to iterate up to the index before the last item (otherwise you might get a false positive at the end of the string by going off the end and getting a single-character string).
def string_match(a: str, b: str) -> int:
return len([
a[i:i+2]
for i in range(min(len(a), len(b)) - 1)
if a[i:i+2] == b[i:i+2]
])
(You could also do this counting with a sum, but this makes it easy to get the actual matches as well!)
You can use this :
def string_match(a, b):
if len(a) < 2 or len(b) < 0:
return 0
subs = [a[i:i+2] for i in range(len(a)-1)]
occurence = list(map(lambda x: x in b, subs))
return occurence.count(True)
This is merge sort tweaked to count inversions. My code throws an odd error
(I'm implementing algos to learn python 3.x).
In line 11,
in merge_sort first_sorted_half, x = merge_sort(arr[:half])
[Previous line repeated 12 more times] ValueError: not enough values
to unpack (expected 2, got 1)
Even though I explicitly return two values? I'm new to python 3 so I'd like to understand exactly what's going on here, I can't seem to find a similar issue anywhere. A link to python docs for more on this would also be appreciated!
def merge_sort(arr):
if len(arr) <= 1:
return arr
half = int(len(arr)/2)
first_sorted_half, x = merge_sort(arr[:half])
second_sorted_half, y = merge_sort(arr[half:])
merged_halves, z = merge(first_sorted_half, second_sorted_half)
return merged_halves, x + y + z
def merge(first_half, second_half):
n = len(first_half) + len(second_half)
i = 0
j = 0
split_inversions = 0
ans = []
for k in range(n):
if i >= len(first_half):
ans.append(second_half[j])
j += 1
continue
if j >= len(second_half):
ans.append(first_half[i])
i += 1
continue
if first_half[i] > second_half[j]:
ans.append(second_half[j])
j += 1
split_inversions += len(first_half) - i
elif first_half[i] < second_half[j]:
ans.append(first_half[i])
i += 1
return ans, split_inversions
numbers = [3,2,1,4,5,6,8,10,9]
print(merge_sort(numbers))
The error you are getting says that your program executed that recursive call 12 times, and at the end it couldn't unpack the result.
What that means is, python expects you to return two values from merge_sort, because you unpack the result into first_sorted_half and x. However, when you return only arr from the condition len(arr) <=1, there is no value to unpack, only there exists the array.
So how you fix that is returning a value for the base case, like return arr, len(arr).
Whilst ilke444 is right - a bit more clarification is needed. To start: returning data variables is what you need but I do not know much about the len(arr) <=1 , and I am quite new to stackflow, I do not know this feature of Python 3. I specialize in Pygame/ standard packages.
First thing - arr in this "Code Snippet" (If it is) is not defined; and/or will need to be defined. Len stands for length as you know - and uses a quote (' ') to use it.
Like so:
len('arr')
would print:
3
because there are 3 Characters in this set. You are obviously new to python 3 as you said because the syntax is slightly different.
As this probably only solves the first bit - with this info I will leave you with 1 thing more.
Call to print requires a quote (' '),
Lists have [ ] Brackets instead of (),
Dictionaries have {} brackets and variables now require definition either by variable definition or function unless put in quote marks.
Thanks,
Jerry