python memoization - python-3.x

I am new in dynamic programming..
This is a python code for finding shortest combination of numbers that add up to exactly the target sum using memoization.
global memo
memo={}
def bestSum(targetSum,arr):
if targetSum in memo:
return memo[targetSum]
#Base conditions
if targetSum==0:
return []
if targetSum<0:
return None
# Branching statments
shortestCombination=None
for i in arr:
remainder_combination=bestSum(targetSum-i,arr)
if remainder_combination != None:
combination=remainder_combination
combination.append(i)
if shortestCombination ==None or len(shortestCombination)>len(combination):
shortestCombination=combination
memo[targetSum]=shortestCombination
return shortestCombination
print(bestSum(10,[1,4,5]))
But the output was this
[4, 1, 4, 1, 5, 1]
whereas the correct output is
[5,5]
if i comment the memoization statements the output will be correct..
This is the python code without memoization for the same problem...
# global memo
# memo={}
def bestSum(targetSum,arr):
# if targetSum in memo:
# return memo[targetSum]
#Base conditions
if targetSum==0:
return []
if targetSum<0:
return None
# Branching statments
shortestCombination=None
for i in arr:
remainder_combination=bestSum(targetSum-i,arr)
if remainder_combination != None:
combination=remainder_combination
combination.append(i)
if shortestCombination ==None or len(shortestCombination)>len(combination):
shortestCombination=combination
# memo[targetSum]=shortestCombination
return shortestCombination
print(bestSum(10,[1,4,5]))
The above code gave me the correct output.
The correct output is also obtained in java script for the same problem with memoization by using object
const bestSum=(targetSum,numbers,memo={})=>{
if(targetSum in memo) return memo[targetSum];
if(targetSum===0) return [];
if(targetSum<0) return null;
let shortestCombination =null;
for (let num of numbers){
reminderCombination=bestSum(targetSum-num,numbers,memo);
if(reminderCombination !==null){
const combination=[...reminderCombination,num]
if(shortestCombination===null || combination.length< shortestCombination.length){
shortestCombination=combination
}
}
}
memo[targetSum]=shortestCombination
return shortestCombination
};
console.log(bestSum(10,[1,4,5]))
Few more examples
print(bestSum(7,[3,4,7]))
print(bestSum(20,[1,2,3,4,5,10]))
print(bestSum(3,[3,2,1]))
Correct outputs
[7]
[10, 10]
[3]
Wrong outputs when memoization is used
[7]
[10, 1, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 5, 10]
[3, 4, 2, 3, 5, 10, 1, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 5]
Thank you!

We have to use copy() method in order to copy a list, without using it we are referencing the list not coping.
memo={}
def bestSum(targetSum,arr):
if targetSum in memo:
return memo[targetSum]
if targetSum==0:
return []
if targetSum<0:
return None
shortestCombination=None
for i in arr:
remainder_combination=bestSum(targetSum-i,arr)
if remainder_combination != None:
combination = remainder_combination.copy()
combination.append(i)
if shortestCombination ==None or len(shortestCombination)>len(combination):
shortestCombination=combination.copy()
memo[targetSum]=shortestCombination
return shortestCombination
print(bestSum(10,[1,4,5]))

Related

My symmetric difference function is returning none and I can't understand why

Trying to solve freecodecamp's symmetric difference challenge (https://www.freecodecamp.org/learn/coding-interview-prep/algorithms/find-the-symmetric-difference), I wrote the following function:
def symdiff(*args):
dump = [x for x in args[0] if x in args[1]]
result = [x for x in args[0] + args[1] if x not in dump]
if len(args) == 2:
return result
else:
symdiff(result, *args[2:])
var = symdiff([1, 2, 3], [3, 2, 0], [7, 2, 6])
print(var)
The value of var turns out to be None. Why is that? I expected it to be [7, 2, 6, 1, 0]. I entered a print(result) just before return result and it printed the correct answer.
In your else block, you need to return symdiff.
def symdiff(*args):
dump = [x for x in args[0] if x in args[1]]
result = [x for x in args[0] + args[1] if x not in dump]
if len(args) == 2:
return result
else:
return symdiff(result, *args[2:])
var = symdiff([1, 2, 3], [3, 2, 0], [7, 2, 6])
print(var)
The above code should work.

