Choosing minimum numbers from a given list to give a sum N( repetition allowed) - python-3.x

How to find the minimum number of ways in which elements taken from a list can sum towards a given number(N)
For example if list = [1,3,7,4] and N=14 function should return 2 as 7+7=14
Again if N= 11, function should return 2 as 7+4 =11. I think I have figured out the algorithm but unable to implement it in code.
Pls use Python, as that is the only language I understand(at present)
Sorry!!!

Since you mention dynamic programming in your question, and you say that you have figured out the algorithm, i will just include an implementation of the basic tabular method written in Python without too much theory.
The idea is to have a tabular structure we will use to compute all possible values we need without having to doing the same computations many times.
The basic formula will try to sum values in the list till we reach the target value, for every target value.
It should work, but you can of course make some optimization like trying to order the list and/or find dividends in order to construct a smaller table and have faster termination.
Here is the code:
import sys
# num_list : list of numbers
# value: value for which we want to get the minimum number of addends
def min_sum(num_list, value):
list_len = len(num_list)
# We will use the tipycal dynamic programming table construct
# the key of the list will be the sum value we want,
# and the value will be the
# minimum number of items to sum
# Base case value = 0, first element of the list is zero
value_table = [0]
# Initialize all table values to MAX
# for range i use value+1 because python range doesn't include the end
# number
for i in range(1, value+1):
value_table.append(sys.maxsize);
# try every combination that is smaller than <value>
for i in range(1, value+1):
for j in range(0, list_len):
if (num_list[j] <= i):
tmp = value_table[i-num_list[j]]
if ((tmp != sys.maxsize) and (tmp + 1 < value_table[i])):
value_table[i] = tmp + 1
return value_table[value]
## TEST ##
num_list = [1,3,16,5,3]
value = 22
print("Min Sum: ",min_sum(num_list,value)) # Outputs 3

it would be helpful if you include your Algorithm in Pseudocode - it will very much look like Python :-)
Another aspect: your first operation is a multiplication with one item from the list (7) and one outside of the list (2), whereas for the second opration it is 7+4 - both values in the list.
Is there a limitation for which operation or which items to use (from within or without the list)?

Related

Sorting algoritm

I want to make my algorithm more efficient via deleting the items it already sorted, but i don't know how I can do it efficiently. The only way I found was to rewrite the whole list.
l = [] #Here you put your list
sl = [] # this is to store the list when it is sorted
a = 0 # variable to store which numbers he already looked for
while True: # loop
if len(sl) == len(l): #if their size is matching it will stop
print(sl) # print the sorted list
break
a = a + 1
if a in l: # check if it is in list
sl.append(a) # add to sorted list
#here i want it to be deleted from the list.
The variable a is a little awkward. It starts at 0 and increments 1 by 1 until it matches elements from the list l
Imagine if l = [1000000, 1200000, -34]. Then your algorithm will first run for 1000000 iterations without doing anything, just incrementing a from 0 to 1000000. Then it will append 1000000 to sl. Then it will run again 200000 iterations without doing anything, just incrementing a from 1000000 to 1200000.
And then it will keep incrementing a looking for the number -34, which is below zero...
I understand the idea behind your variable a is to select the elements from l in order, starting from the smallest element. There is a function that does that: it's called min(). Try using that function to select the smallest element from l, and append that element to sl. Then delete this element from l; otherwise, the next call to min() will select the same element again instead of selecting the next smallest element.
Note that min() has a disadvantage: it returns the value of the smallest element, but not its position in the list. So it's not completely obvious how to delete the element from l after you've found it with min(). An alternative is to write your own function that returns both the element, and its position. You can do that with one loop: in the following piece of code, i refers to a position in the list (0 is the position of the first element, 1 the position of the second, etc) and a refers to the value of that element. I left blanks and you have to figure out how to select the position and value of the smallest element in the list.
....
for i, a in enumerate(l):
if ...:
...
...
If you managed to do all this, congratulations! You have implemented "selection sort". It's a well-known sorting algorithm. It is one of the simplest. There exist many other sorting algorithms.

