Python Greedy Sum - python

I am currently working on this code and the only thing that seems to work is the "no solution." Also it seems that the code has an infinite loop and I can't seem to figure out how to solve it. If someone could point out my mistake it would be appreciated.
def greedySum(L, s):
""" input: s, positive integer, what the sum should add up to
L, list of unique positive integers sorted in descending order
Use the greedy approach where you find the largest multiplier for
the largest value in L then for the second largest, and so on to
solve the equation s = L[0]*m_0 + L[1]*m_1 + ... + L[n-1]*m_(n-1)
return: the sum of the multipliers or "no solution" if greedy approach does
not yield a set of multipliers such that the equation sums to 's'
"""
if len(L) == 0:
return "no solution"
sum_total = (0, ())
elif L[0] > k:
sum_total = greed(L[1:], k)
else:
no_number = L[0]
value_included, take = greed(L, k - L[0])
value_included += 1
no_value, no_take = greed(L[1:], k)
if k >= 0:
sum_total = (value_included, take + (no_number,))
else:
sum_total = (value_included, take + (no_number,))
return sum_total
sum_multiplier = greed(L, s)
return "no solution" if sum(sum_multiplier[1]) != s else sum_multiplier[0]
Second method:
def greedySum(L, s):
answer = []
try:
while (s >= L[0]):
total = s// L[0]
s -= (total * L[0])
answer.append(total)
L = L[1:]
return(str(answer)[1:-1])
except:
return("no solution")

Here is something that works:
def greedySum(L, s):
multiplier_sum = 0
for l in L:
(quot,rem) = divmod(s,l) # see how many 'l's you can fit in 's'
multiplier_sum += quot # add that number to the multiplier_sum
s = rem # update the remaining amount
# If at the end and s is 0, return the multiplier_sum
# Otherwise, signal that there is no solution
return multiplier_sum if s == 0 else "no solution"
I would offer more help on what is wrong with your code, but that is for the moment a moving target - you keep changing it!
>>> greedySum([4,2],8)
2
>>> greedySum([4,2],9)
'no solution'
>>> greedySum([4,2,1],9)
3

Related

Code for consecutive strings works but can't pass random tests

In this problem, I'm given an array(list) strarr of strings and an integer k. My task is to return the first longest string consisting of k consecutive strings taken in the array. My code passed all the sample tests from CodeWars but can't seem to pass the random tests.
Here's the link to the problem.
I did it in two days. I found the max consecutively combined string first. Here's the code for that.
strarr = []
def longest_consec(strarr, k):
strarr.append('')
length = len(strarr)
cons_list = []
end = k
start = 0
freq = -length/2
final_string = []
largest = max(strarr, key=len, default='')
if k == 1:
return largest
elif 1 < k < length:
while(freq <= 1):
cons_list.append(strarr[start:end])
start += k-1
end += k-1
freq += 1
for index in cons_list:
final_string.append(''.join(index))
return max(final_string, key=len, default='')
else:
return ""
Since that didn't pass all the random tests, I compared the combined k strings on both sides of the single largest string. But, this way, the code doesn't account for the case when the single largest string is in the middle. Please help.
strarr = []
def longest_consec(strarr, k):
strarr.append('')
length = len(strarr)
largest = max(strarr, key=len, default='')
pos = int(strarr.index(largest))
if k == 1:
return largest
elif 1 < k < length:
prev_string = ''.join(strarr[pos+1-k:pos+1])
next_string = ''.join(strarr[pos:pos+k])
if len(prev_string) >= len(next_string):
res = prev_string
else:
res = next_string
return res
else:
return ""
print(longest_consec(["zone", "abigail", "theta", "form", "libe"], 2))
Let's start from the first statement of your function:
if k == 1:
while(p <= 1):
b.append(strarr[j:i])
j += 1
i += 1
p += 1
for w in b:
q.append(''.join(w))
return max(q, key=len)
Here q is finally equal strarr so you can shorten this code to:
if k == 1:
return max(strarr, key=len)
I see that second statement's condition checks if k value is between 1 and length of string array inclusive:
elif k > 1 and k <= 2*a:
...
If you want no errors remove equality symbol, last element of every array has index lesser than its length (equal exactly length of it minus 1).
Ceiling and division is not necessary in a definition, so you can shorten this:
a = ceil(len(strarr)/2)
into this:
a = len(strarr)
then your elif statement may look like below:
elif 1 < k < a: # Same as (k > 1 and k < a)
...
again, I see you want to concatenate (add) the longest string to k next strings using this code:
while(p <= 1):
b.append(strarr[j:i])
j += k-1
i += k-1
p += 1
for w in b:
q.append(''.join(w))
return max(q, key=len)
the more clearer way of doing this:
longest = max(strarr, key=len) # Longest string in array.
index = 0 # Index of the current item.
for string in strarr:
# If current string is equal the longest one ...
if string == longest:
# Join 'k' strings from current index (longest string index).
return ''.join(strarr[index:index + k])
index += 1 # Increase current index.
And the last statement which is:
elif k > 2*a or k<1:
return ""
if all previous statements failed then value is invalid so you can instead write:
return "" # Same as with else.
Now everything should work. I advice you learning the basics (especially lists, strings and slices), and please name your variables wisely so they are more readable.
You can try this as well
this has passed all the test cases on the platform you suggested.
def longest_consec(strarr, k):
i = 0
max_ = ""
res = ""
if (k<=0) or (k>len(strarr)):
return ""
while i<=(len(strarr)-k):
start = "".join(strarr[i:i+k])
max_ = max(max_, start, key=len)
if max_==start:
res=strarr[i:i+k]
i+=1
return max_
#output: ["zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"], 2 -> abigailtheta
#output: ["zones", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"],2 -> zonesabigail

