With suggestions, trail and errors; i have iterated the code. However, i still have query:
Current Result : [1, -1, 2, -3, 5, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
Expected & Accurate Result: [5, -3, 2, -1, 1, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
value has correct sequence. each value corresponds to the range value.
However, - value are reversed. (-1) position has 5 & (-5) position has 1. How do i solve it?
Also, if i try bi_fibonacci(5,10):
Ans: [0, 1, 1, 2, 3, 5] - it consider len of the range. irrespective of values.
I would like it to show: [8, 13, 21, 34, 55] - The actual answer.
How do i solve it?
Thanks in advance.
def bi_fibonacci(num1, num2):
a = 1
b = -1
for item in range(num1, num2+1):
if item < 0:
yield a
temp = a
a = b
b = temp - b
a = 0
b = 1
for item in range(num1,num2+1):
if item > -1:
yield a
temp = a
a = b
b = temp + b
fibo_seq = [x for x in bi_fibonacci(-8,8)]
print(fibo_seq)
print(len(fibo_seq))
First, I believe you need a stack for the negative fibonacci sequence. Either an explicit stack (e.g. a list) or an implicit one (i.e. recursion.) Second, you need to do careful bookkeeping on this problem. Consider these three cases:
sequence = bi_fibonacci(-10, -5)
sequence = bi_fibonacci(-10, 10)
sequence = bi_fibonacci(5, 10)
You want to handle all three correctly but without making any of them a special case. Below is my solution using an explicit stack
# ..., −8, 5, −3, 2, −1, 1, 0, 1, 1, 2, 3, 5, 8, ...
def bi_fibonacci(num1, num2):
n = -1
a = 1
b = 0
stack = []
while n >= num1:
if n <= num2:
stack.append(a)
a, b = b - a, a
n -= 1
if stack:
yield from reversed(stack)
n = 0
a = 0
b = 1
while n <= num2:
if n >= num1:
yield a
a, b = b, a + b
n += 1
sequence = bi_fibonacci(-10, -5)
print(*sequence, sep=', ')
sequence = bi_fibonacci(-10, 10)
print(*sequence, sep=', ')
sequence = bi_fibonacci(5, 10)
print(*sequence, sep=', ')
OUTPUT
> python3 test.py
-55, 34, -21, 13, -8, 5
-55, 34, -21, 13, -8, 5, -3, 2, -1, 1, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
5, 8, 13, 21, 34, 55
>
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 like this
tst = [1,3,4,6,8,22,24,25,26,67,68,70,72,0,0,0,0,0,0,0,4,5,6,36,38,36,31]
I want to group the elements from above list into separate groups/lists based on the difference between the consecutive elements in the list (differing by 1 or 2 or 3).
I have tried following code
def slice_when(predicate, iterable):
i, x, size = 0, 0, len(iterable)
while i < size-1:
if predicate(iterable[i], iterable[i+1]):
yield iterable[x:i+1]
x = i + 1
i += 1
yield iterable[x:size]
tst = [1,3,4,6,8,22,24,25,26,67,68,70,72,0,0,0,0,0,0,0,4,5,6,36,38,36,31]
slices = slice_when(lambda x,y: (y - x > 2), tst)
whola=(list(slices))
I got this results
[[1, 3, 4, 6, 8], [22, 24, 25, 26], [67, 68, 70, 72, 0, 0, 0, 0, 0, 0, 0], [4, 5, 6], [36, 38, 36, 31]]
In 3rd list it doesn't separate the sequence of zeros into another list. Any kind of help highly appreciate. Thank you
I guess this is what you want?
tst = [1,3,4,6,8,22,24,25,26,67,68,70,72,0,0,0,0,0,0,0,4,5,6,36,38,36,31]
slices = slice_when(lambda x,y: (abs(y - x) > 2), tst) # Use abs!
whola=(list(slices))
print(whola)
Given a range, range(101), I have known missing inputs from the sequence,
{ 8, 23, 56 }
In this range, the only significant numbers are the start and end, 0 and 100. Here's what my initialization looks like:
r = tuple(range(101))
init_start, init_end = r[0], r[-1]
missing = { 8, 23, 56 }
r = tuple(filter(lambda n: n not in missing, r))
Now here is where I get stuck. I don't know how to approach generating the sub-ranges where the holes are. The expected output here is 0, 7, 9, 22, 24, 55, and 57, 100. I could brute force it with the known missing values, but then it doesn't handle edge cases (what if I only have one value in the range?).
Edit
Someone posted a working solution for the "happy path" of the problem, but it misses edge cases:
how to handle sequentially missing values?
what if the start or end are in the missing values?
r = tuple(range(101))
init_start, init_end = r[0], r[-1]
missing = [8, 23, 56]
r = tuple(filter(lambda n: n not in missing, r))
def gen_ranges():
start = init_start
end = 0
for n in sorted(missing):
yield start
start = n + 1
end = n - 1
yield end
yield start
yield init_end
>>> list(gen_ranges())
[0, 7, 9, 22, 24, 55, 57, 100]
One solution using itertools.groupby():
holes = {8, 23, 56}
from itertools import groupby
def generate(holes, r=range(0, 101)):
for v, g in groupby(r, lambda k: k in holes):
if v is False:
l = [*g]
yield from (l[0], l[-1])
print(list(generate(holes)))
Prints:
[0, 7, 9, 22, 24, 55, 57, 100]
Other inputs:
holes = {8, 10, 56} # [0, 7, 9, 9, 11, 55, 57, 100]
holes = {8, 9, 56} # [0, 7, 10, 55, 57, 100]
EDIT (some explanation):
With itertools.groupby I'm making groups from the range() generator using the key function. Here is the key function k in holes (k is value from the range()). If the value returned from the key function changes, that means one consecutive group. I basically do this:
False [0, 1, 2, ... 5, 6, 7] # group 1 (Take first, last)
True [8, 9] # group 2
False [10, 11, ... 54, 55] # group 3 (Take first, last)
True [56] # group 4
False [57, 58, ... 99, 100] # group 5 (Take first, last)
I see a couple of issues:
You need to ensure the values in missing are sorted;
You're not outputting the last pair of values after you finish processing the values in missing
This should give the results you want (note I've added missing as a parameter to ease testing):
def gen_ranges(missing):
start = init_start
end = 0
for n in sorted(missing):
if n == start:
start = n + 1
continue
yield start
start = n + 1
end = n - 1
yield end
if start <= init_end:
yield start
yield init_end
print(list(gen_ranges({ 8, 9, 56 })))
print(list(gen_ranges({ 0 })))
print(list(gen_ranges({ 100 })))
print(list(gen_ranges({ 0, 100 })))
print(list(gen_ranges({ 1, 100 })))
print(list(gen_ranges({ 0, 99 })))
print(list(gen_ranges({ 0, 50, 100 })))
print(list(gen_ranges({ 0, 1, 50, 99, 100 })))
Output:
[0, 7, 10, 55, 57, 100]
[1, 100]
[0, 99]
[1, 99]
[0, 0, 2, 99]
[1, 98, 100, 100]
[1, 49, 51, 99]
[2, 49, 51, 98]
There's already a good accepted answer, but this was an interesting problem.
Here is my solution, which works with edge cases:
def gen_ranges(start, end, missing):
missing = sorted(missing + [start - 1, end + 1])
for num, value in enumerate(missing):
if value - missing[num - 1] > 1:
yield missing[num - 1] + 1
yield value - 1
print(list(gen_ranges(0, 100, [8, 23, 56]))) # [0, 7, 9, 22, 24, 55, 57, 100]
print(list(gen_ranges(0, 100, [5, 40, 50, 52, 93]))) # [0, 4, 6, 39, 41, 49, 51, 51, 53, 92, 94, 100]
print(list(gen_ranges(0, 100, [0, 50, 100]))) # [1, 49, 51, 99]
print(list(gen_ranges(0, 100, [0, 50, 51, 100]))) # [1, 49, 52, 99]
If I have an array, let's say: np.array([4,8,-2,9,6,0,3,-6]) and I would like to add the previous number to the next element, how do I do?
And every time the number 0 shows up the addition of elements 'restarts'.
An example with the above array, I should get the following output when I run the function:
stock = np.array([4,12,10,19,25,0,3,-3]) is the right output, if the above array is inserted in transactions.
def cumulativeStock(transactions):
# insert your code here
return stock
I can't think of a method to solving this problem. Any help would be very appreciated.
I believe you mean something like this?
z = np.array([4,8,-2,9,6,0,3,-6])
n = z == 0
[False False False False False True False False]
res = np.split(z,np.where(n))
[array([ 4, 8, -2, 9, 6]), array([ 0, 3, -6])]
res_total = [np.cumsum(x) for x in res]
[array([ 4, 12, 10, 19, 25]), array([ 0, 3, -3])]
np.concatenate(res_total)
[ 4 12 10 19 25 0 3 -3]
another vectorized solution:
import numpy as np
stock = np.array([4, 8, -2, 9, 6, 0, 3, -6])
breaks = stock == 0
tmp = np.cumsum(stock)
brval = numpy.diff(numpy.concatenate(([0], -tmp[breaks])))
stock[breaks] = brval
np.cumsum(stock)
# array([ 4, 12, 10, 19, 25, 0, 3, -3])
import numpy as np
stock = np.array([4, 12, 10, 19, 25, 0, 3, -3, 4, 12, 10, 0, 19, 25, 0, 3, -3])
def cumsum_stock(stock):
## Detect all Zero's first
zero_p = np.where(stock==0)[0]
## Create empty array to append final result
final_stock = np.empty(shape=[0, len(zero_p)])
for i in range(len(zero_p)):
## First Zero detection
if(i==0):
stock_first_part = np.cumsum(stock[:zero_p[0]])
stock_after_zero_part = np.cumsum(stock[zero_p[0]:zero_p[i+1]])
final_stock = np.append(final_stock, stock_first_part)
final_stock = np.append(final_stock, stock_after_zero_part)
## Last Zero detection
elif(i==(len(zero_p)-1)):
stock_last_part = np.cumsum(stock[zero_p[i]:])
final_stock = np.append(final_stock, stock_last_part, axis=0)
## Intermediate Zero detection
else:
intermediate_stock = np.cumsum(stock[zero_p[i]:zero_p[i+1]])
final_stock = np.append(final_stock, intermediate_stock, axis=0)
return(final_stock)
final_stock = cumsum_stock(stock).astype(int)
#Output
final_stock
Out[]: array([ 4, 16, 26, ..., 0, 3, 0])
final_stock.tolist()
Out[]: [4, 16, 26, 45, 70, 0, 3, 0, 4, 16, 26, 0, 19, 44, 0, 3, 0]
def cumulativeStock(transactions):
def accum(x):
acc=0
for i in x:
if i==0:
acc=0
acc+=i
yield acc
stock = np.array(list(accum(transactions)))
return stock
for your input np.array([4,8,-2,9,6,0,3,-6])
it returns
array([ 1, 3, 6, 9, 13, 0, 1, 3, 6])
I assume you mean you want to seperate the list at every zero?
from itertools import groupby
import numpy
def cumulativeStock(transactions):
#split list on item 0
groupby(transactions, lambda x: x == 0)
all_lists = [list(group) for k, group in groupby(transactions, lambda x: x == 0) if not k]
# cumulative the items
stock = []
for sep_list in all_lists:
for item in numpy.cumsum(sep_list):
stock.append(item)
return stock
print(cumulativeStock([4,8,-2,9,6,0,3,-6]))
Which will return:
[4, 12, 10, 19, 25, 3, -3]
Suppose I have a sequence of increasing numbers, and I want to find the length of longest arithmetic progression within the sequence. Longest arithmetic progression means an increasing sequence with common difference, such as [2, 4, 6, 8] or [3, 6, 9, 12].
For example,
for [5, 10, 14, 15, 17], [5, 10, 15] is the longest arithmetic progression, with length 3;
for [10, 12, 13, 20, 22, 23, 30], [10, 20, 30] is the longest arithmetic progression with length 3;
for [7, 10, 12, 13, 15, 20, 21], [10, 15, 20] or [7, 10, 13] are the longest arithmetic progressions with length 3.
This site
https://prismoskills.appspot.com/lessons/Dynamic_Programming/Chapter_22_-_Longest_arithmetic_progression.jsp
offers some insight into the problem, i.e. by looping around j and consider
every 3 elements. I intend to use this algorithm in Python, and my code is as follows:
def length_of_AP(L):
n = len(L)
Table = [[0 for _ in range(n)] for _ in range(n)]
length_of_AP = 2
# initialise the last column of the table as all i and (n-1) pairs have lenth 2
for i in range(n):
Table[i][n-1] =2
# loop around the list and i, k such that L[i] + L[k] = 2 * L[j]
for j in range(n - 2, 0, -1):
i = j - 1
k = j + 1
while i >= 0 and k < n:
difference = (L[i] + L[k]) - 2 * L[j]
if difference < 0:
k = k + 1
else:
if difference > 0:
i = i - 1
else:
Table[i][j] = Table[j][k] + 1
length_of_AP = max(length_of_AP, Table[i][j])
k = k + 1
i = i - 1
return length_of_AP
This function works fine with [1, 3, 4, 5, 7, 8, 9], but it doesn't work for [5, 10, 14, 15, 20, 25, 26, 27, 28, 30, 31], where I am supposed to get 6 but I got 4. I can see the reason being that 25, 26, 27, 28 inside the list may be a distracting factor for my function. How do I change my function so that it gives me the result desired.
Any help may be appreciated.
Following your link and running second sample, it looks like the code actually find proper LAP
5, 10, 15, 20, 25, 30,
but fails to find proper length. I didn't spend too much time analyzing the code but the piece
// Any 2-letter series is an AP
// Here we initialize only for the last column of lookup because
// all i and (n-1) pairs form an AP of size 2
for (int i=0; i<n; i++)
lookup[i][n-1] = 2;
looks suspicious to me. It seems that you need to initialize whole lookup table with 2 instead of just last column and if I do so, it starts to get correct length on your sample as well.
So get rid of the "initialise" loop and change your 3rd line to following code:
# initialise whole table with 2 as all (i, j) pairs have length 2
Table = [[2 for _ in range(n)] for _ in range(n)]
Moreover their
Sample Execution:
Max AP length = 6
3, 5, 7, 9, 11, 13, 15, 17,
Contains this bug as well and actually prints correct sequence only because of sheer luck. If I modify the sortedArr to
int sortedArr[] = new int[] {3, 4, 5, 7, 8, 9, 11, 13, 14, 15, 16, 17, 18, 112, 113, 114, 115, 116, 117, 118};
I get following output
Max AP length = 7
112, 113, 114, 115, 116, 117, 118,
which is obviously wrong as original 8-items long sequence 3, 5, 7, 9, 11, 13, 15, 17, is still there.
Did you try it?
Here's a quick brute force implementation, for small datasets it should run fast enough:
def gen(seq):
diff = ((b-a, a) for a, b in it.combinations(sorted(seq), 2))
for d, n in diff:
k = []
while n in seq:
k.append(n)
n += d
yield (d, k)
def arith(seq):
return max(gen(seq), key=lambda x: len(x[1]))
In [1]: arith([7, 10, 12, 13, 15, 20, 21])
Out[1]: (3, [7, 10, 13])
In [2]: %timeit arith([7, 10, 12, 13, 15, 20, 21])
10000 loops, best of 3: 23.6 µs per loop
In [3]: seq = {random.randrange(1000) for _ in range(100)}
In [4]: arith(seq)
Out[4]: (171, [229, 400, 571, 742, 913])
In [5]: %timeit arith(seq)
100 loops, best of 3: 3.79 ms per loop
In [6]: seq = {random.randrange(1000000) for _ in range(1000)}
In [7]: arith(seq)
Out[7]: (81261, [821349, 902610, 983871])
In [8]: %timeit arith(seq)
1 loop, best of 3: 434 ms per loop