Remove all the elements before the given one from the array

Hi im trying to solve this question:
Not all of the elements are important. What you need to do here is to remove from the list all of the elements before the given one.
exemple:
remove_all_before([1, 2, 3, 4, 5], 3) == [3, 4, 5]
remove_all_before([1, 1, 2, 2, 3, 3], 2) == [2, 2, 3, 3]
remove_all_before([1, 1, 2, 4, 2, 3, 4], 2) == [2, 4, 2, 3, 4]
remove_all_before([1, 1, 5, 6, 7], 2) == [1, 1, 5, 6, 7]
remove_all_before([], 0) == []
remove_all_before([7, 7, 7, 7, 7, 7, 7, 7, 7], 7) == [7, 7, 7, 7, 7, 7, 7, 7, 7]
For the illustration we have a list [3, 4, 5] and we need to remove all elements that go before 3 - which is 1 and 2.
We have two edge cases here: (1) if a cutting element cannot be found, then the list shoudn't be changed. (2) if the list is empty, then it should remain empty.
def remove_all_before(items: list, border: int) -> Iterable:
limit = border
item_list = items
for i in item_list:
if i < limit:
return items[i+1:]
elif limit not in item_list:
return items
this is my code so far...and im stuck.
thanks for the help
this can be solved by using the index method of list and try and except command. here is the solution-
def remove_all_before(item, border):
try:
#search for the item
index = item.index(border)
print(f'the border is found at index {index}')
return item[index:]
except ValueError:
print('border not present')
return item
def remove_all_before(items: list, border: int) -> Iterable:
# your code here
for i in range(0, len(items)):
if (items[i] == border):
return items[i:]
return items
in my opinion this is the best solution, in this one you have the verification if border is in items
def remove_all_before(items, border):
result1 = []
result2 = []
for i in range(len(items)):
if (items[i] == border):
result1 = items[i:]
return result1
result2.append(items[i])
if (result1 == []):
return result2
else:
return result1

parsing infinite list into one list

I have this task building a code using recursion. The task is taking a list who can have an infinite amount of lists inside it and making it one list.
This is so far what I have:
def flat_list(array):
new_array =[]
for i in range(0,len(array)):
if len(str(array[i])) > 1:
flat_list(array[i:i+1])
else:
new_array += array[i:len(str(array))-1]
return new_array
These are the tests it needs to pass:
assert flat_list([1, 2, 3]) == [1, 2, 3]
assert flat_list([1, [2, 2, 2], 4]) == [1, 2, 2, 2, 4]
assert flat_list([[[2]], [4, [5, 6, [6], 6, 6, 6], 7]]) == [2, 4, 5, 6, 6, 6, 6, 6, 7]
assert flat_list([-1, [1, [-2], 1], -1]) == [-1, 1, -2, 1, -1]
Mine returns this:
flat_list([1, [2, 2, 2], 4])
my result: [1,[2,2,2],4]
right answer: [1,2,2,2,4]
I think my problem is with creating a new local variable of the new_array at each entry, How can I return one list with no other lists inside it?
This task is without using numpy, but if you can also show me how it can be done with numpy it will really educate me. :)
Thank you for answering
Try this:
def flatten(S):
if S == []:
return S
if isinstance(S[0], list):
return flatten(S[0]) + flatten(S[1:])
return S[:1] + flatten(S[1:])
How it works:
1. The list is passed as an argument to a recursive function to flatten the list.
2. In the function, if the list is empty, the list is returned.
3. Otherwise the function is recursively called with the sublists as the parameters until the entire list is flattened.
I suggest you the following suggestion: it iterates over the list and if the encountered item is a list, then it recursively flattens it before appending it to the resulting flattened list:
def flat_list(aList):
result = []
for i in aList:
if isinstance(i, list):
result += flat_list(i)
else:
result.append(i)
return result

How to write a function where the original list of integers is changed without using return?

