Target sum of an infinite stream of numbers in python - python

I'm trying to find is a target sum could be found from an infinite stream of numbers in Python. The numbers are positive (numbers> 0), unique and the numbers are indefinite. I believe the answer would be to use dynamic programming or heap but can't quite figure out a logic.
Any help on possible data structure or flow of logic to try.
Thank you so much.
e.g
nums = [ 99,85,1,3,6,72,7,9,22,....]
targetSum = 27
output: True
Explanation: 1+6+22 = 27(targetSum)

You can use a set to keep track of all the possible sums given the numbers so far in the iterations. For each iteration, add the current number to each existing sum in the set to add to the set, and add the current number itself to the set. Return True when the target sum is indeed in the set:
def has_sum(nums, targetSum):
sums = set()
for i in nums:
sums.update([s + i for s in sums if s + i <= targetSum])
if i <= targetSum:
sums.add(i)
if targetSum in sums:
return True
return False
so that:
has_sum([99, 85, 1, 3, 6, 72, 7, 9, 22], 29)
returns True (because 1 + 6 + 22 = 29), and that:
has_sum([99, 85, 1, 3, 6, 72, 7, 9, 22], 27)
returns False (because the expected output in your question is incorrect).

#Pavis,
One idea that I can think of is to use tight graph. You can do the following:
add each number element that is less than the sum into the graph as a node
each new node is connected to every other node already present in the graph
after addition to graph, compute the sum using breadth first search from the lowest element
I think this process is slow tho

You can recursively try to satisfy the target sum with or without the first number in the given sequence, until there is no more number in the given sequence, or until the given target sum is no longer positive (since you mentioned in the comment that all given numbers are positive):
def has_sum(nums, targetSum):
if not nums or targetSum <= 0:
return False
first, *rest = nums
return first == targetSum or has_sum(rest, targetSum - first) or has_sum(rest, targetSum)
so that:
has_sum([99, 85, 1, 3, 6, 72, 7, 9, 22], 29)
returns True (because 1 + 6 + 22 = 29), and that:
has_sum([99, 85, 1, 3, 6, 72, 7, 9, 22], 27)
returns False (because the expected output in your question is incorrect).
EDIT: To avoid performance impact from copying the input sequence minus the first item to rest in every call, the code above can be improved with an index instead:
def has_sum(nums, targetSum, index=0):
if index == len(nums) or targetSum <= 0:
return False
num = nums[index]
return num == targetSum or has_sum(nums, targetSum - num, index + 1) or has_sum(nums, targetSum, index + 1)

Related

Unable to prevent 'list index out of range' error in fibonacci 'for' loop iteration

