Python Subset Sum Problem for Given Length of Elements - python

For given set, and sum, and length of elements,
I want to get the boolean value whether the set satisfy the condition
For example...
Input : set = [18,0,2,20], sum = 20, length = 2 <br>
Output : True (subset [18,2] satisfy the sum=20 for given length 2)
Input : set = [18,0,2,20], sum = 22, length = 1 <br>
Output : False
How can I solve the problem if there is a given length constraint?
(I can solve it easily if there is no length condition:
subset-sum-problem)
def isSubsetSum(set, n, sum):
if sum == 0:
return True
if (sum != 0) and (n == 0):
return False
if (set[n-1] > sum):
return isSubsetSum(set,n-1,sum)
# (a) including the last element
# (b) excluding the last element
# Not "AND", But "OR" !!!!!
return isSubsetSum(set,n-1,sum) or isSubsetSum(set,n-1,sum-set[n-1])

If you're allowed to use imported modules, itertools has a combinations function that can make this quite easy:
from itertools import combinations
set = [18,0,2,20]
total = 20
length = 2
result = [ c for c in combinations(set,length) if sum(c) == total ]
if result:
print("True, subset ",result[0],"satisfies the sum", total, "given length",length)
else:
print("False")
If you need it to be a recursive function, consider that for each element X in the set, if you can find a subset of N-1 elements in the subsequent elements that total sum-X, you have a solution for sum/length=N.
For example:
def subSum(numbers,total,length):
if len(numbers) < length or length < 1:
return []
for index,number in enumerate(numbers):
if length == 1 and number == total:
return [number]
subset = subSum(numbers[index+1:],total-number,length-1)
if subset:
return [number] + subset
return []

Use itertools.combinations:
from itertools import combinations
inp = [18,0,2,20]
length = 2
sum_ = 20
def isSubsetSum(data, length, sum_):
data = [i[0]+i[1] for i in combinations(data,length)]
if sum_ in data:
return True
return False
print(isSubsetSum(inp,length, sum_))

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

Returning smallest positive int that does not occur in given list

Write a function that given an array of A of N int, returns the smallest positive(greater than 0) that does not occur in A.
I decided to approach this problem by iterating through the list after sorting it.
The value of the current element would be compared to the value of the next element. Because the list is sorted, the list should follow sequentially until the end.
However, if there is a skipped number this indicates the smallest number that does not occur in the list.
And if it follows through until the end, then you should just add one to the value of the last element.
def test():
arr = [23,26,25,24,28]
arr.sort()
l = len(arr)
if arr[-1] <= 0:
return 1
for i in range(0,l):
for j in range(1,l):
cur_val = arr[i]
next_val = arr[j]
num = cur_val + 1
if num != next_val:
return num
if num == next_val: //if completes the list with no skips
return arr[j] + 1
print(test())
I suggest that you convert to a set, and you can then efficiently test whether numbers are members of it:
def first_int_not_in_list(lst, starting_value=1):
s = set(lst)
i = starting_value
while i in s:
i += 1
return i
arr = [23,26,25,24,28]
print(first_int_not_in_list(arr)) # prints 1
You can do the following:
def minint(arr):
s=set(range(min(arr),max(arr)))-set(arr)
if len(s)>0:
return min(set(range(min(arr),max(arr)))-set(arr)) #the common case
elif 1 in arr:
return max(arr)+1 #arr is a complete range with no blanks
else:
return 1 #arr is negative numbers only
You can make use of sets to achieve your goal.
set.difference() method is same as relative complement denoted by A – B, is the set of all elements in A that are not in B.
Example:
Let A = {1, 3, 5} and B = {1, 2, 3, 4, 5, 6}. Then A - B = {2, 4, 6}.
Using isNeg() method is used to check whether given set contains any negative integer.
Using min() method on A - B returns the minimum value from set difference.
Here's the code snippet
def retMin(arrList):
min_val = min(arrList) if isNeg(arrList) else 1
seqList=list(range((min_val),abs(max(arrList))+2))
return min(list(set(seqList).difference(arrList)))
def isNeg(arr):
return(all (x > 0 for x in arr))
Input:
print(retMin([1,3,6,4,1,2]))
Output:
5
Input:
print(retMin([-2,-6,-7]))
Output:
1
Input:
print(retMin([23,25,26,28,30]))
Output:
24
Try with the following code and you should be able to solve your problem:
def test():
arr = [3,-1,23,26,25,24,28]
min_val = min(val for val in arr if val > 0)
arr.sort()
l = len(arr)
if arr[-1] <= 0:
return 1
for i in range(0,l):
if arr[i] > 0 and arr[i] <= min_val:
min_val = arr[i] + 1
return min_val
print(test())
EDIT
It seems you're searching for the the value grater than the minimum positive integer in tha array not sequentially.
The code it's just the same as before I only change min_val = 1 to:
min_val = min(val for val in arr if val > 0), so I'm using a lambda expression to get all the positive value of the array and after getting them, using the min function, I'll get the minimum of those.
You can test it here if you want

