Longest Common Subsequence of Three Sequences - python

I've implemented my version of Longest Common Subsequence of Three Sequences and cannot find a mistake. But Coursera grader says that I fail last test case.
It means that the algorithm is almost corrects but outputs a wrong answer in a specific case. But what case is it?
Constraints: length of the list is not less than one and not bigger than 100. Numbers in the lists are integers from -10^9 to 10^9.
import sys
def lcs3(a, b, c):
start_b = 0
start_c = 0
result = []
for i in range(len(a)):
for j in range(start_b, len(b)):
if a[i] == b[j]:
for k in range(start_c, len(c)):
if b[j] == c[k]:
start_b = j+1
start_c = k+1
result.append(a[i])
break
if b[j] == c[k]:
break
return len(result)
def lcs3_reversed(a,b, c):
# check reversed sequence which can be with different order
a_rev = a[::-1]
b_rev = b[::-1]
c_rev = c[::-1]
result = lcs3(a, b, c)
result_reversed = lcs3(a_rev, b_rev, c_rev)
if result == result_reversed:
return result
else:
return result_reversed
if __name__ == '__main__':
input = sys.stdin.read()
data = list(map(int, input.split()))
an = data[0]
data = data[1:]
a = data[:an]
data = data[an:]
bn = data[0]
data = data[1:]
b = data[:bn]
data = data[bn:]
cn = data[0]
data = data[1:]
c = data[:cn]
print(lcs3_reversed(a, b, c))
Update: added the function lcs3_reversed to solve the cases described by you. Anyway cannot pass the test case.
Output should contain the length of common subsequence. For example, for input:
3
1 2 3
3
2 1 3
3
1 3 5
output is 2 because the common part is (1, 3) for these 3 lists.
Runtime for failed case is 0.04 seconds and it looks like that the lists are rather long since most of my own tests worked much faster.
Thanks for your help!
Update2: I've tried another version. First we find the Longest Common Subsequence of 2 lists and then use it again on our result and the 3-rd list.
def lcs2(a, b):
start_b = 0
result = []
for i in range(len(a)):
for j in range(start_b, len(b)):
if a[i] == b[j]:
start_b = j+1
result.append(a[i])
break
return result
def lcs2_reversed(a, b):
# check reversed sequence which can be with different order
a_rev = a[::-1]
b_rev = b[::-1]
result_reversed = lcs2(a_rev, b_rev)[::-1]
return result_reversed
def lcs3_reversed(a, b, c):
lcs2_str = lcs2(a, b)
lcs2_rev = lcs2_reversed(a, b)
lcs3_str_str = lcs2(lcs2_str, c)
lcs3_rev_rev = lcs2_reversed(lcs2_rev, c)
lenghts = [len(lcs3_str_str), len(lcs3_rev_rev)]
return max(lenghts)
if __name__ == '__main__':
an = input()
a = input().split()
bn = input()
b = input().split()
cn = input()
c = input().split()
print(max(lcs3_reversed(a, b, c), lcs3_reversed(a, c, b), lcs3_reversed(b, a, c),
lcs3_reversed(b, c, a), lcs3_reversed(c, a, b), lcs3_reversed(c, b, a)))
Moreover, I tried all the combinations of orders but it did not help... Again I cannot pass this last test case.

Your example breaks with something like:
a = [1,2,7,3,7]
b = [2,1,2,3,7]
c = [1,2,3,1,7]
The sequence should be [1,2,3,7] (if I understand the exercise correctly), but the problem is that the last element of a gets matched to the last elements of b and c, which means that start_b and start_c are set to the last elements and therefore the loops are over.

Related

Find the difference between two strings of uneven length in python

