How to find maximum sum in array less than N - python

I have array of M elements. I should find maximum sum of my array, which is less than integer number "N". All the elements in array are positive integers bigger or equal to zero. Also, sum can be non-consistent.
FOR example:
let's say M is = [1,2,3,6,0, 8, 9, 12] and N = 20, so here the answer is 20
but if M = [1,5,4,6] and N = 13, the answer is 12 - the maximum sum of array which is less than N

Problem: Find max sum from weights array, within maxCapacity
Approach: Problem is same as 0/1 Knapsack.
0/1 Knapsack problem:
Given: maxCapacity (int), weights (array) and values (array).
Find: max "value" by choosing items with total weight within
maxCapacity.
In this question:
Given: maxCapacity (int) and weights (array).
Find: max "weight" by choosing items with total weight within
maxCapacity.
Difference:
So unlike knapsack we have to maximise weight
instead of values. Thus, weight array will work as values array here.
def func(weights, maxCapacity):
knapsack = [[0 for i in range(len(weights) + 1)] for j in range(maxCapacity + 1)]
for w in range(maxCapacity + 1):
for i in range(len(weights) + 1):
if i == 0 or w == 0:
knapsack[w][i] = 0
elif weights[i - 1] <= w:
knapsack[w][i] = max(
weights[i - 1] + knapsack[w - weights[i - 1]][i - 1],
knapsack[w][i - 1],
)
else:
knapsack[w][i] = knapsack[w][i - 1]
for r in knapsack:
print(r)
return knapsack[-1][-1]
func([4, 8, 5, 9], 20)
Summary: Learn to solve 0-1 Knapsack Problem to understand this better.

First we need to check if the numbers sum is smaller than N, then save the sum as the result and the sum as the string at different lists at the same time.
So when we find the max in the list of sums is smaller than N, we can access the second list containing the strings using the same index.
M = [12, 9, 8, 4, 8, 5]
Ma = []
Ma_num = []
N = 20
for i in M:
for a in range(len(M)):
if i + M[a] <= N:
Ma.append(f"{i} + {M[a]}")
Ma_num.append(i + M[a])
max_num = Ma_num.index(max(Ma_num))
print(Ma[max_num])
Output:
12 + 8
By the way, if you meant that you wanted to see the number 20 in output, the solution is this:
M = [12, 9, 8, 4, 8, 5]
Ma = []
N = 20
for i in M:
for a in range(len(M)):
if i + M[a] <= N:
Ma.append(i + M[a])
max_num = max(Ma)
print(max_num)
Output:
20

I have a solution, first sum all number in your m array then in a loop check
sum >=n
if true return m
else sum = m - min(m)
and remove min
and check again
##############################3
check this solotion
M = [1,2,3,6,0, 8, 9, 12]
n = 20
s= 0
while s < n:
maximum = max(M)
M.remove(maximum)
if (s+ maximum)>n:
continue
s = s + maximum
print(s)

This can be solved as a Knapsack Problem
In the Knapsack problem we have a vector of values (val) and weights (wt)
We want to maximize the sum of a subset of values (val) such that
the corresponding weight is less than some max (referred to as capacity)
We can use the Knapsack algorithm by:
(1) Letting the input array corresponds to both weights and values
(2) Maximum capacity is the max sum
Code for solving Knapsack from here
def knapSack(W , wt , val, n):
# Base Case
if n == 0 or W == 0 :
return 0
# If weight of the nth item is more than Knapsack of capacity
# W, then this item cannot be included in the optimal solution
if (wt[n-1] > W):
return knapSack(W , wt , val , n-1)
# return the maximum of two cases:
# (1) nth item included
# (2) not included
else:
return max(val[n-1] + knapSack(W-wt[n-1] , wt , val , n-1),
knapSack(W , wt , val , n-1))
def max_sum(K, arr):
'''Solve using Knapsack code with (set weights and values equal to arr)'''
return knapSack(K, arr, arr, len(arr))
Test
arr = [1,5,4,6]
print(max_sum(13, arr))
#>>> Outputs 12
arr =[1,2,3,6,0, 8, 9, 12]
print(max_sum(20, arr))
#>>> Outputs 20
arr = [2,5,6,8]
print(max_sum(17, arr))
#>>> Outputs 16
Complexity
The time complexity of Knapsack solution is O(nW)
where n is the length of the array arr
W is the max sum