I'm still something of a beginner with Python and I was trying to optimise a function to generate the Fibonacci sequence to a specified number of values. This is the code I have written:
def attempt2(length):
listy=[]
for i in range(0,length+1):
if i == 0:
listy.append(1)
elif i == 1:
listy.append(1)
else:
listy.append(listy[i]+listy[i-1])
return listy
Whilst keeping this structure I have found no way to overcome the 'list index out of range' error. I think because the listy[i-1] would be out of range when i = 0, but if the function progresses through the loop linearly then the else statement should only take effect when i = 2. Can anyone see what I'm doing wrong?
Thanks!
So, to find out the source of your issue, we need to take a step back to see what your loop is doing.
Initially, your for-loop is counting from 0 to whatever the length is, let's see what the values for i will look like:
0
1
2
...
so starting from 2, since the behavior of 0,1 is defined:
listy.append(listy[2]+listy[1])
Remember that listy has 2 items now, which are zero indexed, in other words the items are 1 and 0, hence the item listy[2] doesn't exist.
Thus, your code should be
listy.append(listy[i-2]+listy[i-1])
It's not a good solution overall but the tiny mistake is that you should change line 9 to:
listy.append(listy[i - 1] + listy[i - 2])
Also you'll have a `length + 1` size list not `length`.
You are using wrong list indices
def attempt2(length):
listy=[]
for i in range(0,length):
if i == 0:
listy.append(1)
elif i == 1:
listy.append(1)
else:
listy.append(listy[i -1]+listy[i - 2])
return listy
print(attempt2(12))
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
Listy[-1] returns the last element of your list.
List position is initialising at 0 not 1.
When i = 2, in your else statement
listy.append(listy[i]+listy[i-1]) is equivalent to listy.append(listy[2]+listy[1])
Yet, your list after the second loop is equal to [1,1].
The max pos is 1 and 2 is out of range.
def loop_fib(n):
# first two numbers are 1
fib_1=1
fib_2=1
res=[1,1]
# n is inclusive
for i in range(3,n+1):
# new fib_2=fib_1+fib_2
# new fib_1=old fib_2
fib_1,fib_2=fib_2,fib_1+fib_2
res.append(fib_2)
return res
loop_fib(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Faster way to find the biggest prime number less than or equal to the given input

Given an integer number, I want to find the biggest prime number under it. For example:
input 20 -> output 19
input 100 -> output 97.
I already have the simple program given below, but I'm curious about how to make it faster.
def isPrime(x):
for j in range(2,int(x**0.5)+1):
if x%j==0:
return False
return True
def findPrimeNum(num):
for i in range(num-1,1,-1):
if isPrime(i):
return i
findPrimeNum(600851475143) # -> 600851475067
The best way is probably to mirror what several number theory libraries use to implement an efficient next_prime function. The basic layout is identical to yours: an isPrime(x) function, and a loop counting down. Those provide two areas for optimization.
Optimizing isPrime
The recommended approach is to use a number theory library for Python like gmpy2, and a probabilistic primality test like Miller-Rabin repeated an appropriate number of times. This scales fairly well with larger numbers, and you can even get a deterministic primality test by using Miller-Rabin with enough small bases.
Optimizing iteration over possible primes
There is already a comprehensive guide for optimizing next_prime in practice, which basically involves choosing the first k primes (e.g. 2, 3 and 5) and computing all residues modulo their product that could potentially be a prime. Then, rather than iterating over all smaller numbers, you jump between those residues only. To adapt this to previousPrime, we just jump between residues in the opposite direction.
For 2, 3, and 5, those residues mod 30 are L = [1, 7, 11, 13, 17, 19, 23, 29]. For an integer x > 30, say x = 30*q + r, you would do a binary search over L for the largest element less than r, and iterate backwards in this list:
residues = [1, 7, 11, 13, 17, 19, 23, 29]
small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
def prevPrime(num):
if num <= 2:
return 0
q, r = divmod(num, 30)
if q == 0:
return small_primes[bisect_left(small_primes, num) - 1]
num = 30 * q
if r <= 2:
num -= 30
q -= 1
idx = len(residues) - 1
else:
idx = bisect_left(residues, r) - 1
num += residues[idx]
while not (isPrime(num)):
idx -= 1
if idx < 0:
q -= 1
idx = len(residues) - 1
num = 30 * q + residues[idx]
return num

Sorting in ascending order with selection sort

I'm in need of big help, I cant seem to figure out how to do this code. So I am sorting an unsorted list of numbers in ascending order using selection sort and then returning the number of swaps it takes to sort the list.
Below is my code:
def swaps(numbers):
count = 0
for i in range(len(numbers)):
minIndex = i
for j in range(i + 1, len(numbers)):
if numbers[j] < numbers[minIndex]:
minIndex = j
if i != minIndex:
numbers[i], numbers[minIndex] = numbers[minIndex], numbers[i]
count += 1
return count
For these two test cases:
numbers = [0, 4, 2, 7, 5]
print(swaps(numbers))
numbers = [9, 8, 7, 6, 5, 4]
print(swaps(numbers))
it works perfect but for this test case it doesn't work:
import random
random.seed(30)
numbers = [random.randint(1, 50) for index in range(10)]
print(numbers)
print(swaps(numbers))
The numbers list for this test case is [35, 19, 40, 2, 40, 42, 14, 17, 4, 26]. Now working it out it swaps it 7 times but in my test program it is suppose to have swapped 8 times. Is this because of the repeat of 40 ?
How do I configure my code so that it takes into account a repeat of the same number?
If you are supposed to count an extra swap when you have a single pair of duplicate values, an easy way to match that expectation is to change the numbers[j] < numbers[minIndex] check to use <= instead of <.
That's making the code worse though, so I'd be sure to double check if that expectation is actually real or not. Managing to sort with fewer swaps should be a feature, not a bug!

Algorithm for finding if an array is balanced [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm trying to create a program that will create a 10 element array and then assign random values to each element. I then want the program to tell if the array is balanced. By balanced I mean, is there anywhere in the array values that at a certain element the sum of the values in the elements are equal to the sum of the array values in the elements greater than that current element.
Example
Element (1,2,3,4) Values (2,1,3,0)
The program would then display that elements 1-2 are balanced to elemtns 3-4, because they both equal 4.
So far I have
import random
size = 10
mean = 0
lists = [0] * size
for i in range(size):
var = random.randint(0,4)
lists[i] = var
for i in lists:
mean += i
avg = (mean)/(size)
I figured the only way the elements could be balanced is if the values average is equal to 2, so I figured that's how I should start.
I'd appreciate any help in the right direction.
If I understand the question, the simplest solution is something like this:
def balanced(numbers):
for pivot in range(len(numbers)):
left_total = sum(numbers[:pivot])
right_total = sum(numbers[pivot:])
if left_total == right_total:
return pivot
return None
For example:
>>> numbers = [2, 1, 3, 0]
>>> balanced(numbers)
2
>>> more_numbers = [2, 1, 3, 4]
>>> balanced(numbers)
(That didn't print anything, because it returned None, meaning there is no pivot to balance the list around.)
While this is the simplest solution, it's obviously not the most efficient, because you keep adding the same numbers up over and over.
If you think about it, it should be pretty easy to figure out how to keep running totals for left_total and right_total, only calling sum once.
def balanced(numbers):
left_total, right_total = 0, sum(numbers)
for pivot, value in enumerate(numbers):
if left_total == right_total:
return pivot
left_total += value
right_total -= value
return None
Finally, here's how you can build a program around it:
size = 10
numbers = [random.range(4) for _ in range(size)]
pivot = balanced(numbers)
if pivot is None:
print('{} is not balanced'.format(numbers))
else:
print('{} is balanced, because elements 1-{} equal {}-{}'.format(
numbers, pivot+1, pivot+2, size+1))
A good data structure to know about for this kind of problem is an array that has the cumulative sum. element[j] - element[i] is the sum from i to j in the original series. If you have the original series [1, 2, 3, 4], the cumulative series is [0, 1, 3, 6, 10]. The sum up to the i position in the original series is element[i] - element[0]. For this problem, we are interested in only a sum starting at 0, so this is a bit of overkill but, again, more fully useful for other problems.
Here is code to make a cumulative sum:
def cumulative_sum(series):
s = [0]
for element in series:
s.append(element + s[-1])
return s
Given that, we can find the pivot point with this code:
def find_pivot(series):
cs = cumulative_sum(series)
total = cs[-1]
even_total = not (total & 1)
if even_total:
target = total // 2
for i, element in enumerate(cs[1:]):
if element == target:
return i + 1
return -1
Notice that it is not necessary to try dividing the series if we know the series sums to an odd number: there cannot be a pivot point then.
Alternatively, you can write find_pivot like this:
def find_pivot(series):
cs = cumulative_sum(series)
total = cs[-1]
even_total = not (total & 1)
if even_total:
target = total // 2
try:
return cs.index(target)
except ValueError:
return -1
return -1
It has the advantage that the looping is not done explicitly in python but in C code in the standard library.
Trying the code out:
def test():
for i in range(1, 30):
test_values = range(i)
j = find_pivot(test_values)
if j >= 0:
print "{0} == {1}".format(test_values[:j], test_values[j:])
And we get this output:
[0] == []
[0, 1, 2] == [3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] == [15, 16, 17, 18, 19, 20]

Determining if a list of numbers is in heap order, Python 3.2

I just discovered heap (in real life and in Python) and now I'm trying to determine if a certain list of random numbers is in heap order.
Problem is I'm not sure myself if I actually understand "heap" in practice even though I believe the definition provided makes sense.
I found some practice problems that should help you write heap psuedo code.
This is the problem and below it is my attempt at solving it:
Write a function that checks whether a list of numbers is a heap or not:
Given a list, it returns True if the numbers are in a heap order, and False if the numbers are not and have the programme return and print the answer.
Example:
returns True:
the following list is in heap order: [0,1, 10, 2, 3, 11, 12, 4, 5, 19, 15]
returns False
the following list is not in heap order: [0, 1, 10, 2, 15, 11, 12, 4, 5, 19, 3]
Then there were 2 lists with a bunch of random numbers from 1 - 100 thrown in there, and some repeat.
def heap_or(A):
n = len(A)
for i in range(n):
start = (len(A) - 2) / 2
while start >= 0:
siftDown(A, start, len(A) - 1)
start -= 1:
return 'True'
else:
return 'False'
def siftDown(A, start, end):
root = start
while root * 2 + 1 <= end:
number = root * 2 + 1
if number + 1 <= end and A[number] < A[number + 1]:
number += 1
if number <= end and A[root] < A[number]:
A[root], A[number] = A[number], A[root]
root = number
else:
return
print
Can somebody please give me a hand? Because I'm not really sure if I'm defining heap correctly the code is giving me a hard time as well!
The heap property (for a max heap) is that each node should be greater than or equal to its parent. The parent of element i in a binary heap stored in an array is element (i - 1) // 2:
def is_heap(A):
return all(A[i] >= A[(i - 1) // 2] for i in range(1, len(A)))
Obviously because the heap is stored in array we don't need to check the shape.

Categories

Resources