a = 'abcdfjghij'
b = 'abcdfjghi'
Output : j
def diff(a, b):
string=''
for val in a:
if val not in b:
string=val
return string
a = 'abcdfjghij'
b = 'abcdfjghi'
print(diff(a,b))
This code returns an empty string.
Any solution for this?
collections.Counter from the standard library can be used to model multi-sets, so it keeps track of repeated elements. It's a subclass of dict which is performant and extends its functionality for counting purposes. To find differences between two strings you can mimic a symmetric difference between sets.
from collections import Counter
a = 'abcdfjghij'
b = 'abcdfjghi'
ca = Counter(a)
cb = Counter(b)
diff = (cb-ca)+(ca-cb) # symmetric difference
print(diff)
#Counter({'j': 1})
Its hard to know exactly what you want based on your question. Like should
'abc'
'efg'
return 'abc' or 'efg' or is there always just going to be one character added?
Here is a solution that accounts for multiple characters being different but still might not give your exact output.
def diff(a, b):
string = ''
if(len(a) >= len(b)):
longString = a
shortString = b
else:
longString = b
shortString = a
for i in range(len(longString)):
if(i >= len(shortString) or longString[i] != shortString[i]):
string += longString[i]
return string
a = 'abcdfjghij'
b = 'abcdfjghi'
print(diff(a,b))
if one string just has one character added and i could be anywhere in the string you could change
string += longString[i]
to
string = longString[i]
In your example, there are 2 differences between the 2 strings :
The letter g and j.
I tested your code and it returns g because all the other letters from are in b:
a = 'abcdfjghij'
b = 'abcdfjhi'
def diff(a, b):
string=''
for val in a:
if val not in b:
string=val
return string
print(diff(a,b))
updated
But you have j twice in a. So the first time it sees j it looks at b and sees a j, all good. For the second j it looks again and still sees a j, all good.
Are you wanting to check if each letter is the same as the other letter in the same sequence, then you should try this:
a = 'abcdfjghij'
b = 'abcdfjghi'
def diff(a, b):
if len(a)>len(b):
smallest_len = len(b)
for index, value in enumerate(a[:smallest_len]):
if a[index] != b[index]:
print(f'a value {a[index]} at index {index} does not match b value {b[index]}')
if len(a) == len(b):
pass
else:
print(f'Extra Values in A Are {a[smallest_len:]}')
else:
smallest_len = len(a)
for index, value in enumerate(b[:smallest_len]):
if a[index] != b[index]:
print(f'a value {a[index]} at index {index} does not match b value {b[index]}')
if len(a) == len(b):
pass
else:
print(f'Extra Values in B Are {b[smallest_len:]}')
diff(a, b)
if I understand correctyl your question is:
"given 2 strings of different length, how can I find the characters
that are different between them?"
So judging by your example, this implies you want either the characters that are only present in 1 of the strings and not on the other, or characters that might be repeated and which count is different in between the two strings.
Here's a simple solution (maybe not the most efficient one), but one that's short and does not require any extra packages:
**UPDATED: **
a = 'abcdfjghij'
b = 'abcdfjghi'
dict_a = dict( (char, a.count(char)) for char in a)
dict_b = dict( (char, b.count(char)) for char in b)
idx_longest = [dict_a, dict_b].index(max([dict_a, dict_b], key = len))
results = [ k for (k,v) in [dict_a, dict_b][idx_longest].items() if k not in [dict_a, dict_b][1-idx_longest].keys() or v!=[dict_a, dict_b][1-idx_longest][k] ]
print(results)
> ['j']
or you can try with other pair of strings such as
a = 'abcaa'
b = 'aaa'
print(results)
> ['b', 'c']
as 'a' is in both string an equal number of times.

How can I avoid getting Index error in the question sorting the output from a quadratic equation if the input is already sorted?