Related

loop through the list to get Maximum sum for a given range in python

I am a novice in python. I have a code where I loop through a list to capture maximum sum of numbers for given range k. It is working fine but I want it to make it shorter/optimal. 'k' may vary
numb = [100,33,22,200,333,1000,22]
m=0
k=2
sum1=0
temp=[]
for j in range(len(numb)-(k-1)):
for i in range(m,k):
temp.append(numb[i])
if sum1 < sum(temp):
sum1 = sum(temp)
temp=[]
m+=1
k+=1
print(sum1)
Ans: 1533 when k = 3
Ans: 1333 when k = 2
You can start by adding up the first k numbers. That is your starting sum and your current max. Then run a sliding window along the list, adding the next number and removing the one that goes out of the window.
def sum_k(x, k):
m = s = sum(x[:k])
for i, a in enumerate(x[k:]):
b = x[i] # number to remove
s += a - b
m = max(m, s)
return m
numb = [100, 33, 22, 200, 333, 1000, 22]
print(sum_k(numb, 2), sum_k(numb, 3))
This runs in linear time, which is optimal since you need to at least look at every element in your input.
The index, i, in the loop runs from zero to n-k-1, so although we enumerate over x[k:] the indices we pick are from x[0:], so when we pick b we are picking the number that goes out of the window. Meanwhile, a is the new number that comes in.
This is the simplified code you want which takes O(n) of time complexity. This approach is based on Sliding Window Algorithm.
maxSum is the function which takes 2 arguments (array of numbers and k) and returns maximum for any value of k.
def maxSum(arr, k):
# Edge case
if len(arr) <= k:
return sum(arr)
sums = sum(arr[:k]) # sum the first 3 val in arr.
start = 0 # tell us the first element index whose value is in sums variable
maximum = sums
for val in arr[k:]:
sums = (sums - arr[start]) + val
# here we first subtracted the start value and then added current value.
# Eg. From [1,2,3,4] sums have 1+2+3, but now sums have ( 1+2+3(previous) - 1(start) ) + 4(current)
# Now check for maximum.
if sums > maximum:
maximum = sums
# now increase start by 1 to make pointer to value '2' and so on.
start += 1
# return maximum
return maximum
arr = [100,33,22,200,333,1000,22]
k = 2
print("For k=2: ", maxSum(arr, k))
k = 3
print("For k=3: ", maxSum(arr, k))
Output:
For k=2: 1333
For k=3: 1533

Counting elements in 2 arrays (GFG)

