Translating recursion to divide and conquer - recursion

I'm trying to return the three smallest items in a list. Below is an O(n) solution I've written:
def three_smallest(L):
# base case
if (len(L) == 3):
return sorted(L)
current = L[0]
(first_smallest,second_smallest,third_smallest) = three_smallest(L[1:])
if (current < first_smallest):
return (current, first_smallest, second_smallest)
elif (current < second_smallest):
return (first_smallest, current, second_smallest)
elif (current < third_smallest):
return (first_smallest, second_smallest, current)
else:
return (first_smallest,second_smallest,third_smallest)
Now I'm trying to write a divide and conquer approach but I'm not sure how I should divide the list. Any help would be appreciated.
Note that this solution (to my understanding) is NOT divide and conquer. It is just a basic recursive solution as divide and conquer involves dividing a list of length n by integer b, and calling the algorithm on those parts.

For divide and conquer you generally want to divide a set (roughly) in half rather than whittle it away one by one. Perhaps the following would meet your needs?
def three_smallest(L):
if (len(L) <= 3): # base case, technically up to 3 (can be fewer)
return sorted(L)
mid = len(L) // 2 # find the midpoint of L
# find (up to) the 3 smallest in first half, ditto for the second half, pool
# them to a list with no more than 6 items, sort, and return the 3 smallest
return sorted(three_smallest(L[:mid]) + three_smallest(L[mid:]))[:3]
Note that due to the inequality in the base case, this implementation does not have a minimum list size requirement.
At the other end of the scale, your original implementation is limited to lists with fewer than a thousand values or it will blow out the recursion stack. The implementation given above was able to handle a list of a million values with no problem.

Related

How to find n as sum of dustinct prime numbers (when n is even number)

This problem gives you a positive integer number which is less than or equal to 100000 (10^5). You have to find out the following things for the number:
i. Is the number prime number? If it is a prime number, then print YES.
ii. If the number is not a prime number, then can we express the number as summation of unique prime numbers? If it is possible, then print YES. Here unique means, you can use any prime number only for one time.
If above two conditions fail for any integer number, then print NO. For more clarification please see the input, output section and their explanations.
Input
At first you are given an integer T (T<=100), which is the number of test cases. For each case you will be given a positive integer X which is less than or equal 100000.
Output
For every test case, print only YES or NO.
Sample
Input Output
3
7
6
10 YES
NO
YES
Case – 1 Explanation: 7 is a prime number.
Case – 2 Explanation: 6 is not a prime number. 6 can be expressed as 6 = 3 + 3 or 6 = 2 + 2 + 2. But you can’t use any prime number more than 1 time. Also there is no way to express 6 as two or three unique prime numbers summation.
Case – 3 Explanation: 10 is not prime number but 10 can be expressed as 10 = 3 + 7 or 10 = 2 + 3 + 5. In this two expressions, every prime number is used only for one time.
Without employing any mathematical tricks (not sure if any exist...you'd think as a mathematician I'd have more insight here), you will have to iterate over every possible summation. Hence, you'll definitely need to iterate over every possible prime, so I'd recommend the first step being to find all the primes at most 10^5. A basic (Sieve of Eratosthenes)[https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes] will probably be good enough, though faster sieves exist nowadays. I know your question is language agnostic, but you could consider the following as vectorized pseudocode for such a sieve.
import numpy as np
def sieve(n):
index = np.ones(n+1, dtype=bool)
index[:2] = False
for i in range(2, int(np.sqrt(n))):
if index[i]:
index[i**2::i] = False
return np.where(index)[0]
There are some other easy optimizations, but for simplicity this assumes that we have an array index where the indices correspond exactly to whether the number is prime or not. We start with every number being prime, mark 0 and 1 as not prime, and then for every prime we find we mark every multiple of it as not prime. The np.where() at the end just returns the indices where our index corresponds to True.
From there, we can consider a recursive algorithm for actually solving your problem. Note that you might feasibly have a huge number of distinct primes necessary. The number 26 is the sum of 4 distinct primes. It is also the sum of 3 and 23. Since the checks are more expensive for 4 primes than for 2, I think it's reasonable to start by checking the smallest number possible.
In this case, the way we're going to do that is to define an auxiliary function to find whether a number is the sum of precisely k primes and then sequentially test that auxiliary function for k from 1 to whatever the maximum possible number of addends is.
primes = sieve(10**5)
def sum_of_k_primes(x, k, excludes=()):
if k == 1:
if x not in excludes and x in primes:
return (x,)+excludes
else:
return ()
for p in (p for p in primes if p not in excludes):
if x-p < 2:
break
temp = sum_of_k_primes(x-p, k-1, (p,)+excludes)
if temp:
return temp
return ()
Running through this, first we check the case where k is 1 (this being the base case for our recursion). That's the same as asking if x is prime and isn't in one of the primes we've already found (the tuple excludes, since you need uniqueness). If k is at least 2, the rest of the code executes instead. We check all the primes we might care about, stopping early if we'd get an impossible result (no primes in our list are less than 2). We recursively call the same function for smaller k, and if we succeed we propagate that result up the call stack.
Note that we're actually returning the smallest possible tuple of unique prime addends. This is empty if you want your answer to be "NO" as specified, but otherwise it allows you to easily come up with an explanation for why you answered "YES".
partial = np.cumsum(primes)
def max_primes(x):
return np.argmax(partial > x)
def sum_of_primes(x):
for k in range(1, max_primes(x)+1):
temp = sum_of_k_primes(x, k)
if temp:
return temp
return ()
For the rest of the code, we store the partial sums of all the primes up to a given point (e.g. with primes 2, 3, 5 the partial sums would be 2, 5, 10). This gives us an easy way to check what the maximum possible number of addends is. The function just sequentially checks if x is prime, if it is a sum of 2 primes, 3 primes, etc....
As some example output, we have
>>> sum_of_primes(1001)
(991, 7, 3)
>>> sum_of_primes(26)
(23, 3)
>>> sum_of_primes(27)
(19, 5, 3)
>>> sum_of_primes(6)
()
At a first glance, I thought caching some intermediate values might help, but I'm not convinced that the auxiliary function would ever be called with the same arguments twice. There might be a way to use dynamic programming to do roughly the same thing but in a table with a minimum number of computations to prevent any duplicated efforts with the recursion. I'd have to think more about it.
As far as the exact output your teacher is expecting and the language this needs to be coded in, that'll be up to you. Hopefully this helps on the algorithmic side of things a little.