Finding first pair of numbers in array that sum to value

Im trying to solve the following Codewars problem: https://www.codewars.com/kata/sum-of-pairs/train/python
Here is my current implementation in Python:
def sum_pairs(ints, s):
right = float("inf")
n = len(ints)
m = {}
dup = {}
for i, x in enumerate(ints):
if x not in m.keys():
m[x] = i # Track first index of x using hash map.
elif x in m.keys() and x not in dup.keys():
dup[x] = i
for x in m.keys():
if s - x in m.keys():
if x == s-x and x in dup.keys():
j = m[x]
k = dup[x]
else:
j = m[x]
k = m[s-x]
comp = max(j,k)
if comp < right and j!= k:
right = comp
if right > n:
return None
return [s - ints[right],ints[right]]
The code seems to produce correct results, however the input can consist of array with up to 10 000 000 elements, so the execution times out for large inputs. I need help with optimizing/modifying the code so that it can handle sufficiently large arrays.
Your code inefficient for large list test cases so it gives timeout error. Instead you can do:
def sum_pairs(lst, s):
seen = set()
for item in lst:
if s - item in seen:
return [s - item, item]
seen.add(item)
We put the values in seen until we find a value that produces the specified sum with one of the seen values.
For more information go: Referance link
Maybe this code:
def sum_pairs(lst, s):
c = 0
while c<len(lst)-1:
if c != len(lst)-1:
x= lst[c]
spam = c+1
while spam < len(lst):
nxt= lst[spam]
if nxt + x== s:
return [x, nxt]
spam += 1
else:
return None
c +=1
lst = [5, 6, 5, 8]
s = 14
print(sum_pairs(lst, s))
Output:
[6, 8]
This answer unfortunately still times out, even though it's supposed to run in O(n^3) (since it is dominated by the sort, the rest of the algorithm running in O(n)). I'm not sure how you can obtain better than this complexity, but I thought I might put this idea out there.
def sum_pairs(ints, s):
ints_with_idx = enumerate(ints)
# Sort the array of ints
ints_with_idx = sorted(ints_with_idx, key = lambda (idx, num) : num)
diff = 1000000
l = 0
r = len(ints) - 1
# Indexes of the sum operands in sorted array
lSum = 0
rSum = 0
while l < r:
# Compute the absolute difference between the current sum and the desired sum
sum = ints_with_idx[l][1] + ints_with_idx[r][1]
absDiff = abs(sum - s)
if absDiff < diff:
# Update the best difference
lSum = l
rSum = r
diff = absDiff
elif sum > s:
# Decrease the large value
r -= 1
else:
# Test to see if the indexes are better (more to the left) for the same difference
if absDiff == diff:
rightmostIdx = max(ints_with_idx[l][0], ints_with_idx[r][0])
if rightmostIdx < max(ints_with_idx[lSum][0], ints_with_idx[rSum][0]):
lSum = l
rSum = r
# Increase the small value
l += 1
# Retrieve indexes of sum operands
aSumIdx = ints_with_idx[lSum][0]
bSumIdx = ints_with_idx[rSum][0]
# Retrieve values of operands for sum in correct order
aSum = ints[min(aSumIdx, bSumIdx)]
bSum = ints[max(aSumIdx, bSumIdx)]
if aSum + bSum == s:
return [aSum, bSum]
else:
return None

Divide and Conquer. Find the majority of element in array