Let us say we have a list of integers:
list = [6, 4, 1, 4, 4, 4, 4, 4, 2, 1]
I now wrote a function which returns another list with all the integers from the list above without repeats.
def no_repeats(s):
new_list = []
for number in s:
if new_list.count(number) < 1:
new_list.append(number)
return(new_list)
The new_list returns [6, 4, 1, 2] which is good! My question is how I would now write two similar functions:
A function clean(s) which does not return a new list like the function above, but changes the original list by deleting all the numbers that repeat. Thus, the result has to be the same and the function must not include "return" or create a new list. It must only clean the original list.
A function double(s) which, again, changes the original list (does not return a new list!) but this time, by doubling every number in the original list. Thus, double(list) should change the original list above to:
[6, 6, 4, 4, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1]
Thank you for all the help!
Removing duplicates inplace without preserving the order:
def no_repeats(L):
L[:] = set(L)
There are several variations possible (preserve order, support non-hashable items, support item that do not define total ordering) e.g., to preserve order:
from collections import OrderedDict
def no_repeats(L):
L[:] = OrderedDict.fromkeys(L)
To double each element's value inplace:
def double(L):
for i in range(len(L)):
L[i] *= 2
To duplicate each element:
def duplicate_elements(L):
L[:] = [x for x in L for _ in range(2)]
>>> def clean(s):
... s[:] = [s[i] for i in range(len(s)) if s[i] not in s[:i]]
...
>>> st = [1, 2, 3, 2, 1]
>>> clean(st)
>>> st
[1, 2, 3]
>>> def double(s):
... s[:] = [s[i//3] for i in range(3*len(s)) if i % 3]
...
>>> st = [1, 2, 3, 2, 1]
>>> double(st)
>>> st
[1, 1, 2, 2, 3, 3, 2, 2, 1, 1]
neither is particularly efficient nor pythonic, yet do address the OP question
def double(s):
... s[:] = [s[i//2] for i in range(2*len(s))]
will also do the trick, with a little less obsfucation

How to combine array in groovy?

The following java code exists but I'm trying to convert it to groovy. Should I simply keep it as is w/ the System.arraycopy or does groovy have a nicer way to combine arrays like this?
byte[] combineArrays(foo, bar, start) {
def tmp = new byte[foo.length + bar.length]
System.arraycopy(foo, 0, tmp, 0, start)
System.arraycopy(bar, 0, tmp, start, bar.length)
System.arraycopy(foo, start, tmp, bar.length + start, foo.length - start)
tmp
}
Thank you
def a = [1, 2, 3]
def b = [4, 5, 6]
assert a.plus(b) == [1, 2, 3, 4, 5, 6]
assert a + b == [1, 2, 3, 4, 5, 6]
If you want to use an array:
def abc = [1,2,3,4] as Integer[] //Array
def abcList = abc as List
def xyz = [5,6,7,8] as Integer[] //Array
def xyzList = xyz as List
def combined = (abcList << xyzList).flatten()
Using Lists:
def abc = [1,2,3,4]
def xyz = [5,6,7,8]
def combined = (abc << xyz).flatten()
def a = [1, 2, 3]
def b = [4, 5, 6]
a.addAll(b)
println a
>> [1, 2, 3, 4, 5, 6]
The trick is the flatten() method, that combined nested arrays into one:
def a = [1, 2, 3]
def b = [4, 5, 6]
def combined = [a, b].flatten()
assert combined == [1, 2, 3, 4, 5, 6]
println(combined)
To remove null values you can use findAll() like this:
def a = null
def b = [4, 5, 6]
def combined = [a, b].flatten().findAll{it}
assert combined == [4, 5, 6]
println(combined)
I'd go with
byte[] combineArrays(foo, bar, int start) {
[*foo[0..<start], *bar, *foo[start..<foo.size()]]
}
It could be done like this:
def newCombine(foo,bar,start) {
([].add + foo[0..<start]+bar+foo[start..<foo.size()]).flatten()
}
It works for all kinds of arrays (byte[]) or lists
All the solutions above fails if an array is undefined:
def a = [1,2]
def b
assert a+b == [1, 2, null]
which is probably not what you want.
Either test if the array exists before adding:
def a = [1,2,3,4]
def b // null array
def c = [0,4,null,6]
def abc = []
[a,b,c].each{ if (it) abc += it }
assert abc == [1, 2, 3, 4, 0, 4, null, 6]
,or add all and then filter the output:
(a+b+c).findAll{ it != null }
(assuming here that null isn't a valid value in the original arrays, which implies that the first solution is a lot better, even if it may not look Groovy enough.)

Resources