Get the value of a list that produces the maximum value of a calculation

I apologize if this is a duplicate, I tried my best to find an existing question but was unsuccessful.
Recently, I've run into a couple of problems where I've needed to find the element in a list that produces the max/min value when a calculation is performed. For example, a list of real numbers where you want to find out which element produces the highest value when squared. The actual value of the squared number is unimportant, I just need the element(s) from the list that produces it.
I know I can solve the problem by finding the max, then making a pass through the list to find out which values' square matches the max I found:
l = [-0.25, 21.4, -7, 0.99, -21.4]
max_squared = max(i**2 for i in l)
result = [i for i in l if i**2 == max_squared]
but I feel like there should be a better way to do it. Is there a more concise/one-step solution to this?
This will return you just the element which gives the max when squared.
result = max(l, key = lambda k: k**2)
It does not get much better if you need the value in a list f.e. to see how often it occures. You can remeber the source element as well if you do not need that:
l = [-0.25, 21.4, -7, 0.99, -21.4]
max_squared = max( (i**2, i) for i in l) # remeber a tuple, with the result coming first
print(max_squared[1]) # print the source number (2nd element of the tuple)
Output:
21.4
Your calculation does only return the first occurence of abs(24.1) because max only returns one value, not two - if you need both, you still need to do:
print( [k for k in l if abs(k) == max_squared[1]])
to get
[21.4,-21.4]

list and dictionary: which one is faster

I have the following pieces of code doing the sorting of a list by swapping pairs of elements:
# Complete the minimumSwaps function below.
def minimumSwaps(arr):
counter = 0
val_2_indx = {val: arr.index(val) for val in arr}
for indx, x in enumerate(arr):
if x != indx+1:
arr[indx] = indx+1
s_indx = val_2_indx[indx+1]
arr[s_indx] = x
val_2_indx[indx+1] = indx
val_2_indx[x] = s_indx
counter += 1
return counter
def minimumSwaps(arr):
temp = [0] * (len(arr) + 1)
for pos, val in enumerate(arr):
temp[val] = pos
swaps = 0
for i in range(len(arr)):
if arr[i] != i+1:
swaps += 1
t = arr[i]
arr[i] = i+1
arr[temp[i+1]] = t
temp[t] = temp[i+1]
temp[i+1] = i
return swaps
The second function works much faster than the first one. However, I was told that dictionary is faster than list.
What's the reason here?
A list is a data structure, and a dictionary is a data structure. It doesn't make sense to say one is "faster" than the other, any more than you can say that an apple is faster than an orange. One might grow faster, you might be able to eat the other one faster, and they might both fall to the ground at the same speed when you drop them. It's not the fruit that's faster, it's what you do with it.
If your problem is that you have a sequence of strings and you want to know the position of a given string in the sequence, then consider these options:
You can store the sequence as a list. Finding the position of a given string using the .index method requires a linear search, iterating through the list in O(n) time.
You can store a dictionary mapping strings to their positions. Finding the position of a given string requires looking it up in the dictionary, in O(1) time.
So it is faster to solve that problem using a dictionary.
But note also that in your first function, you are building the dictionary using the list's .index method - which means doing n linear searches each in O(n) time, building the dictionary in O(n^2) time because you are using a list for something lists are slow at. If you build the dictionary without doing linear searches, then it will take O(n) time instead:
val_2_indx = { val: i for i, val in enumerate(arr) }
But now consider a different problem. You have a sequence of numbers, and they happen to be the numbers from 1 to n in some order. You want to be able to look up the position of a number in the sequence:
You can store the sequence as a list. Finding the position of a given number requires linear search again, in O(n) time.
You can store them in a dictionary like before, and do lookups in O(1) time.
You can store the inverse sequence in a list, so that lst[i] holds the position of the value i in the original sequence. This works because every permutation is invertible. Now getting the position of i is a simple list access, in O(1) time.
This is a different problem, so it can take a different amount of time to solve. In this case, both the list and the dictionary allow a solution in O(1) time, but it turns out it's more efficient to use a list. Getting by key in a dictionary has a higher constant time than getting by index in a list, because getting by key in a dictionary requires computing a hash, and then probing an array to find the right index. (Getting from a list just requires accessing an array at an already-known index.)
This second problem is the one in your second function. See this part:
temp = [0] * (len(arr) + 1)
for pos, val in enumerate(arr):
temp[val] = pos
This creates a list temp, where temp[val] = pos whenever arr[pos] == val. This means the list temp is the inverse permutation of arr. Later in the code, temp is used only to get these positions by index, which is an O(1) operation and happens to be faster than looking up a key in a dictionary.