I am working on a python algorithm to find the most frequent element in the list.
def GetFrequency(a, element):
return sum([1 for x in a if x == element])
def GetMajorityElement(a):
n = len(a)
if n == 1:
return a[0]
k = n // 2
elemlsub = GetMajorityElement(a[:k])
elemrsub = GetMajorityElement(a[k:])
if elemlsub == elemrsub:
return elemlsub
lcount = GetFrequency(a, elemlsub)
rcount = GetFrequency(a, elemrsub)
if lcount > k:
return elemlsub
elif rcount > k:
return elemrsub
else:
return None
I tried some test cases. Some of them are passed, but some of them fails.
For example, [1,2,1,3,4] this should return 1, buit I get None.
The implementation follows the pseudocode here:
http://users.eecs.northwestern.edu/~dda902/336/hw4-sol.pdf
The pseudocode finds the majority item and needs to be at least half. I only want to find the majority item.
Can I get some help?
Thanks!
I wrote an iterative version instead of the recursive one you're using in case you wanted something similar.
def GetFrequency(array):
majority = int(len(array)/2)
result_dict = {}
while array:
array_item = array.pop()
if result_dict.get(array_item):
result_dict[array_item] += 1
else:
result_dict[array_item] = 1
if result_dict[array_item] > majority:
return array_item
return max(result_dict, key=result_dict.get)
This will iterate through the array and return the value as soon as one hits more than 50% of the total (being a majority). Otherwise it goes through the entire array and returns the value with the greatest frequency.
def majority_element(a):
return max([(a.count(elem), elem) for elem in set(a)])[1]
EDIT
If there is a tie, the biggest value is returned. E.g: a = [1,1,2,2] returns 2. Might not be what you want but that could be changed.
EDIT 2
The pseudocode you gave divided into arrays 1 to k included, k + 1 to n. Your code does 1 to k - 1, k to end, not sure if it changes much though ? If you want to respect the algorithm you gave, you should do:
elemlsub = GetMajorityElement(a[:k+1]) # this slice is indices 0 to k
elemrsub = GetMajorityElement(a[k+1:]) # this one is k + 1 to n.
Also still according to your provided pseudocode, lcount and rcount should be compared to k + 1, not k:
if lcount > k + 1:
return elemlsub
elif rcount > k + 1:
return elemrsub
else:
return None
EDIT 3
Some people in the comments highligted that provided pseudocode solves not for the most frequent, but for the item which is present more that 50% of occurences. So indeed your output for your example is correct. There is a good chance that your code already works as is.
EDIT 4
If you want to return None when there is a tie, I suggest this:
def majority_element(a):
n = len(a)
if n == 1:
return a[0]
if n == 0:
return None
sorted_counts = sorted([(a.count(elem), elem) for elem in set(a)], key=lambda x: x[0])
if len(sorted_counts) > 1 and sorted_counts[-1][0] == sorted_counts[-2][0]:
return None
return sorted_counts[-1][1]

Recursive Sub-Palindrom with length of SubPalindrom

I'm trying to make a recursive function, which calculates the biggest sub-palindrome.
For example the biggest sub.Pal. for "character" is "carac".
So far I've achieved my goal but only with a global variable "length" where i'm adding my values, but it would be nice if someone could show me how to do this with only recursive calls. I first tried to give the function a second parameter (length=0) and to add the value to it when i'm calling the function,but i'm not getting it to work properly.
Here's my Code:
length = 0
def subpalindrom(s):
global length
if len(s) == 1:
length += 1
return True, length
if len(s) == 0:
return True, length
elif s[0] != s[-1]:
for i in range(len(s) - 1, int(len(s) / 2) - 1, -1): # search right half, if there is smth. equal
if s[0] == s[i]:
length += 2
return subpalindrom(s[1:i]) # if smth. is equal slice it, add length
elif i == int(len(s) / 2):
# if index i is at half of the string and nothing was found, continue with next val on left half
return subpalindrom(s[1:])
else:
length += 2
return subpalindrom(s[1:-1])
print(subpalindrom("character"))
And if anyone could tell me how i can see which time complexity this function has it would be more than great. I would say that it is O(log n) but it's just a guess.
Edit: T(n) = T(n-2) + n/2 ?
T(n-2) for recursive calls (because we slice 2 elements away) and + n/2 because of the for loop?
Thank you for your Time !
Sry for the late share,but if anyone is interested, here is how i handled it:
def subpalindrom(l, r, w):
if l == r:
return 1
if l > r:
return 0
if w[l] == w[r]:
return 2 + subpalindrom(l + 1, r - 1, w)
else:
return max(subpalindrom(l + 1, r, w), subpalindrom(l, r - 1, w))
print(subpalindrom(0, len("character")-1, "character"))

