Related
Given an integer array A, I need to pick B elements from either left or right end of the array A to get maximum sum. If B = 4, then you can pick the first four elements or the last four elements or one from front and three from back etc.
Example input:
A = [5, -2, 3, 1, 2]
B = 3
The correct answer is 8 (by picking 5 from the left, and 1 and 2 from the right).
My code:
def solve(A, B):
n = len(A)
# track left most index and right most index i,j
i = 0
j = n-1
Sum = 0
B2 = B # B for looping and B2 for reference it
# Add element from front
for k in range(B):
Sum += A[k]
ans = Sum
# Add element from last
for _ in range(B2):
# Remove element from front
Sum -= A[i]
# Add element from last
Sum += A[j]
ans = max(ans, Sum)
return ans
But the answer I get is 6.
Solution
def max_bookend_sum(x, n):
bookends = x[-n:] + x[:n]
return max(sum(bookends[i : i + n]) for i in range(n + 1))
Explanation
Let n = 3 and take x,
>>> x = [4, 9, -7, 4, 0, 4, -9, -8, -6, 9]
Grab the "right" n elements, concatenate with the "left" n:
>>> bookends = x[-n:] + x[:n]
>>> bookends # last three elements from x, then first three
[-8, -6, 9, 4, 9, -7]
Take "sliding window" groups of n elements:
>>> [bookends[i : i + n] for i in range(n + 1)]
[[-8, -6, 9], [-6, 9, 4], [9, 4, 9], [4, 9, -7]]
Now, instead of producing the sublists sum them instead, and take the max:
>>> max(sum(bookends[i : i + n]) for i in range(n + 1))
22
For your large array A from the comments:
>>> max(sum(bookends[i : i + n]) for i in range(n + 1))
6253
Solution based on sum of the left and right slices:
Data = [-533, -666, -500, 169, 724, 478, 358, -38, -536, 705, -855, 281, -173, 961, -509, -5, 942, -173, 436, -609,
-396, 902, -847, -708, -618, 421, -284, 718, 895, 447, 726, -229, 538, 869, 912, 667, -701, 35, 894, -297, 811,
322, -667, 673, -336, 141, 711, -747, -132, 547, 644, -338, -243, -963, -141, -277, 741, 529, -222, -684,
35] # to avoid var shadowing
def solve(A, B):
m, ln = None, len(A)
for i in range(B):
r = -(B-i-1) # r is right index to slice
tmp = sum(A[0:i + 1]) + sum(A[r:]) if r < 0 else 0
m = tmp if m is None else max(m, tmp)
return m
print(solve(Data, 48)) # 6253
A recursive approach with comments.
def solve(A, B, start_i=0, end_i=None):
# set end_i to the index of last element
if end_i is None:
end_i = len(A) - 1
# base case 1: we have no more moves
if B == 0:
return 0
# base case 2: array only has two elemens
if end_i - start_i == 1:
return max(A)
# next, we need to choose whether to use one of our moves on
# the left side of the array or the right side. We compute both,
# then check which one is better.
# pick the left side to sum
sum_left = A[start_i] + solve(A, B - 1, start_i + 1, end_i)
# pick the right side to sum
sum_right = A[end_i] + solve(A, B - 1, start_i, end_i - 1)
# return the max of both options
return max(sum_left, sum_right)
arr = [5, -2, 3, 1, 2]
print(solve(arr, 3)) # prints 8
The idea is if we have this list:
[5, 1, 1, 8, 2, 10, -2]
Then the possible numbers for B=3 would be:
lhs = [5, 1, 1] # namely L[+0], L[+1], L[+2]
rhs = [2, 10, -2] # namely R[-3], R[-2], R[-1]
The possible combinations would be:
[5, 1, 1] # L[+0], L[+1], L[+2]
[5, 1, -2] # L[+0], L[+1], R[-1]
[5, 10, -2] # L[+0], R[-2], R[-1]
[2, 10, -2] # R[-3], R[-2], R[-1]
As you can see, we can easily perform forward and backward iterations which will start from all L (L[+0], L[+1], L[+2]), and then iteratively replacing the last element with an R (R[-1], then R[-2], then R[-3]) up until all are R (R[-3], then R[-2], then R[-1]).
def solve(A, B):
n = len(A)
max_sum = None
for lhs, rhs in zip(range(B, -1, -1), range(0, -(B+1), -1)):
combined = A[0:lhs] + (A[rhs:] if rhs < 0 else [])
combined_sum = sum(combined)
max_sum = combined_sum if max_sum is None else max(max_sum, combined_sum)
return max_sum
for A in [
[5, 1, 1, 8, 2, 10, -2],
[5, 6, 1, 8, 2, 10, -2],
[5, 6, 3, 8, 2, 10, -2],
]:
print(A)
print("\t1 =", solve(A, 1))
print("\t2 =", solve(A, 2))
print("\t3 =", solve(A, 3))
print("\t4 =", solve(A, 4))
Output
[5, 1, 1, 8, 2, 10, -2]
1 = 5
2 = 8
3 = 13
4 = 18
[5, 6, 1, 8, 2, 10, -2]
1 = 5
2 = 11
3 = 13
4 = 20
[5, 6, 3, 8, 2, 10, -2]
1 = 5
2 = 11
3 = 14
4 = 22
public int solve(int[] A, int B) {
int sum = 0;
int i = 0;
int n = A.length -1;
for (int k = 0; k < B; k++){
sum += A[k];
}
int ans = sum;
int B2 = B -1;
for (int j = n; j > n -B; j--){
sum -= A[B2];
sum += A[j];
ans = Math.max(ans, sum);
B2--;
}
return ans;
}
}
I have a list of n numbers. I want to divide the list into sub lists, such as the sub list consists of continuous increasing numbers or continuous decreasing numbers. Then take the product of each sub list's min value and it's length. Finally take the sum of all this product's
Input:
l = [1,2,6,4,2,3,1,8,9,7]
Output:
32
Details:
[1,2,6],[6,4,2],[2,3],[3,1],[1,8,9],[9,7]
(1*3) +(2*3) + (2*2)+(1*2)+(1*3)+ (7*2) = 32
Code so far:
n = 10
l = [1,2,6,4,2,3,1,8,9,7]
tot = 0
count = 0
inc=dec=False
min_val = 1001 # max value in list won't exceed 1000
for idx, e in enumerate(l):
if idx+1<=n:
if e > l[idx+1]:
count+=1
if min_val > l[idx+1]:
min_val=l[idx+1]
inc=True
dec=False
elif e < l[idx+1]:
count+=1
if min_val > e:
min_val=e
dec=True
# if not inc
inc=False
*Note: No Two adjacent value will be equal in the list.
Update-1:
itemp = [1001]
dtemp = [1001]
result=0
for e in l:
# if not itemp or not dtemp:
# itemp.append(e)
# dtemp.append(e)
if e > itemp[-1]:
if not dtemp:
itemp.append(e)
else:
result+=(min(dtemp)*(len(dtemp)-1))
dtemp=[1001]
itemp.append(e)
elif e < dtemp[-1]:
dtemp.append(e)
if not itemp:
dtemp.append(e)
else:
result+=(min(itemp)*(len(itemp)-1))
itemp=[1001]
dtemp.append(e)
print(result)
This results 0 as output. Can some one help?
l = [1,2,6,4,2,3,1,8,9,7]
local_max= [i for i in range(1, len(l)-1) if l[i-1]<l[i]>l[i+1]]
local_min= [i for i in range(1, len(l)-1) if l[i-1]>l[i]<l[i+1]]
idx= sorted(local_max+local_min +[0,len(l)-1])
idx_pairs = zip(idx[:-1],idx[1:])
sum(min(l[i_1],l[i_2])*(i_2+1-i_1) for i_1,i_2 in idx_pairs)
You could identify the breaking positions (peaks and bottoms) using zip to detect changes of increasing/decreasing values between each sequence of 3 elements. Then use these breaks to form the sub-lists and apply the calculation in a comprehension.
L = [1,2,6,4,2,3,1,8,9,7]
breaks = [i+1 for i,(a,b,c) in enumerate(zip(L,L[1:],L[2:])) if (a<b)==(b>c)]
subL = [ L[s:e+1] for s,e in zip([0]+breaks,breaks+[len(L)]) ]
result = sum(min(s)*len(s) for s in subL)
print(breaks) # [2, 4, 5, 6, 8] indices of peaks and bottoms
# [1,2,6,4,2,3,1,8,9,7]
# ^ ^ ^ ^ ^
# 0 1 2 3 4 5 6 7 8 9
print(subL) # [ [1, 2, 6], [6, 4, 2], [2, 3], [3, 1], [1, 8, 9], [9, 7]]
# 0..2+1 2..4+1 4..5+1 5..6+1 6..8+1 8..len(L)
# | | | | | | | | | | | |
# [0] | + [2, | 4, | 5, | 6, | 8] |
# [2, 4, 5, 6, 8] + [len(L)]
print(result) # 32
tot = start = m = n = 0
direc = -1
for n, x in enumerate(lis):
if n == 0:
m = x
else:
old = lis[n - 1]
if (x > old and direc == 0) or (x < old and direc == 1):
tot += m * (n - start)
start = n - 1
m = min(old, x)
direc ^= 1
else:
direc = 1 if x > old else 0
m = min(m, x)
ln = n - start + 1
if ln > 1:
tot += m * ln
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
def mergeSort(A, l, r):
if l < r:
mid = (l + r) // 2
mergeSort(A, l, mid)
mergeSort(A, mid + 1, r)
merge(A, l, mid, r)
def merge(arr, l, mid, r):
arr1 = []
arr2 = []
for i in range(mid):
arr1.append(arr[i])
for j in range(mid, r):
arr2.append(arr[j])
i = 0
j = 0
k = 0
while (i < len(arr1) and j < len(arr2)):
if arr1[i] < arr2[j]:
arr[k] = arr1[i]
i += 1
else:
arr[k] = arr2[j]
j += 1
k += 1
while i < len(arr1):
arr[k] = arr1[i]
i += 1
k += 1
while j < len(arr2):
arr[k] = arr2[j]
j += 1
k += 1
arr = [2, 9, 7, 6, 1, 8, 4, 3]
mergeSort(arr, 0, 8)
print(arr)
There's a slight mistake somewhere in the code that I'm not able to find
Please try to run this code on your machine with different test cases.
And Let me know what I'm doing wrong here.
I don't know why I'm getting an incorrect answer: [1, 2, 3, 4, 6, 8, 9, 7]
You have problems with indexes. You wrote code in C style.
Just use slices to fix your problem
Change definition (delete for loops for arr1 and arr2) for arr1 and arr2 to :
arr1 = arr[:mid]
arr2 = arr[mid:]
else:
arr[k] = arr2[j]
j += 1
k += 1
Change the place of
k += 1
To this:
else:
arr[k] = arr2[j]
j += 1
k += 1
Or this:
else:
arr[k] = arr2[j]
j += 1
k += 1
There are multiple problems in your code:
you pass the index of the first element to sort and the index once past the last element of the slice, but you wrote the function mergeSort with different semantics as you assume r to be the index to the last element of the slice.
similarly, merge expects the mid argument to be the start of the right half and you pass mid, which would be the index to the last element of the first half in your approach.
in the merge function, arr1 should be initialized with i varying from l to mid, with for i in range(l:mid):
furthermore, k must be initialized to l, not 0.
note that arr1 and arr2 could be initialized from simple slices of arr.
Here is a modified version:
def mergeSort(A, l, r):
if r - l > 1:
mid = (l + r) // 2
mergeSort(A, l, mid)
mergeSort(A, mid, r)
merge(A, l, mid, r)
def merge(arr, l, mid, r):
arr1 = arr[l : mid]
arr2 = arr[mid : r]
i = 0
j = 0
k = l
while (i < len(arr1) and j < len(arr2)):
if arr1[i] <= arr2[j]:
arr[k] = arr1[i]
i += 1
else:
arr[k] = arr2[j]
j += 1
k += 1
while i < len(arr1):
arr[k] = arr1[i]
i += 1
k += 1
while j < len(arr2):
arr[k] = arr2[j]
j += 1
k += 1
arr = [2, 9, 7, 6, 1, 8, 4, 3]
mergeSort(arr, 0, 8)
print(arr)
Output:
[1, 2, 3, 4, 6, 7, 8, 9]
My goal is to get all numbers between start and stop, inclusive. If the starting point exceeds a defined maximum (restart_point), it should start from 1 again
For example:
start = 4
stop = 8
restart_point = 12
result should be: [4, 5, 6, 7, 8]
start = 9
stop = 3
restart_point = 12
result should be: [9, 10, 11, 12, 1, 2, 3]
The following code works, but I find it a bit complicated. I would be happy about alternative solutions.
start = 10
stop = 3
restart_point = 12
if stop - start < 0:
difference = restart_point - start + stop
else:
difference = stop - start
numbers = []
r = 0
for i in range(difference + 1):
val = i + start
if val > restart_point:
r += 1
val = r
numbers.append(val)
print(numbers)
# result -> [10, 11, 12, 1, 2, 3]
From your simple examples, it appears that I can assume that both stop and start are between 1 and restart_point, inclusive. This makes it simple enough:
start, stop, restart_point = 10, 3, 12
if stop < start:
stop += restart_point
numbers = []
for i in range(start-1, stop):
val = i % restart_point + 1
numbers.append(val)
print(numbers)
Output:
[10, 11, 12, 1, 2, 3]
Remember to use mod if you need loop in number:
start = 9
stop = 3
restart_point = 12
while start % restart_point != stop:
print(start % restart_point)
start = start + 1
It's 0-index based but it is easy to modified into 1-index based. Leave it to you :)
[i for i in range(start, stop+1)] if start<stop else [i for i in range(start, restart_point+1)] + [i for i in range(1, stop+1)]
I think I would do something like this:
numbers = []
x = start
while x <= stop:
if x > restart_point:
x = 1
numbers.append(x)
x = x + 1
start = 9
stop = 3
restart_point = 12
l = []
if restart_point > stop:
l = l + [i for i in range(start,restart_point)] + [i for i in range(1, stop+1)]
else:
l = l + [i for i in range(start, stop+1)]
print(l)
Output:
(python37) C:\Users\Documents>py test.py
[9, 10, 11, 1, 2, 3]
Here it is:
start, stop, restart_point = (10, 3, 12)
x = list(range(start, 1 + min(stop, restart_point))) + \
list(range(start, 1 + (start>stop) * max(stop, restart_point))) + \
list(range(1, 1 + (start>stop) *stop))
print(x)
Output
[10, 11, 12, 1, 2, 3]
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.