I came up with a DP algorithm to compute the maximum sum of non-consecutive elements of an array. I understand there are similar questions but none of them record the indices of the elements which make up the maximum sum.
Original algorithm:
def maxSum(arr) {
sum = [0]*len(arr);
sum_indices = []
for i in range(len(arr)):
if i==0:
sum[0] = arr[0];
else if(i==1) {
sum[1] = max(sum[0],arr[1]);
else
sum[i] = max(sum[i-2]+arr[i],sum[i-1]);
return sum[len(arr)-1];
Attempt at modification to return indices:
def maxSum(A):
n = len(A)
M = [0]*len(A)
M[0] = A[0]
I = [None]*len(A)
if A[0] > A[1]:
M[1] = A[0]
I[0] = True
I[1] = False
else:
M[1] = A[1]
I[0] = False
I[1] = True
for i in range(2, len(A)):
if M[i-1] > M[i-2] + A[i]:
M[i] = M[i-1]
I[i] = False
else:
M[i] = M[i-2] + A[i]
I[i] = True
I[i-1] = False
I[i-2] = True
indices = []
print(I)
for j in range(len(A)):
if I[j] == True:
indices.append(j)
return indices
For example, maxSum([1,2,3,8,9]) should return [1,3,9], but it returns [1, 2, 3, 9].
I have been trying to modify the DP algorithm to return the indices of the non-consecutive elements, but I have been struggling to do so. Is there some trick I'm missing?
If we can assume that arr has only nonnegative elements, then the following should work.
def max_sum(arr):
sum_and_ind= []
for i in range(len(arr)):
best = (arr[i], -1)
if 1 < i:
best = max(best, (sum_and_ind[i-2][0] + arr[i], i-2))
if 2 < i:
best = max(best, (sum_and_ind[i-3][0] + arr[i], i-3))
sum_and_ind.append(best)
if 0 == len(sum_and_ind):
return []
elif 1 == len(sum_and_ind):
return [0]
else:
best_i = None
if sum_and_ind[-1] > sum_and_ind[-2]:
best_i = len(sum_and_ind) - 1
else:
best_i = len(sum_and_ind) - 2
answer = []
while -1 < best_i:
answer.append(arr[best_i])
best_i = sum_and_ind[best_i][1]
return list(reversed(answer))
print(max_sum([1,2,3,8,9]))
I need to find out the first duplicated number in a list (the index of the second occurrence must be the smallest). Here is my code:
def firstDuplicate(a):
b = []
for i in range(len(a)):
for j in range(i+1, len(a)):
if a[i] == a[j]:
b.append(j)
if len(b) == 0:
return -1
else:
return a[min(b)]
for example if I have a = [2, 1, 3, 5, 3, 2], it should return 3, but it returns 2 instead.
I verified with this code:
a = [2, 1, 3, 5, 3, 2]
b = []
for i in range(len(a)):
for j in range(i+1, len(a)):
if a[i] == a[j]:
b.append(j)
print(b)
it turned out with the correct answer which is [5,4].
So I don't know what's wrong here. Can anybody help? Thanks!!
Here is the screenshots:
Everytime the condition a[i] == a[j] is met, you are returning and stoping the loop. Return after the loop is finished:
def firstDuplicate(a):
b = []
for i in range(len(a)):
for j in range(i+1, len(a)):
if a[i] == a[j]:
b.append(j)
if len(b) == 0:
return -1
else:
return a[min(b)]
print(firstDuplicate([2, 1, 3, 5, 3, 2]))
Out:
3
It seems you have written return condition inside for loop. So it returning on first iteraton. Try this
def firstDuplicate(a):
b = []
for i in range(len(a)):
for j in range(i+1, len(a)):
if a[i] == a[j]:
b.append(j)
if len(b) == 0:
return -1
else:
return a[min(b)]
I think we can identify duplicate with single iteration of array.
def first_duplicate(arr):
d = dict()
n = len(arr)
for i, v in enumerate(arr):
if v in d:
d[v] = i
else:
d[v] = n
# print(d)
return min(d, key=d.get)
arr = [2, 1, 3, 5, 3, 2]
print(first_duplicate(arr))
I am very new to Python and have been going through multiple tutorials to get better.
I have straggled with one difficult problem and found a solution. But it feels, works very newbie like. I think that I have tailored it to answer the specific question.
So the question is:
SUMMER OF '69: Return the sum of the numbers in the array, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.
summer_69([1, 3, 5]) --> 9
summer_69([4, 5, 6, 7, 8, 9]) --> 9
summer_69([2, 1, 6, 9, 11]) --> 14
My code to solve this is:
def summer_69(arr):
list1 = arr
summ = int()
for i in range(0, len(arr)):
if 6 in list1:
listOfRange = range(list1.index(6), list1.index(9) + 1)
for index in listOfRange:
print(listOfRange)
arr[index] = 0
if 6 != arr[i]:
summ += arr[i]
else:
continue
else:
summ += arr[i]
return summ
It is a very basic problem and I am very alerted that I have struggled with something like this already.
Short O(n) solution using an iterator and the in operator to search for (and thereby skip to) the 9 following each 6:
def summer_69(lst):
it = iter(lst)
return sum(x for x in it
if x != 6 or 9 not in it)
Less dense version:
def summer_69(lst):
it = iter(lst)
total = 0
for x in it:
if x == 6:
9 in it
else:
total += x
return total
Correctness check (random test cases) and benchmark (with [1] * 5000 + [6, 9] * 2500) along with the accepted answer's solution (which takes O(n2)):
30 out of 30 tests correct
303045 us 303714 us 304335 us 306007 us 309986 us summer_69_Accepted
444 us 446 us 464 us 478 us 527 us summer_69_Kelly1
442 us 448 us 453 us 465 us 500 us summer_69_Kelly2
Code (Try it online!):
from timeit import repeat
def summer_69_Accepted(lst):
copyoflist = lst[:] # makes shallow copy of list
while True:
if 6 not in copyoflist:
return sum(copyoflist)
indexof6 = copyoflist.index(6)
indexof9 = copyoflist.index(9, indexof6+1) # begin search for 9 after 6
del copyoflist[indexof6:indexof9+1]
def summer_69_Kelly1(lst):
it = iter(lst)
return sum(x for x in it
if x != 6 or 9 not in it)
def summer_69_Kelly2(lst):
it = iter(lst)
total = 0
for x in it:
if x == 6:
9 in it
else:
total += x
return total
funcs = summer_69_Accepted, summer_69_Kelly1, summer_69_Kelly2
from random import randrange, choices
def testcase():
def others():
return choices([0, 1, 2, 3, 4, 5, 7, 8], k=randrange(10))
lst = others()
for _ in range(10):
lst += [6, *others(), 9, *others()]
return lst
tests = correct = 0
for _ in range(10):
lst = testcase()
expect = funcs[0](lst.copy())
for func in funcs:
result = func(lst.copy())
correct += result == expect
tests += 1
print(correct, 'out of', tests, 'tests correct')
print()
lst = [1] * 5000 + [6, 9] * 2500
for func in funcs:
times = repeat(lambda: func(lst), number=1)
print(*('%6d us ' % (t * 1e6) for t in sorted(times)), func.__name__)
Here's how I'd do it, as a first cut:
def summer_69(series):
in_summer = False
cur_sum = 0
for v in series:
if in_summer:
if v == 9:
in_summer = False
else:
if v == 6:
in_summer = True
else:
cur_sum += v
return cur_sum
Here's a version that uses a more reusable pythonic idiom, a generator function, and is a little more compact (at the slight cost of an extra comparison):
def yield_non_summer(series):
in_summer = False
def stateful_summer_predicate(v):
nonlocal in_summer
if in_summer and v == 9:
in_summer = False
return True # 9 is still in summer
elif not in_summer and v == 6:
in_summer = True
return in_summer
return (v for v in series if not stateful_summer_predicate(v))
def summer_69(series):
return sum(yield_non_summer(series))
Or, in fewer lines:
def yield_non_summer(series):
in_summer = False
def stateful_summer_predicate(v):
nonlocal in_summer
in_summer = (in_summer or v == 6) and v != 9
return in_summer
return (v for v in series if not stateful_summer_predicate(v))
def summer_69(series):
return sum(yield_non_summer(series))
def summer_69(arr):
sum = 0
Flag = False
if 6 not in arr:
for num in arr:
sum = sum + num
return sum
else:
for num in arr:
if num != 6 and Flag == False:
sum = sum + num
elif num == 6:
Flag = True
continue
elif Flag == True and num != 9:
continue
elif num == 9:
Flag = False
return sum
A simple approach is to make a filter and sum the results.
Code
def filter_substring(seq, start, end):
"""Yield values outside a given substring."""
release = True
for x in seq:
if x == start:
release = False
elif x == end:
release = True
elif release:
yield x
def summer(seq):
"""Return the sum of certain values."""
return sum(filter_substring(seq, 6, 9))
Demo
assert 0 == summer([])
assert 6 == summer([1, 2, 3])
assert 6 == summer([1, 2, 3, 6, 8, 7, 9])
assert 9 == summer([1, 3, 5])
assert 8 == summer([3, 5, 6, 7, 8, 9])
assert 15 == summer([2, 1, 6, 9, 12])
assert 16 == summer([2, 1, 6, 9, 1, 6, 6, 120, 9, 9, 12])
Details
filter_substring()+
This is a generator function. It iterates the input sequence and only yields a value if the conditions are appropriate, i.e. when the release remains True.
>>> list(filter_substring("abcde", "c", "d"))
['a', 'b', 'e']
>>> list(filter_substring([0, 1, 2, 3, 10], 1, 3))
[0, 10]
summer()
Here we simply sum whatever filter_range() yields.
+Note: a substring is a contiguous subsequence; this may or may not include strings in Python.
Will work with indexes:
def summer_69(arr):
y = []
for x in arr:
if 6 in arr:
a = arr.index(6)
b = arr.index(9)
del arr[a:b+1]
y = arr
elif arr == []:
return "0"
else:
return sum(arr)
return sum(y)
print(summer_69([])) #0
print(summer_69([1, 3, 5])) #9
print(summer_69([4, 5, 6, 7, 8, 9])) #9
print(summer_69([2, 1, 6, 9, 11])) #14
print(summer_69([2, 1, 6, 9, 6, 11, 25, 36, 11, 9, 4, 6, 4, 6, 3, 9, 15])) #22
Something like this:
def summer_69(lst):
"""Return the sum of the numbers in the array,
except ignore sections of numbers starting with a 6 and extending to the next 9
(every 6 will be followed by at least one 9). Return 0 for no numbers
"""
if not lst:
return 0
else:
_sum = 0
active = True
for x in lst:
if active:
if x != 6:
_sum += x
else:
active = False
else:
if x == 9:
active = True
return _sum
print(summer_69([1, 3, 5]))
print(summer_69([4, 5, 6, 7, 8, 9]))
print(summer_69([2, 1, 6, 9, 11]))
output
9
9
14
def summer_69(arr):
if 6 in arr:
c=arr[arr.index(6):arr.index(9)+1]
for i in c:
arr.remove(i)
print(arr)
return sum(arr)
else:
return sum(arr)
summer_69([1,2,3,4,5,6,7,8,9,10,11,12])
This will work:
def summer_69(arr):
total = 0
add = True
for num in arr:
while add:
if num != 6:
total += num
break
else:
add = False
while not add:
if num != 9:
break
else:
add = True
break
return total
def summer_69(arr):
a = 0
for nums in arr:
if nums == 6:
for items in arr[arr.index(6):]:
a = a+ items
if items == 9:
break
return sum(arr)-a
def summer_69(arr):
x = arr.count(6)
y = arr.count(9)
# to decide number of iteration required for loop
z = min(x,y)
k = 0
while k < (z) :
m = arr.index(6)
n = arr.index(9)
del arr[m:(n+1)]
k = k + 1
print(arr)
return sum(arr)
This will work for summer_69 problem as well for filtering substring
def filter_substring(seq, start, end):
flag = False
for char in seq:
if char == start:
flag = True
continue
elif flag:
if char == end:
flag = False
else:
continue
else:
yield char
def summer_69(seq, start, end):
return sum(filter_substring(seq, start, end))
def print_substring(string, start, end):
return list(filter_substring(string, start, end))
Example ::
seq = [4, 5, 9, 6, 2, 9, 5, 6, 1, 9, 2]
print(summer_69(seq, start=6, end=9))
string = "abcdef"
print(print_substring(string, start='c', end='e'))
This is the probably best answer if you are a newbie. I have simplified it as much as i can. you only need to know enumerate, function, for loops , tuple unpacking,if/else statements and break function.So lets go straight to the answer.
def myfunc(a):
mylist=[]
sum1 = 0
for b,c in enumerate(a):
if c==6:
for d in a[:b]:
mylist.append(d)
for e,f in enumerate(a):
if f==9:
for j in a[e+1:]:
mylist.append(j)
for y in a:
if y==6:
break
else:
mylist.append(y)
for k in mylist:
sum1 = sum1+k
print(sum1)
myfunc([1,3,5])
For those interested, here is my solution for this problem:
def summer_69(arr):
skate = arr
guitar = []
for i in range(len(arr)):
if 6 in arr:
guitar = skate[skate.index(6):skate.index(9)+1]
return abs(sum(skate) - sum(guitar))
else:
return sum(skate)
Replace
list1.index(9)+1
by
list1.index(9,list1.index(6)+1)+1
in line 6.
This will start searching for a 9 after 6.
This is taken from a Udemy course.
Here is the official answer . . .
def summer_69(arr):
total = 0
add = True
for num in arr:
while add:
if num != 6:
total += num
break
else:
add = False
while not add:
if num != 9:
break
else:
add = True
break
return total
Jose Periera has this on Python 'zero to hero' course.
My own particular approach was this . . .
def summer_69(arr):
#first find out if 6 or 9 are in the list
if 6 in arr and 9 in arr:
#Then create a variable that stores the index location of the number 6
#and the number 9
sixer = arr.index(6)
niner = arr.index(9)
#now return the sum of the array minus the sum of the values between
#index of 6 and index of 9 inclusive (hence the plus 1)
#This way will ignore the case of a 9 appearring before a 6 too.
return sum(arr) - sum(arr[sixer:niner+1])
#Otherwise just return the sum of the array.
else:
return sum(arr)
Happy to accept criticism here. I'm learning Python myself and I'm undergoing an Msc in computer science and hoping to apply for jobs in the field soon, so your comments will help me :)
My approach was to sum the whole list and the part of the list that we want to ignore and subtract them at the end.
def summer_69(arr):
result=0
reduction =0
for i in range(0,len(arr)):
result+=arr[i]
if arr[i] == 6:
temp = arr[arr.index(6):arr.index(9)+1]
reduction = sum(temp)
return result - reduction
def summer69(a):
for z in a:
if z==6 and 9 in a:
x=a.index(6)
y=a.index(9)
del a[x:y+1]
t= sum(a)
else:
t=sum(a)
return t
Will always prefer short , clear and easy understandable solution.
def summer_69(arr):
if 9 in arr :
sum = 0
y = arr.index(9)
for i , l in enumerate(arr):
if l == 6:
del arr[i:y+1]
for i in range(len(arr)):
sum = sum + arr[i]
return sum
elif 9 not in arr:
sum = 0
for i in range(len(arr)):
sum = sum + arr[i]
return sum
def summer_69(mylist):
if 6 in mylist:
return sum(mylist) - sum(mylist[mylist.index(6):mylist.index(9)+1])
else:
return sum(mylist)
def summer_69(arr):
returner = []
if 6 and 9 in arr:
a = arr.index(6)
b = arr.index(9)
if a < b:
seq = arr[a:(b+1)]
for i in arr:
if i not in seq:
returner.append(i)
return (sum(returner))
elif a > b:
seq = arr[b:(a+1)]
for i in arr:
if i not in seq:
returner.append(i)
return (sum(returner))
elif 6 in arr:
a = arr.index(6)
seq = arr[a:]
for i in arr:
if i not in slicer:
returner.append(i)
return(sum(returner))
elif 9 in arr:
a = arr.index(9)
seq = arr[a:]
for i in arr:
if i not in slicer:
returner.append(i)
return(sum(returner))
elif arr == []:
return 0
else:
return (sum(arr))
Just learning Python too and this was what I came up with for it:
def myfunc(arr):
ignore_list = []
newlist = []
for i,v in enumerate(arr):
if v >= 6 and v <= 9:
ignore_list.append(i)
if i in ignore_list:
newlist.append(0)
else:
newlist.append(v)
return sum(newlist)
I'm trying to create a function that takes a list (a) and integer (x) as input and returns true if the list contains 3 elements that sum to the value of x. I'm getting a semantic error when I execute the code that I've written - please advise!
def sum_tri(a, x):
for i in range(len(a) - 1):
for j in range(i, len(a)):
for k in range(j, len(a)):
if a[i] + a[j] + a[k] == x:
return True
else:
return False
>>> a = [1, 5, 8, 2, 6, 55, 90]
>>> x = 103
>>> sum_tri(a, x)
False # However it should return True
You are returning False on the first failure, but you should do it only when all the options fail:
def sum_tri(a, x):
for i in range(len(a) - 1):
for j in range(i, len(a)):
for k in range(j, len(a)):
if a[i] + a[j] + a[k] == x:
return True
return False
a = [1, 5, 8, 2, 6, 55, 90]
x = 103
print sum_tri(a, x)
>>>True
Also you'll need to change the limits of your inner for loops from len(a) to len(a) - 1 or else you'll get:
a,x = [1,2,3],8
print sum_tri(a, x)
>>>True
because the 2nd and 3rd loops will accept the last element (3 in this case)...
The final function should look like:
def sum_tri(a, x):
for i in range(len(a) - 1):
for j in range(i, len(a) - 1):
for k in range(j, len(a) - 1):
if a[i] + a[j] + a[k] == x:
return True
return False