Maximum increasing subsequence - python

I am trying to solve the longest increasing subsequence problem using recursion.
My code below seems logical to me, but it is not correct.
Where the recursion is missing up with the problem in the code?
def max_increasing_subseq(seq):
if len(seq) == 1:
return 1
if not seq:
return 0
if is_increasing(seq):
return len(seq)
global_max = 0
for i in range(1, len(seq)):
new_seq = seq[:i] + seq[i + 1 :]
size = max_increasing_subseq(new_seq)
global_max = max(global_max, size)
return global_max
def is_increasing(s):
return s == sorted(s)
print(max_increasing_subseq([4, 18, 20, 10, 12, 15, 19])) # --> 5 Correct
print(max_increasing_subseq([12, 9, 2, 5, 4, 32, 90, 20])) # --> 3 Wrong, Correct= 6
print(max_increasing_subseq([42, 50, 51, 60, 55, 70, 4, 5, 70])) # --> 6 Wrong, Correct= 5

Related

For a given X print numbers according to the scheme

Write a function, which for a given h will print numbers according to the scheme:
every line begins with a number 2^(line_number), then next natural numbers are added, so that in each line there were as many numbers as the line number.
For example for h = 5 the expected output would be:
2
4,5
8,9,10
16,17,18,19
32,33,34,35,36
I was able only to do that:
def function():
h = 1
while h <= 5:
a = 2**h
h += 1
print(a)
return
function()
output:
2
4
8
16
32
It prints only the first numbers, no idea how to do it as required.
You can use range() to create a sequence of numbers starting from a with the desired length, and print that as the row.
def function():
for h in range(1, 6):
a = 2**h
row = range(a, a+h)
print(",".join(str(num) for num in row))
def func(val):
h=2
res = []
for i in range(1, val+1):
tmp =[h**i]
tmp +=[tmp[0]+j for j in range(1, i)]
res.append(tmp)
return res
sol = func(5)
print(sol, sep='\n')
#[[2], [4, 5], [8, 9, 10], [16, 17, 18, 19], [32, 33, 34, 35, 36]]
print(*sol, sep='\n')
"""
[2]
[4, 5]
[8, 9, 10]
[16, 17, 18, 19]
[32, 33, 34, 35, 36]
"""

bottom up dynamic programming

I was trying to write a dynamic programming that counts the number of ways in which the road can be paved by using stones that are 2, 3, 5 meters. When I put 2, it gave me an error and starting from 2 to 20, it was supposed to give an output of
1, 1, 1, 3, 2, 5, 6, 8, 14, 16, 27, 36, 51, 77, 103, 155, 216, 309,
448
My code gives this result when I start the input from 3. Did I misunderstand something here?
def waysRoad(n):
if n<0:
return 0
dp = [0] * (n+1)
dp[0] = 1
dp[1] = 0
for i in range(2, n):
sum = 0
if i >=2:
sum += dp[i-2]
if i >=3:
sum += dp[i-3]
if i >=5:
sum += dp[i-5]
dp[i] = sum
return dp[i]
To fill n-th list entry, you need to use loop limit n+1:
for i in range(2, n + 1):
also it is worth to change return to
return dp[n]

IndexError: list index out of range - throwing error in Python?