I was working on a GFG question
Question:
Given two unsorted arrays arr1[] and arr2[]. They may contain duplicates. For each element in arr1[] count elements less than or equal to it in array arr2[].
Example 1:
Input:
m = 6, n = 6
arr1[] = {1,2,3,4,7,9}
arr2[] = {0,1,2,1,1,4}
Output: 4 5 5 6 6 6
Explanation: Number of elements less than
or equal to 1, 2, 3, 4, 7, and 9 in the
second array are respectively 4,5,5,6,6,6
Example 2:
Input:
m = 5, n = 7
arr1[] = {4 8 7 5 1}
arr2[] = {4,48,3,0,1,1,5}
Output: 5 6 6 6 3
Your Task :
Complete the function countEleLessThanOrEqual() that takes two array arr1[], arr2[], m, and n as input and returns an array containing the required results(the count of elements less than or equal to it in arr2 for each element in arr1 where ith output represents the count for ith element in arr1.)
Expected Time Complexity: O((m + n) * log n).
Expected Auxiliary Space: O(1).
Constraints:
1<=m,n<=10^5
1<=arr1[i],arr2[j]<=10^5
My python solution:
def countEleLessThanOrEqual(arr1,n1,arr2,n2):
#returns the required output
res=[]
arr2.sort()
for i in range(n1):
search=arr1[i]
count=0
start=0
end=n2-1
while(start<=end):
mid = int(start+(end-start)/2)
if search==arr2[mid]:
start=mid+1
elif search>arr2[mid]:
start=mid+1
elif search<arr2[mid]:
end=mid-1
count=end+1
res.append(count)
return res
When I submit it, it gives me TLE error even though my solution is similar to the one posted in the editorial:
Editorial solution:
# python implementation of For each element in 1st
# array count elements less than or equal to it
# in 2nd array
# function returns the index of largest element
# smaller than equal to 'x' in 'arr'. For duplicates
# it returns the last index of occurrence of required
# element. If no such element exits then it returns -1
def bin_search(arr, n, x):
l = 0
h = n - 1
while(l <= h):
mid = int((l + h) / 2)
# if 'x' is greater than or equal to arr[mid],
# then search in arr[mid + 1...h]
if(arr[mid] <= x):
l = mid + 1;
else:
# else search in arr[l...mid-1]
h = mid - 1
# required index
return h
# function to count for each element in 1st array,
# elements less than or equal to it in 2nd array
def countElements(arr1, arr2, m, n):
# sort the 2nd array
arr2.sort()
# for each element in first array
for i in range(m):
# last index of largest element
# smaller than or equal to x
index = bin_search(arr2, n, arr1[i])
# required count for the element arr1[i]
print(index + 1)
# driver program to test above function
arr1 = [1, 2, 3, 4, 7, 9]
arr2 = [0, 1, 2, 1, 1, 4]
m = len(arr1)
n = len(arr2)
countElements(arr1, arr2, m, n)
# This code is contributed by Aditi Sharma
You could use a binary search on the second array after sorting it in place:
from bisect import bisect_right
def lowerCount(arr1,arr2):
arr2.sort()
return [bisect_right(arr2,v) for v in arr1]
print(*lowerCount([1,2,3,4,7,9],[0,1,2,1,1,4])) # 4 5 5 6 6 6
print(*lowerCount([4, 8, 7, 5, 1],[4,48,3,0,1,1,5])) # 5 6 6 6 3
Sorting arr2 is O(N log N), and binary searches will take O(M log N) for a total of O( (N+M) log N ).
If you can't use libraries, you could always write your own bisect_right function:
def bisect_right(A,x):
lo,hi = 0,len(A)-1
while lo <= hi:
mid = (lo+hi)//2
if A[mid] <= x: lo = mid+1
else: hi = mid-1
return hi+1
#AasthaJha, would you like to try this similar but simplified alternative version:
def bin_search(A, n, x):
low, high = 0, n-1
while low <= high:
mid = (low + high) // 2
# if 'x' is greater than or equal to A[mid],
# then search in arr[mid + 1...h]
if A[mid] <= x:
low = mid + 1;
else:
high = mid -1 # else search in A[l...mid-1]
return high
# function to count for each element in 1st array,
# elements less than or equal to it in 2nd array
def countElements(A, B, m, n):
B.sort()
result = []
# loop element in A - first array
for i in range(m):
# last index of largest element smaller than or equal to x
index = bin_search(B, n, A[i])
print(index + 1) # count
result.append(index + 1)
return result
# Testing
A = [1, 2, 3, 4, 7, 9]
B = [0, 1, 2, 1, 1, 4]
m, n = len(A), len(B)
print(countElements(A, B, m, n))

Trying to find the optimal subset for the Greedy knapsack problem(python)

I think this is the correct algorithm for finding the optimal value, but now i need to find the optimal subsets that got me that value. Help would be greatly appreciated!
These were my directions:
Implement a greedy algorithm that arranges the items in the decreasing order of value to weight ratio (vi/wi for i = 1, 2, ..., n), then select the items in this order until the weight of the next item exceeds the remaining capacity (Note: In this greedy version, we stop right after the first item whose inclusion would exceed the knapsack capacity).
def greedy_knapsack(val, weight, W, n):
# index = [0, 1, 2, ..., n - 1] for n items
index = list(range(len(val)))
# contains ratios of values to weight
ratio = [v / w for v, w in zip(val, weight)]
QuickSort(ratio, 0, len(ratio) - 1)
max_value = 0
for i in index:
if weight[i] <= W:
max_value += val[i]
W -= weight[i]
else:
max_value += val[i] * W // weight[i]
break
return max_value
Your greedy approach will fail in many cases.
One such trivial case:
weight = [10, 10, 10]
value = [5, 4, 3]
W = 7
In this case, your algorithm will choose (item 1) sum = 5, but the optimal answer should be (items 2 and 3), sum = 7.
You need a dynamic programming approach to solve this and you can keep a matrix to store your previous states so that you can reconstruct the solution and get the item list.
# Prints the items which are put in a
# knapsack of capacity W
def printknapSack(W, wt, val, n):
K = [[0 for w in range(W + 1)]
for i in range(n + 1)]
# Build table K[][] in bottom
# up manner
for i in range(n + 1):
for w in range(W + 1):
if i == 0 or w == 0:
K[i][w] = 0
elif wt[i - 1] <= w:
K[i][w] = max(val[i - 1]
+ K[i - 1][w - wt[i - 1]],
K[i - 1][w])
else:
K[i][w] = K[i - 1][w]
# stores the result of Knapsack
res = K[n][W]
print(res)
w = W
for i in range(n, 0, -1):
if res <= 0:
break
# either the result comes from the
# top (K[i-1][w]) or from (val[i-1]
# + K[i-1] [w-wt[i-1]]) as in Knapsack
# table. If it comes from the latter
# one/ it means the item is included.
if res == K[i - 1][w]:
continue
else:
# This item is included.
print(wt[i - 1])
# Since this weight is included
# its value is deducted
res = res - val[i - 1]
w = w - wt[i - 1]
# Driver code
val = [ 60, 100, 120 ]
wt = [ 10, 20, 30 ]
W = 50
n = len(val)
printknapSack(W, wt, val, n)
ref: https://www.geeksforgeeks.org/printing-items-01-knapsack/