How to see if a given array is between two arrays

I am using python 3.2.0 and numpy. I would like to check if one of the arrays is in between two other specified arrays. I would like it if you suggest a function or few of them together. Any help is appreciated , as it is a school project and I need to submit it quickly.
If you mean how the last item of arr1 is less than all items of input_arr, and the first item of arr2 is greater than all those in input_arr, you can do this, with "biggest" of arr1 and "smallest" of arr2:
biggest = arr1[len(arr1)-1]
smallest = arr2[0]
between=True
for item in input_arr:
if not (biggest<item and smallest>item):
between=False
break
Alternatively, you could change the < and/or the > to <= or >= if you allow equals to (so [1,3,4],[4,6,8],[8,17,18] is True)
This assumes that the lists are consecutive. If they're not, you'll have to loop through arr1 to find the largest number and arr2 to find the smallest first.
biggest=0
for item in arr1:
if item>biggest:
biggest=item
smallest=arr2[0]
for item in arr2:
if item<smallest:
smallest = item
Use this as a skeleton guide, don't just copy and paste. If you don't understand it and therefore can't construct your own version, you probably need to do some sort of online course (eg. Codecademy). In the mean time, copy the 2nd bit first if you need it, then the first.
If you had 3 arrays,
#lower bound
In[1]: small = np.zeros((3,3))
#Array we are testing
In[2]: test = np.ones((3,3))
#Upper bound
In[3]: large = np.ones((3,3))*2
then you could do a logical_and and test the entire array with the Boolean sum against the size
In[4]: np.logical_and(small<=testm,testm<=large).sum() == l.size
out[4]: True

merging some entries in a python list based on length of items

I have a list of about 20-30 items [strings].
I'm able to print them out in my program just fine - but I'd like to save some space, and merge items that are shorter...
So basically, if I have 2 consecutive items that the combined lengths are less than 30, I want to join those to items as a single entry in the list - with a / between them
I'm not coming up with a simple way of doing this.
I don't care if I do it in the same list, or make a new list of items... it's all happening inside 1 function...
You need to loop through the list and keep joining items till they satisfy your requirement (size 30). Then add them to a new list when an element grows that big.
l=[] # your new list
buff=yourList[0] if len(yourList)>0 else "" # hold strings till they reach desired length
for i in range(1,len(yourList)):
# check if concatenating will exceed the size or not
t=yourList[i]
if (len(buff) + len(t) + 1) <= 30:
buff+="/"+t
else:
l.append(buff)
buff=t
l.append(buff) # since last element is yet to be inserted
You can extend method of list as follows:
a = [1,2,3]
b = [4,5,6]
a.append('/')
a.extend(b)
You just need to check the size of two list a and b as per your requirements.
I hope I understood your problem !
This code worked for me, you can check to see if that's what you wanted, it's a bit lenghty but it works.
list1 = yourListOfElements
for elem in list1:
try: # Needs try/except otherwise last iteration would throw an indexerror
listaAUX = [] # Auxiliar list to check length and join smaller elements. You can probably eliminate this using list slicing
listaAUX.append(elem)
listaAUX.append(list1[list1.index(elem)+1])
if len(listaAUX[0]) + len(listaAUX[1]) < 30:
concatenated = '/'.join(listaAUX)
print(concatenated)
else:
print(elem)
except IndexError:
print(elem)

Resources