Converting phone number range list to prefix list

I have a phone number range, for example:
3331234-3332345
I need to write a function that converts it to list of prefixes:
3331234
...
3331239
333124
...
333129
33313
...
33319
33320
...
33322
333231
333232
333233
3332341
...
3332345
Question is not so easy. I don't need to get a list of numbers between range start and end.
My working code. It not very quick, too. Optimizations welcome.
def diap_to_prefix(a, b):
lst = ['%0*d'%(max(len(str(a)), len(str(b))), x) for x in range(int(a), int(b)+1)]
new_lst = []
while len(lst) != len(new_lst):
lst = new_lst or lst
new_lst = []
c = lst[0]
tmp_lst = [c]
for i in lst[1:]:
if c[:-1] == i[:-1]:
c = i
tmp_lst.append(c)
else:
if len(tmp_lst) == 10:
new_lst.append(c[:-1])
else:
new_lst.extend(tmp_lst)
c = i
tmp_lst = [c]
if len(tmp_lst) == 10:
new_lst.append(c[:-1])
else:
new_lst.extend(tmp_lst)
return lst
My new more optimal solution (py3.4)
def diap_to_prefix(a, b):
def inner(aa, bb, p):
if p == 1:
if a <= aa <= b:
yield aa
return
for d in range(aa, bb + 1, p):
if a <= d and d + p - 1 <= b:
yield d // p
elif not (bb < a or aa > b):
for i in range(10):
yield from inner(d + i * p // 10, d + (i + 1) * p // 10 - 1, p // 10)
a, b = int(a), int(b)
p = 10**(max(len(str(x)) for x in (a, b)) - 1)
yield from inner(a // p * p, b // p * p + p - 1, p)
You need to get the common prefix of the values separated by "-", so:
Use .split to get these and iterate through them until you find a difference
Complete the first value with zeros (to get the least number) until you get phone_len digits and do the same for the maximum (with nines)
Then, you have a simple range of numbers
Iterate through them and convert them to strings
Here it is:
phone_len = 7
R = "33312345-3332345".split("-")
prefix = ""
for i in range(len(R[0])):
if R[0][i] == R[1][i]:
prefix += R[0][i]
else:
break
m = int(R[0]+"0"*(phone_len-len(R[0])))
M = int(R[1]+"9"*(phone_len-len(R[0])))
phones = [str(n) for n in range(m, M+1)]
Here's a sketch of one way to handle this problem. I've used ellipses to mark the spots where you'll need to fill in the details explained in the comments. I'd write a function to derive the initial value of 'maxpower', everything else is simple enough to be written inline.
firstnumber = 3331234
lastnumber = 3332345
current = firstnumber
while current <= lastnumber:
# Find the largest power of 10 that exactly divides 'current'.
# Call this value 'maxpower'. 'maxpower' is a candidate for the
# size of the block of numbers that will be represented by the
# next output value.
maxpower = ... # 1, 10, 100, 1000, 10000, and so on
# If a block of size 'maxpower' would take us past the
# 'lastnumber', we can't use that block size. We must try a
# smaller block. Divide 'maxpower' by 10 until the block size
# becomes acceptable.
while (current + maxpower) > ... :
maxpower /= 10
# Now 'maxpower' is the largest acceptable size for the next
# block, so the desired prefix is 'current' divided by 'maxpower'.
# Emit that value, then add 'maxpower' to 'current' to get the new
# 'current' value for the next iteration.
print ...
current += maxpower
My working code. It not very quick, but working. Optimizations welcome.
def fill(root, prefix, value, parent, pkey):
if len(prefix) > 1:
if prefix[0] in root:
fill(root[prefix[0]], prefix[1:], value, root, prefix[0])
if pkey:
if len(parent[pkey]) == 10:
parent[pkey] = value
elif type(root) == type({}):
root[prefix[0]] = {}
fill(root[prefix[0]], prefix[1:], value, root, prefix[0])
if pkey:
if len(parent[pkey]) == 10:
parent[pkey] = value
elif type(root) == type({}):
root[prefix[0]] = value
if pkey:
if len(parent[pkey]) == 10:
parent[pkey] = value
return root
def compact(prefixes, current):
if not type(prefixes) == type({}):
return [current]
else:
rlist = []
for k, v in prefixes.iteritems():
rlist.extend(compact(v, current + k))
continue
return rlist
if __name__ == '__main__':
plist = {}
for x in range(4440000, 4490000):
fill(plist, str(x), 'value', plist, None)
#print plist
print compact(plist, '')

Categories