Dynamic Programming, Arithmetic Progression, Time complexity issues

Given an array of size n (1<=n<=200000) with each entry a[i] ( 1<=a[i]<=100), find all the number of subsequences that form Arithmetic progression.
Subsequences are the sequences where you can leave any number of elements in the original sequence.
For example, the sequence A,B,D is a subsequence of A,B,C,D,E,F obtained after removal of elements C, E and F. The relation of one sequence being the subsequence of another is a preorder.
I have written O(n^2) solution using DP. But n^2 = 10^10. So, It'll not get accepted.
Here is what I did.
Pseudocode:
for every element A[i]:
for every element A[k] such that k<i:
diff = A[i] - A[k] + 100: (adding 100, -ve differences A.P.)
dp[i][diff] += dp[i-1][diff] + 1;
for every element A[i]:
for every diff, d:
ans = ans + dp[i][d];
return ans;
This is giving correct output but TLE for 3 big cases.
P.S. Please suggest better solution..!!
Is divide and conquer optimization DP required here?? If yes, tell me how to build the solution.

working with powers in ocaml

I am trying to write a recursive function that will return true if second number is power of first number.
For example:
find_power 3 9 will return true
find_power 2 9 will return false because the power of 2 is 8 not 9
This is what I have tried but I need a recursive solution
let rec find_power first second =
if (second mod first = 0)
return true
else
false ;;
A recursive function has the following rough form
let rec myfun a b =
if answer is obvious then
obvious_answer
else
let (a', b') = smaller_example_of_same_problem a b in
myfun a' b'
In your case, I'd say the answer is obvious if the second number is not a multiple of the first or if it's 1. That is essentially all your code is doing now, it's testing the obvious part. (Except you're not handling the 0th power, i.e., 1.)
So, you need to figure out how to make a smaller example of the same problem. You know (by hypothesis) that the second number is a multiple of the first one. And you know that x * a is a power of a if and only if x is a power of a. Since x is smaller than x * a, this is a smaller example of the same problem.
This approach doesn't work particularly well in some edge cases, like when the first number is 1 (since x is not smaller than x * 1). You can probably handle them separately.

counting number of arithmetic progressions in an array

My previous qs. was unclear so I am again putting it in clear terms.
I need an efficient algorithm to count the number of arithmetic progressions in a series. The number of elements in a single AP should be >2.
eg. if the series is {1,2,2,3,4,4} then the different solutions are listed below(with index numbers):
0,1,3
0,2,3
0,1,3,4
0,1,3,5
0,2,3,4
0,2,3,5
hence the answer should be 6
I am not able to code it when these numbers become large and size of array increases. I need an efficient algorithm for this.
First of all, you answer is incorrect. Numbers 2,3,4 (indexes also 2,3,4) form an AP.
Second, here is a simple brute force algorithm:
def find (vec,value,start):
for i from start to length(vec):
if vec[i] == value:
return i
return None
for i from 0 to length(vec) - 2:
for j from i to length(vec) - 1:
next = 2 * vec[j] - vec[i] # the next element in the AP
pos = find(vec,next,j+1)
if pos is None:
continue
print "found AP:\n %d\n %d\n %d" % (i,j,pos)
prev = vec[j]
here = next
until (pos = find(vec,next = 2*here-prev,pos+1)) is None:
print ' '+str(pos)
prev = here
here = next
I don't think you can do better than this O(n^4) because the total number of APs to be printed is O(n^4) (consider a vector of zeros).
If, on the other hand, you want to only print maximal APs, i.e., APs which are not contained in any other AP, then the problem becomes much more interesting...

Finding the k-th largest number in a vector recursively

I have an unsorted vector and i want to return the k-th largest number in this vector recursively. There is a way to do this?
Ex: 2 3 41 67 0 9
And I want to return the second largest number which is 41.
Thanks!
Well,
search for the highest number in the vector, remove it from the vector, repeat k times.
In pseudo-code:
function findKthHighestNumber(vetor, k):
i := findIndexOfHighestNumber(vector)
if k = 1:
return vector[i]
else
return findKthHighestNumber(concat(vector[0..i-1], vector[i+1..vector.length]), k-1)
Of course, the actual implementation would depend on the programming language used. Also, findIndexOfHighestNumber should be provided as well, but that's a different task ...
You use a helper like
(define (nth-max vec nth cur-idx cur-max lower-than)
...)
or the same as named let. The logic in it should:
If cur-idx is same as vector-length
A. nth is larger than 1: recur with lower-than as cur-max and reduce nth by 1 and set cur-idx to 0.
B. Else cur-max is the solution.
Recur with cur-idx as cur-max if it's higher than cur-max and lower than lower-than
You can start off lower-than as +Inf.0 and cur-max as first element as -Inf.0. If the result is -Inf.0 then there is no solution.. eg. Find second largest in #(5 5 5 5)

Resources