MyProgrammingLab Triangular Number probelm

The question is:
A triangular number is a number that is the sum of the integers from 1 to some integer n. Thus 1 is a triangular number because it's the sum of the integers from 1 to 1; 6 is a triangular number because it's 1+2+3=6.
Given the non-negative integers m and n (with m < n), create a list of the triangular numbers between (and including) m and n. Thus if m is 3 and n is 20, the list would be: [3, 6, 10, 15]. Associate the list with the variable triangulars.
The code I've tried:
Sum = 0
triangulars = []
for i in range(m,m+n):
if (n >= m) and (m >= 0):
Sum += 1
triangulars.append(Sum)
The error I have is the programming lab recommends I use the sum function, and the results I am getting are no triangular numbers (I should get 6, 10 , 15 when m = 5 and n = 17, instead I get 5, 11, 18 and so on)
I changed it around a bit, put it in a function, renamed some variables, and threw in the test cases of m=3,n=20. I also tested several other combos including m=5,n=17. I also employed the sum() function you mentioned that you were asked to use. Here's the working code:
def triangulars(m,n):
if (n >= m) and (m >= 0):
sum_list = []
triangular_list = []
for i in range(1,n+1):
sum_list.append(i)
a_triangular = sum(sum_list)
if m <= a_triangular <= n:
print(m,n,a_triangular)
triangular_list.append(a_triangular)
print(m,n,triangular_list)
else:
print('Invalid m,n values')
m = 3
n = 20
triangulars(m,n)

Fibonacci sequence using codelab

In the following sequence, each number (except the first two) is the sum of the previous two number: 0, 1, 1, 2, 3, 5, 8, 13, .... This sequence is known as the Fibonacci sequence.
Given the positive integers m and n (with m < n) create a list consisting of the portion of the Fibonacci sequence greater than or equal to m and less than or equal to n. For example, if m is 3 and n is 6, then the list would be [3, 5] and if m is 2 and n is 20, then the list would be [2, 3, 5, 8, 13].
Associate the list with the variable fib.
Have done this far, but still getting error.
Where does it need to be fixed?
fib = [0,1,1]
result = 0
while result <=n:
result=fib[-1]+fib[-2]
if result <=n and result>=m:
fib.append(result)
# create a fibonacci series from 0 to n
f = [0,1]
for i in range(1, n+1):
x = f[i]+f[i-1]
if x > n:
break
else:
f.append(x)
# copy only those numbers of series that are in range m to n
fib = []
for i in range(0, len(f)):
if f[i] >= m and f[i] <= n:
fib.append(f[i])
You could use the code below.
fib = [0,1,1]
fibrange = [] # keeps your digits that are in range m < n
result = 0
n = 80
m = 2
while result <=n:
result =fib[-1]+fib[-2]
fib.append(result)
if result <=n and result>=m:
fibrange.append(result)
print fibrange
fib=[0,1]
i=0
while i <=n:
i=fib[-1]+fib[-2]
if i<=n:
fib.append(i)

Categories

Resources