Finding how many times a certain character appears in a multiplied string

We want to find the number of 'a's in a given string s multiplied infinite times.
We will be given a number n that is the slicing size of the infinite string.
sample input:
aba 10
output:
7
Here aba is multiplied with 10, resulting in 'abaabaabaa'
and the no. of 'a's are 7.
This is my code:
def repeatedString(s, n):
count = 0
inters = s * n
reals = s[0:n+1]
for i in reals:
if (i == 'a'):
count += 1
return count
I'm getting 2 instead of 7 as the output (test case 'aba' 10). Where did I go wrong? I just multiplied the given string with n because it will never be greater than the slicing size.
Here's the link to the problem:
https://www.hackerrank.com/challenges/repeated-string/problem
Much simpler solution using python3.
s = input().strip()
n = int(input())
print(s[:n%len(s)].count('a')+(s.count('a')*(n//len(s))))
There's no reason to slice the string
def repeatedString(s, n):
count = 0
for index, i in enumerate(s*n):
if index >= n:
return count
if(i == 'a'):
count += 1
# empty string
return count
I used a simple unitary method.
Number of 'a' in one repetition is cnt_a so the number of 'a' in first n characters will be (cnt_a/len(s)) * n
def repeatedString(s, n):
if len(s)==1 and s=='a':
return n
cnt_a=0
for i in s:
if i == 'a':
cnt_a+=1
if cnt_a % 2 == 0:
no_a = (cnt_a/len(s)) * n
return math.ceil(no_a)
else:
no_a = (cnt_a/len(s)) * n
return math.floor(no_a)
If you would like a more readable answer....
def repeatedString(s, n):
target = 'a'
target_count = 0
# how many times does the string need to be repeated: (n // len(s) * s) + s[:(n % len(s))]
quotient = n // len(s)
remainder = n % len(s)
for char in s: # how many times target appears in 1 instance of the substring
if char == target:
target_count += 1
# how many times the target appears in many instances of the substring provided
target_count = target_count * quotient
for char in s[:remainder]: # count the remaining targets in the truncated substring
if char == target:
target_count += 1
return target_count
One liner answer:
return [s[i%len(s)] for i in range(n)].count('a')
There is only two problem in your code
s = 'aba'
n = 10
count = 0
inters = s * n
# Here you need to slice(inters) not (s) because s only hold 'aba'
# And not n+1 it's take 11 values only n
reals = inters[0:n]
for i in reals:
if (i == 'a'):
count += 1
print(count)
so if the string contains "a"s only simply return n. otherwise, count the number of a's in the string s, now using divmond() function I have found the number of string that can be added without surpassing n. for example string s is "aba" and n=10, so I can add 3 "abs"s completely without the length of string going over 10. now the number of a's in the added string (3*2). Now the places left to be filled are equal to the remainder(y) of divmond() function. Now slice the string s up to y and find the number of a's in it and add it to count.
divmond(10,3) returns (10//3) and it's remainder.
def repeatedString(s, n):
if len(s)==1 and s=="a":
return n
count=s.count("a")
x,y=divmod(n,len(s))
count=count*x
str=s[:y]
return count+str.count("a")
The solution in Python 3:
def repeatedString(s,n):
i = 0
c = 0
for i in s:
if i == 'a':
c += 1
q = int(n / len(s)) #Finding the quotient
r = int(n % len(s)) #Finding the remainder
if r == 0:
c *= q
else:
x = 0
for i in range(r):
if s[i] == 'a':
x += 1
c = c*q + x
return int(c)
s = input()
n = int(input())
print(repeatedString(s,n))
if character 'a' is present in a given string pattern, then its quite faster to get the repeated count for it and later based on the total length of final string mentioned, will be trying to repeat the given pattern for same number of times & hence will multiple the repeated count with number of times a string pattern is going to repeat. Importantly if final string input is in odd numbers then we need to identify the those odd pattern and separately count the occurance of character 'a' in odd string pattern. Finally summing up the total count ( even & odd ) will gives us the expected result
def repeatedString(s, n):
# Get the length of input string
strlen = len(s)
a_repeat = 0
# Get the total count of a repeated character from the input string
for i in range(0,strlen):
if s[i] == 'a':
a_repeat = a_repeat + 1
# Get the multiplier to make sure that desired input string length achieved
str_multiplier = int(n // strlen)
# Get the repeated count if new string is been created
result = a_repeat*str_multiplier
new_str = s[:int( n % strlen )]
# for odd length of string, get the remaining characters and find repated characters count and add up it to final count
for i in range(0, len(new_str)):
if new_str[i] == 'a':
result += 1
return result
For this problem,
Get the length of string s.
First, if conditions: constrain
Now, instead of using a loop to add to space and time complexity, we use basic math's. Find the quotient of n//Len (s). Now find the number of times "a" is used in our string.
We can multiply the quotient with this number to get the total "a" used. Now, we can find the remainder of the string and use slice to search for "a" in the string we have left in the last.
Add both to get our answer.
def repeatedString(s, n):
#finding quotient and remainder of division
str1=len(s)
remainder=0
if 1<=str1<=100 and 1<=n<=10**12:
quotient= n//str1
a_s = s.count("a")
if a_s==0:
return 0
else:
remainder=s[:n%str1].count('a')
return quotient*a_s + remainder
Simple answer:
def repeatedString(s, n):
totalNumber = 0 // setting total of a's to 0
// using count function to find the total number of a's in the substring
totalNumber = s.count('a')
// finding how many number of times the substring fits in "n" and multiplying that by the number of a's we found earlier
totalNumber = n//len(s) * totalNumber
// if there is a remainder, we loop through the remainder string and add the number of "a's" found in that substring to the total
for i in s[:n%len(s)]:
if(i == "a"):
totalNumber +=1
return totalNumber

Binary strings recursive function

How to write a recursive function that generates a list of binary of length n with a specified number of 1s?
Here's a code that generates recursively a list of binarys; without a specified number of 1s:
def generateAllBinaryStrings(n, arr, i):
if i == n:
printTheArray(arr, n)
return
# First assign "0" at ith position
# and try for all other permutations
# for remaining positions
arr[i] = 0
generateAllBinaryStrings(n, arr, i + 1)
# And then assign "1" at ith position
# and try for all other permutations
# for remaining positions
arr[i] = 1
generateAllBinaryStrings(n, arr, i + 1)
Taken from geeksforgeeks
You could do it like this:
def binaryStrings(n, ones):
if n < ones: # impossible
return []
if n == ones:
return ["1" * ones]
if ones == 0:
return ["0" * n]
a = binaryStrings(n-1, ones)
b = binaryStrings(n-1, ones-1)
return ["0"+s for s in a] + ["1"+s for s in b]
Example call to get all 6-digit binary numbers which have exactly 4 1-digits:
print(binaryStrings(6,4))
You have to generate all possible sequences with adding a 0 or a 1 at each position. Total possible sequences = 2^MAX. Keep track of the number of 1s in the current sequence so far to break.
# Generate all binary numbers with exactly "n" 1s
# Max digits in the binary number = MAX
def binary(n):
MAX = 5
all_solutions = []
def solve(current, remaining_ones):
if len(current) > MAX:
return
if remaining_ones == 0:
all_solutions.append(current+"0"*(MAX-len(current)))
return
solve(current+"1", remaining_ones - 1)
solve(current+"0", remaining_ones)
solve("", n)
return all_solutions
print(binary(2))
# ['11000', '10100', '10010', '10001', '01100', '01010', '01001', '00110', '00101', '00011']

How to see if the list contains consecutive numbers

I want to test if a list contains consecutive integers and no repetition of numbers.
For example, if I have
l = [1, 3, 5, 2, 4, 6]
It should return True.
How should I check if the list contains up to n consecutive numbers without modifying the original list?
I thought about copying the list and removing each number that appears in the original list and if the list is empty then it will return True.
Is there a better way to do this?
For the whole list, it should just be as simple as
sorted(l) == list(range(min(l), max(l)+1))
This preserves the original list, but making a copy (and then sorting) may be expensive if your list is particularly long.
Note that in Python 2 you could simply use the below because range returned a list object. In 3.x and higher the function has been changed to return a range object, so an explicit conversion to list is needed before comparing to sorted(l)
sorted(l) == range(min(l), max(l)+1))
To check if n entries are consecutive and non-repeating, it gets a little more complicated:
def check(n, l):
subs = [l[i:i+n] for i in range(len(l)) if len(l[i:i+n]) == n]
return any([(sorted(sub) in range(min(l), max(l)+1)) for sub in subs])
The first code removes duplicates but keeps order:
from itertools import groupby, count
l = [1,2,4,5,2,1,5,6,5,3,5,5]
def remove_duplicates(values):
output = []
seen = set()
for value in values:
if value not in seen:
output.append(value)
seen.add(value)
return output
l = remove_duplicates(l) # output = [1, 2, 4, 5, 6, 3]
The next set is to identify which ones are in order, taken from here:
def as_range(iterable):
l = list(iterable)
if len(l) > 1:
return '{0}-{1}'.format(l[0], l[-1])
else:
return '{0}'.format(l[0])
l = ','.join(as_range(g) for _, g in groupby(l, key=lambda n, c=count(): n-next(c)))
l outputs as: 1-2,4-6,3
You can customize the functions depending on your output.
We can use known mathematics formula for checking consecutiveness,
Assuming min number always start from 1
sum of consecutive n numbers 1...n = n * (n+1) /2
def check_is_consecutive(l):
maximum = max(l)
if sum(l) == maximum * (maximum+1) /2 :
return True
return False
Once you verify that the list has no duplicates, just compute the sum of the integers between min(l) and max(l):
def check(l):
total = 0
minimum = float('+inf')
maximum = float('-inf')
seen = set()
for n in l:
if n in seen:
return False
seen.add(n)
if n < minimum:
minimum = n
if n > maximum:
maximum = n
total += n
if 2 * total != maximum * (maximum + 1) - minimum * (minimum - 1):
return False
return True
import numpy as np
import pandas as pd
(sum(np.diff(sorted(l)) == 1) >= n) & (all(pd.Series(l).value_counts() == 1))
We test both conditions, first by finding the iterative difference of the sorted list np.diff(sorted(l)) we can test if there are n consecutive integers. Lastly, we test if the value_counts() are all 1, indicating no repeats.
I split your query into two parts part A "list contains up to n consecutive numbers" this is the first line if len(l) != len(set(l)):
And part b, splits the list into possible shorter lists and checks if they are consecutive.
def example (l, n):
if len(l) != len(set(l)): # part a
return False
for i in range(0, len(l)-n+1): # part b
if l[i:i+3] == sorted(l[i:i+3]):
return True
return False
l = [1, 3, 5, 2, 4, 6]
print example(l, 3)
def solution(A):
counter = [0]*len(A)
limit = len(A)
for element in A:
if not 1 <= element <= limit:
return False
else:
if counter[element-1] != 0:
return False
else:
counter[element-1] = 1
return True
The input to this function is your list.This function returns False if the numbers are repeated.
The below code works even if the list does not start with 1.
def check_is_consecutive(l):
"""
sorts the list and
checks if the elements in the list are consecutive
This function does not handle any exceptions.
returns true if the list contains consecutive numbers, else False
"""
l = list(filter(None,l))
l = sorted(l)
if len(l) > 1:
maximum = l[-1]
minimum = l[0] - 1
if minimum == 0:
if sum(l) == (maximum * (maximum+1) /2):
return True
else:
return False
else:
if sum(l) == (maximum * (maximum+1) /2) - (minimum * (minimum+1) /2) :
return True
else:
return False
else:
return True
1.
l.sort()
2.
for i in range(0,len(l)-1)))
print(all((l[i+1]-l[i]==1)
list must be sorted!
lst = [9,10,11,12,13,14,15,16]
final = True if len( [ True for x in lst[:-1] for y in lst[1:] if x + 1 == y ] ) == len(lst[1:]) else False
i don't know how efficient this is but it should do the trick.
With sorting
In Python 3, I use this simple solution:
def check(lst):
lst = sorted(lst)
if lst:
return lst == list(range(lst[0], lst[-1] + 1))
else:
return True
Note that, after sorting the list, its minimum and maximum come for free as the first (lst[0]) and the last (lst[-1]) elements.
I'm returning True in case the argument is empty, but this decision is arbitrary. Choose whatever fits best your use case.
In this solution, we first sort the argument and then compare it with another list that we know that is consecutive and has no repetitions.
Without sorting
In one of the answers, the OP commented asking if it would be possible to do the same without sorting the list. This is interesting, and this is my solution:
def check(lst):
if lst:
r = range(min(lst), max(lst) + 1) # *r* is our reference
return (
len(lst) == len(r)
and all(map(lst.__contains__, r))
# alternative: all(x in lst for x in r)
# test if every element of the reference *r* is in *lst*
)
else:
return True
In this solution, we build a reference range r that is a consecutive (and thus non-repeating) sequence of ints. With this, our test is simple: first we check that lst has the correct number of elements (not more, which would indicate repetitions, nor less, which indicates gaps) by comparing it with the reference. Then we check that every element in our reference is also in lst (this is what all(map(lst.__contains__, r)) is doing: it iterates over r and tests if all of its elements are in lts).
l = [1, 3, 5, 2, 4, 6]
from itertools import chain
def check_if_consecutive_and_no_duplicates(my_list=None):
return all(
list(
chain.from_iterable(
[
[a + 1 in sorted(my_list) for a in sorted(my_list)[:-1]],
[sorted(my_list)[-2] + 1 in my_list],
[len(my_list) == len(set(my_list))],
]
)
)
)
Add 1 to any number in the list except for the last number(6) and check if the result is in the list. For the last number (6) which is the greatest one, pick the number before it(5) and add 1 and check if the result(6) is in the list.
Here is a really short easy solution without having to use any imports:
range = range(10)
L = [1,3,5,2,4,6]
L = sorted(L, key = lambda L:L)
range[(L[0]):(len(L)+L[0])] == L
>>True
This works for numerical lists of any length and detects duplicates.
Basically, you are creating a range your list could potentially be in, editing that range to match your list's criteria (length, starting value) and making a snapshot comparison. I came up with this for a card game I am coding where I need to detect straights/runs in a hand and it seems to work pretty well.

Categories