a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= []
for i in a:
if a[i] % 2 == 0 :
l.append(a[i])
The code above keeps throwing the error - "IndexError: list index out of range"
I cannot understand what to do ?
When you perform for i in a you are iterating over the elements of a, not the indices!
You are trying to access: a[1] and then a[4] and then a[9] and then a[16] -> Which is the one that is causing the IndexError.
If you want to iterate only over the indices try:
>>> for i in range(len(a)):
if a[i] % 2 == 0 :
l.append(a[i])
>>> print (l)
[4, 16, 36, 64, 100]
If you need both the value and index use for index, value in enumerate(a):.
When you are iterating over a, you are looking at the value rather than the position of that value in the list.
You could use just the value like so:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= []
for val in a:
if val % 2 == 0 :
l.append(val)
Or alternately, if you need both the position and the value then you can use the enumerate function, like so:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= []
for pos, val in enumerate(a):
if a[pos] % 2 == 0 :
l.append(a[pos])
There are some ways:
for e in a:
if e % 2 == 0 :
l.append(e)
or
for i in range(len(a)):
if a[i] % 2 == 0 :
l.append(a[i])
or
for i, e in enumerate(a):
if e % 2 == 0 :
l.append(e)
or
for i, e in enumerate(a):
if a[i] % 2 == 0 :
l.append(a[i])
You could use list comprehension for that:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l = [i for i in a if i%2 == 0]
print(l)
[4, 16, 36, 64, 100]
List comprehesions can be used to make it one-liner
l=[x for x in a if x%2==0]
And as stated in ather answers your problem is that you are using list item as its indexes.
You can use filter for your task:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
print filter(lambda x: x % 2 == 0, a)
as in other answers, i takes the values from a, which are [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
in the loop when i takes the value "16", a[i] will be out of range!! (16 > len(a))
for debugging i always suggest printing...
in this case if you print the value ofi in the loop, you will find the problem yourself
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= []
for i in a:
if a[i] % 2 == 0 :
l.append(a[i])
...
if a[1] % 2 == 0:
...
if a[4] % 2 == 0:
...
if a[9] % 2 == 0:
...
if a[16] % 2 == 0:
index error, because the biggest index is 9 in array a...
so u have to use this:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= []
for i in a:
if i % 2 == 0 :
l.append(i)
or this example:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= []
for i in a:
if i % 2 == 0 :
l.append(i)
or the 1 line solution:
a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
l= [x for x in a if x%2 == 0]

Peak finder in Python in O(log n) complexity

I'm completely new to Python, thus the question. I'm trying to solve a standard interview question, which is finding a peak in an array. A peak is defined as a number which is greater than it's left and right neighbor. I'm trying to find the largest such peak.
This is my code:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peak(arr))
def find_peak(arr):
return _find_peak(arr, 0, len(arr))
def _find_peak(arr, start, stop):
mid = (start + stop) // 2
if arr[mid] > arr[mid - 1] and arr[mid] > arr[mid + 1]:
return arr[mid]
elif arr[mid] < arr[mid - 1]:
_find_peak(arr, 0, mid - 1)
elif arr[mid] < arr[mid + 1]:
_find_peak(arr, mid + 1, stop)
if __name__ == '__main__':
main()
The output of this program is None, where as the expected output is 24. Any help appreciated.
Data
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
A one-liner:
One line should be enough:
max_peak = max(x2 for x1, x2, x3 in zip(arr, arr[1:], arr[2:]) if x1 < x2 > x3)
In a loop
Maybe easier to understand when you are new to Python:
peak = float('-inf')
for x1, x2, x3 in zip(arr, arr[1:], arr[2:]):
if x1 < x2 > x3:
peak = max(peak, x2)
print(peak)
Output:
24
All peaks
You can also use a one-liner to get all peaks:
>>> [x2 for x1, x2, x3 in zip(arr, arr[1:], arr[2:]) if x1 < x2 > x3]
[13, 24]
and get the greatest one with max() on the result.
Explanation
Let's have a look at some of the components of the solution. I am working with Python 3 here, as everybody should. ;)
You can slice lists.
>>> arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
This gives you all of the list but the first element:
>>> arr[1:]
[12, 13, 8, 2, 16, 24, 11, 5, 1]
Here its starts with element three:
>>> arr[2:]
[13, 8, 2, 16, 24, 11, 5, 1]
The zip() function zips multiple sequences together. To visualize what happens, you can convert the zip object into a list:
>>> list(zip(arr, arr[1:], arr[2:]))
[(7, 12, 13),
(12, 13, 8),
(13, 8, 2),
(8, 2, 16),
(2, 16, 24),
(16, 24, 11),
(24, 11, 5),
(11, 5, 1)]
Python supports tuple unpacking. This allows to assign individual names to all members of a tuple:
>>> x1, x2, x3 = (7, 12, 13)
>>> x1
7
>>> x2
12
>>> x3
13
Another nice feature is the comparison of more than two objects:
>>> 10 < 12 > 8
True
This is equivalent to:
>>> (10 < 12) and (12 > 8)
True
Python offers list comprehensions:
>>> [x * 2 for x in range(2, 6)]
[4, 6, 8, 10]
Generator expression work in a similar way but don't produce a list but an iterator and can be consumed without using lots of memory:
>>> sum(x * 2 for x in range(2, 6))
28
you are missing a return statement for your two elif cases
I think the 13 also is a peak (greater than 12 and 8).
Try this approach:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peaks(arr))
def find_peaks(arr):
return list(_search(arr))
def _search(arr):
last = len(arr) - 1
for i, e in enumerate(arr):
if not any((i > 0 and arr[i-1] > e, i < last and arr[i+1] > e)):
yield e
if __name__ == '__main__':
main()
If you don’t understand anything, ask!
Another approach – using only one function:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peaks(arr))
def find_peaks(arr):
last = len(arr) - 1
return [
e for i, e in enumerate(arr)
if not any((i > 0 and arr[i-1] > e, i < last and arr[i+1] > e))
]
if __name__ == '__main__':
main()
I don't think you can find a peak in O(log N) time, because by definition the items cannot be in order, and there is no way to predict the peaky-ness of any item in a list given other items, except that comparing item N with item N+1 is presumably reflexive - it tells you that either N or N+1 might be a peak. That gets you to N/2 compares, which must then be followed by N/2 more compares to check the other side of the peak.
Here's a local_maxima(iterable) function that you can use with max() to find peaks. It treats start/end elements as peaks if they are greater than their one neighbor.
data = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1, None, 2, None, 3, 4, None, 5, 1, None]
firstpeak = [12, 7, 9, 8]
lastpeak = [1, 2, 3, 4]
def local_maxima(it):
"""Find local maxima in iterable _it_. Compares with None using
`is (not) None`, and using operator `<`."""
peaking = False
last = None
for item in it:
# Deal with last item peaking
if peaking and (item is None or item < last):
yield last
peaking = False
elif item is None:
peaking = False
elif last is None or last < item:
peaking = True
else:
peaking = False
last = item
if peaking:
yield last
print([x for x in local_maxima(data)])
print("Highest:", max(local_maxima(data)))
print([x for x in local_maxima(firstpeak)])
print("Highest:", max(local_maxima(firstpeak)))
print([x for x in local_maxima(lastpeak)])
print("Highest:", max(local_maxima(lastpeak)))