So I was trying this question on g4g:
https://practice.geeksforgeeks.org/problems/sort-the-given-array-after-applying-the-given-equation0304/1#
Here I am using the idea to get the minima/maxima of the quadratic
equation so that I can apply the merge process(which is using two
sorted arrays to make a single sorted array containing both the
elements) Here A0 and A<=0 is used to get the nature of the parabola,
opening upward or downward
I am facing error at out.append(A*arr[i]arr[i]+Barr[i]+C) as
indexerror, list out of range. I am sure if x = 0 or x = len(nums),
then I'll get into trouble, but I am not able to think anything
otherwise:
Some of the test cases are:
A = 1, B = 1, C = 1. N = 3 Arr[] = {1, 2, 3}
A = -1, B = 2, C = -1. N = 6 Arr[] = {-1, 0, 1, 2, 3, 4}
Here is my code for the same:
class Solution:
def sortArray(self, arr, n, A, B, C):
# Code here
#nums = arr[:]
#print(nums)
out = []
nums = []
for i in range(len(arr)):
nums.append(A*arr[i]*arr[i]+B*arr[i]+C)
x = -((B)//2*A)
#print(x)
i = x
j = x-1
#out = []
if i == 0:
return arr
if A>0:
while j>=0 and i<len(nums):
if A*arr[i]*arr[i]+B*arr[i]+C<=A*arr[j]*arr[j]+B*arr[j]+C:
out.append(A*arr[i]*arr[i]+B*arr[i]+C)
i+=1
else:
out.append(A*arr[j]*arr[j]+B*arr[j]+C)
j-=1
while i<len(nums):
#print(i)
out.append(A*arr[i]*arr[i]+B*arr[i]+C)
i+=1
while j>=0:
out.append(A*arr[j]*arr[j]+B*arr[j]+C)
j-=1
return out
elif A<=0:
i = 0
j = len(nums)-1
while j>=x and i<x:
if A*arr[i]*arr[i]+B*arr[i]+C<=A*arr[j]*arr[j]+B*arr[j]+C:
out.append(A*arr[i]*arr[i]+B*arr[i]+C)
i+=1
else:
out.append(A*arr[j]*arr[j]+B*arr[j]+C)
j-=1
while j>=x:
out.append(A*arr[j]*arr[j]+B*arr[j]+C)
j-=1
while i<x:
out.append(A*arr[i]*arr[i]+B*arr[i]+C)
i+=1
return out
#{
# Driver Code Starts
#Initial Template for Python 3
if __name__ == '__main__':
T=int(input())
for i in range(T):
a, b, c = input().split()
a = int(a)
b = int(b)
c = int(c)
n = int(input())
arr = list(map(int, input().split()))
ob = Solution()
ans = ob.sortArray(arr, n, a, b, c)
for each in ans:
print(each,end=" ")
print()
#} Driver Code Ends
Thanks in advance!
Always try to break such a problem down into small junks that makes it way easier for you to understand what is happening and find errors. Also, you don't need to define a class for this problem, when you can just use simple functions.
I don't want to give a finished code sample, because I guess you like to solve the problem yourself, so here is a boilerplate that may help you to solve it. The body of the two functions should not be longer than maybe 10 lines of code, so if you end up with more lines, you should reconsider. Good luck :)
def calculate_new_array(arr, a, b, c):
# calculate the resulting array out of the input values
# ...
# return resulting array
return result
def sort_array(arr):
# sort the array somehow
# ...
# return the sorted array
return sorted_arr
if __name__ == '__main__':
a, b, c = input().split()
a = int(a)
b = int(b)
c = int(c)
arr = list(map(int, input().split()))
new_array = calculate_new_array(arr, a, b, c)
sorted_array = sort_array(new_array)
print(sorted_array)
Small little spoiler: With python N is not that important.

Compare position and elements of 3 different lists

I'm trying to compare the position and elements of 3 different lists, to then save them in a new list, if at least 2 of the elements at the same position matched.
For Example:
a = [FF2, FF6, FC4]
b = [FB5, FB3, FC4]
c = [FF2, FB3, FM8]
Result = [FF2, FB3, FC4]
At the beginning I used the following code to compare 2 lists, and tried to adapt it for 3 lists, by adding an extra for loop after the for i1 and also adding an or to my if, but went horribly wrong (almost 10 times more values as expected as output).
for i, v in enumerate(a):
for i1, v1 in enumerate(b):
if (i==i1) & (v==v1):
Result.append(v)
This is my current approach, it's working fine, but I have no idea how can I append the matched value to my Result list.
Result = list(x for x, (xa, xb, xc) in enumerate(zip(a, b, c))
if xa == xb or xb == xc or xa == xc)
al = ['FF2', 'FF6', 'FC4']
bl = ['FB5', 'FB3', 'FC4']
cl = ['FF2', 'FB3', 'FM8']
res = []
for a,b,c in zip(al, bl, cl):
if a == b or b == c or c == a:
if a == b:
res.append(a)
elif b == c:
res.append(b)
elif c == a:
res.append(c)
print(res)
You can iterate through the 3 lists at the same time & append to the resulting list. Use zip()
You could avoid the issues you're having by eliminating the use of enumerate() and just using zip. We then check each unique element in each tuple created by zip and see if the count of that element is greater than 1. If so, we append this to our return list. The use of t.count() resolves the need for the untidy xa == xb or xb == xc or xa == xc condition & makes it easily extendable to n lists.
Code:
a = ['FF2', 'FF6', 'FC4']
b = ['FB5', 'FB3', 'FC4']
c = ['FF2', 'FB3', 'FM8']
r = [x for t in zip(a, b, c) for x in set(t) if t.count(x) > 1]
Output:
>>> r
['FF2', 'FB3', 'FC4']
You could do something like this,
a = ["FF2", "FF6", "FC4"]
b = ["FB5", "FB3", "FC4"]
c = ["FF2", "FB3", "FM8"]
result = []
for idx in range(len(a)):
if a[idx] == b[idx] or a[idx] == c[idx]:
result.append(a[idx])
elif b[idx] == c[idx]:
result.append(b[idx])
else:
pass
print(result)
the output will be,
['FF2', 'FB3', 'FC4']

How to write Fibonacci with generator without stop number

I went through Beginning Python fibonacci generator
How to write with out stop number where we want to stop.
My Code of FIbnocci is below
def Fibonnaci(n):
if n == 0:
return 0
if n == 1:
return 1
else:
return (Fibonnaci(n-1)+ Fibonnaci(n-2))
n = int(input())
print(Fibonnaci(n))
I wrote with yield statement but its infinite loop running
def fib(n):
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib(7)
Desired out >
13
You don't want to loop infinitely; you need to keep track of how many times you've performed an operation.
Hold the state of a counter in your loop while you generate elements. Keep going until count >= n.
def fib(n):
count = 0
a, b = 0, 1
while count < n:
yield a
a, b = b, a + b
count += 1
You can then leverage this in a list comprehension to get all of the values up to that Fibonacci number if you so desire.
[i for i in fib(10)]
The yield statement is used to iterate over some data, yielding one value at a time.
So: iterate over it
f = fib()
fibs = [next(f) for _ in range(7)]
fib_7 = fibs[-1]
note as you start with yield a you get a 0 as first number. so shift to yield b which will work as expected
n = int(input())
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b #swap the values, sum
def firstn(g, n):
for i in range(n):
yield g.__next__() # take the next value for the generator
t = (list(firstn(fibonacci(), n+1))) # Put in a list
print (t[-1]) #take the last element

Python sum of non duplicate int

I am given 3 int, a, b, c. I would like to find the sum of all three int provided that they are unique. If a, b, or c has the same values as any of the other values, then they don't count towards the sum.
Example 1:
a = 3, b = 3, c =3
sum = 0
Example 2
a = 1, b = 3, c =3
sum = 1
This is what I have done. Is there a more pythonic way of doing this without so many if else statements?
def lone_sum(a, b, c):
if a != b and b != c and a != c:
return a + b + c
elif a == b == c:
return 0
elif a == b:
return c
elif b == c:
return a
elif a == c:
return b
from collections import Counter
def lone_sum(a, b, c):
d = Counter([a, b, c])
return sum(k for k in d if d[k]==1)
Add any number of numbers:
def lone_sum(*L):
d = Counter(L)
return sum(k for k in d if d[k]==1)
Add numbers repeated exactly c times:
def rep_sum(c, *L):
d = Counter(L)
return sum(k for k in d if d[k]==c)
Add numbers repeated at most c times:
def rep_sum(c, *L):
d = Counter(L)
return sum(k for k in d if d[k]<=c)
... or if you're bored and want to get really creative:
def lone_sum(*L):
nums = set()
all_nums = set()
for num in L:
if num in nums:
nums.remove(num)
elif num not in all_nums:
all_nums.add(num)
nums.add(num)
return sum(nums)
Here is a good beginners way to solve it
def lone_sum(*args):
return sum(x for x in args if args.count(x) == 1)
The issue with this is that args.count is a hidden loop, so the calculation becomes O(n2)
This doesn't matter much if there are only ever 3 arguments - ie n == 3.
A longhand way to write the same thing is
def lone_sum(a, b, c):
args = (a, b, c)
s = 0
for x in args:
if args.count(x) == 1:
s += x
return s
Here I take a list of your numbers, call it x, and then select only those x[i] which are not present in a list which is x without x[i]. That is, it removes all numbers which have a duplicate.
def lone_sum(a, b, c):
x = [a,b,c]
x = [x[i] for i in range(len(x)) if x[i] not in [x[j] for j in range(len(x)) if j!=i]]
return sum(x)
So,
[x[j] for j in range(len(x)) if j!=i]
is basically a list of elements excluding x[i]. It takes all elements apart from ith. If x[i] is in this list, it means it is a duplicate and we need to remove it. That is,
x[i] not in [x[j] for j in range(len(x)) if j!=i]
I think a lot has already been said and done on this topic and there is not much that can be added. But I too have written a program that uses sets to go about this task which is a little different from the top answer. So if you still wish to see all possible programs then here you go. Hope it helps!
def lone_sum(x):
c = set(x)
for b in c:
x.remove(b)
for a in set(x):
if a in c:
c.remove(a)
return(sum(c))

Categories