Merge Sort in place for python (Cant find what is wrong)

I was reading about merge sort(In place) in my algorithm book (Intro to algorithms 3rd edition Cormen), and I decided to implement it in Python. The problem is that I can't find what I am doing wrong... I saw some code in C++, but even with that I can't fix it.
Here is my code:
def MERGE(A,start,mid,end):
L=[0]*(mid - start + 1)
for i in range(len(L) - 1):
L[i] = A[start+i]
L[len(L) - 1] = 100000 # centinel, (fix)
R=[0]*(end - mid + 2)
for j in range(len(R) - 1):
R[j] = A[mid+j]
R[len(R) - 1] = 100000
i = 0
j = 0
k = start
for l in range(k,end):
if(L[i] < R[j]):
A[l] = L[i]
i = i + 1
else:
A[k] = R[j]
j = j + 1
def mergeSort(A,p,r):
if p < r:
mid = int((p+r)/2)
mergeSort(A,p,mid)
mergeSort(A,mid+1,r)
MERGE(A,p,mid,r)
A = [20, 30, 15, 21, 42, 45, 31, 0, 9]
mergeSort(A,0,len(A)]
When I run the code I have some index problems:
File "myrealmerge.py", line 9, in MERGE
R[j] = A[mid+j]
IndexError: list index out of range
I know that this my be a "dumb question" and that there is some related post, but I tried the suggestions in there and It does not work for me...
Can anyone help me? T
Thanks!
This code works fine:
def MERGE(A,start,mid,end):
L = A[start:mid]
R = A[mid:end]
i = 0
j = 0
k = start
for l in range(k,end):
if j >= len(R) or (i < len(L) and L[i] < R[j]):
A[l] = L[i]
i = i + 1
else:
A[l] = R[j]
j = j + 1
def mergeSort(A,p,r):
if r - p > 1:
mid = int((p+r)/2)
mergeSort(A,p,mid)
mergeSort(A,mid,r)
MERGE(A,p,mid,r)
A = [20, 30, 21, 15, 42, 45, 31, 0, 9]
mergeSort(A,0,len(A))
print A
I tried to minimize the change from your code.
Good luck!
(Added)
You can check the dividing process by using this code.
def MERGE(A,start,mid,end):
# Do nothing
pass
def mergeSort(A,p,r):
if r - p > 1:
mid = int((p+r)/2)
print A[p:mid],A[mid:r]
mergeSort(A,p,mid)
mergeSort(A,mid,r)
MERGE(A,p,mid,r)
A = [20, 30, 21, 15, 42, 45, 31, 0, 9]
mergeSort(A,0,len(A))
The result is as follows:
[20, 30, 21, 15] [42, 45, 31, 0, 9]
[20, 30] [21, 15]
[20] [30]
[21] [15]
[42, 45] [31, 0, 9]
[42] [45]
[31] [0, 9]
[0] [9]
This is what we want. However, 'mid+1' makes invalid result. Here is the test code:
def MERGE(A,start,mid,end):
# Do nothing
pass
def mergeSort(A,p,r):
if r - p > 1:
mid = int((p+r)/2)
print A[p:mid],A[mid+1:r] # Changed
mergeSort(A,p,mid)
mergeSort(A,mid+1,r) # Changed
MERGE(A,p,mid,r)
A = [20, 30, 21, 15, 42, 45, 31, 0, 9]
mergeSort(A,0,len(A))
result:
[20, 30, 21, 15] [45, 31, 0, 9]
[20, 30] [15]
[20] []
[45, 31] [9]
[45] []
(Added)
Here is a code using 'mid+1':
# New indexing function that includes the right index.
def get_partial_list(origin_list, left_index, right_index): # Added
return origin_list[left_index:right_index+1]
def MERGE(A,start,mid,end):
L = get_partial_list(A,start,mid)
R = get_partial_list(A,mid+1,end)
i = 0
j = 0
k = start
for l in range(k,end+1): # changed
if j >= len(R) or (i < len(L) and L[i] < R[j]):
A[l] = L[i]
i = i + 1
else:
A[l] = R[j]
j = j + 1
def mergeSort(A,p,r):
if r - p > 0: # changed
mid = int((p+r)/2)
mergeSort(A,p,mid)
mergeSort(A,mid+1,r) # changed
MERGE(A,p,mid,r)
A = [20, 30, 21, 15, 42, 45, 31, 0, 9]
mergeSort(A,0,len(A)-1) # changed
print A
I've added new indexing function. Is this the code you expected?
The solutions provided by lancif and krishna Prasad dont not have space complexity O(1).
Here is algorithm in place merge sorting for Py3 with space complexity O(1).
The main function sort_imerge uses 2 auxiliary functions wmerge and wsort.
This solution based on C code that discussed on:
other SO topic and on good C implementation
Also you can find full Python code with doctests here
def sort_imerge(Seq, l=0, u=None):
""" Merge sorting, mutable input.
Input sequence changed in place.
Time: O(n * log n)
log n -- levels
n -- elements on each level must be merged
Space (additional): O(1)
input changed in place
Returns None
"""
u = len(Seq) if u is None else u
if u - l > 1:
m = l + (u - l) // 2
w = l + u - m
wsort(Seq, l, m, w)
while w - l > 2:
n = w
w = l + (n - l + 1) // 2
wsort(Seq, w, n, l)
wmerge(Seq, l, l + n - w, n, u, w)
n = w
while n > l: # fallback to insert sort
for m in range(n, u):
if Seq[m-1] > Seq[m]:
Seq[m-1], Seq[m] = Seq[m], Seq[m-1]
n -= 1
def wmerge(Seq, i, m, j, n, w):
"""Merge subarrays [i, m) and [j, n) into work area w.
All indexes point into Seq.
The space after w must be enough to fit both subarrays.
"""
while i < m and j < n:
if Seq[i] < Seq[j]:
Seq[i], Seq[w] = Seq[w], Seq[i]
i += 1
else:
Seq[j], Seq[w] = Seq[w], Seq[j]
j += 1
w += 1
while i < m:
Seq[i], Seq[w] = Seq[w], Seq[i]
i += 1
w += 1
while j < n:
Seq[j], Seq[w] = Seq[w], Seq[j]
j += 1
w += 1
def wsort(Seq, l, u, w):
"""Sort subarray [l, u) and put reuslt into work area w.
All indexes point into Seq.
"""
if u - l > 1:
m = l + (u - l) // 2
sort_imerge(Seq, l, m)
sort_imerge(Seq, m, u)
wmerge(Seq, l, m, m, u, w)
else:
while l < u:
Seq[l], Seq[w] = Seq[w], Seq[l]
l +=1
w +=1
Recursively split the array into left and right part and then merge it as per your requirements i.e ASC or DESC, Check the below code:
def merge_sort(a):
if len(a) <= 1:
return a
left = [];
right = [];
mid = len(a)/2
left = a[0:mid]
right = a[mid:(len(a))]
print left
print right
#exit()
left = merge_sort(left)
right = merge_sort(right)
return merge(left, right)
def merge(left, right):
result = []
while len(left) > 0 and len(right) > 0:
lv = left[0]
rv = right[0]
if lv <= rv:
result.append(lv)
left.pop(0)
else:
result.append(rv)
right.pop(0)
while len(left) > 0:
result.append(left.pop(0))
while len(right) > 0:
result.append(right.pop(0))
return result
A = [20, 30, 21, 15, 42, 45, 31, 0, 9]
print A
print merge_sort(A)
For understanding I have printed the intermediate partitioned array have a look into the output:
[20, 30, 21, 15, 42, 45, 31, 0, 9]
[20, 30, 21, 15]
[42, 45, 31, 0, 9]
[20, 30]
[21, 15]
[20]
[30]
[21]
[15]
[42, 45]
[31, 0, 9]
[42]
[45]
[31]
[0, 9]
[0]
[9]
[0, 9, 15, 20, 21, 30, 31, 42, 45]
Hope this will help you to understand the logic.

Categories

Resources