Minimum No of coins required from a given set of coins to make all numbers up to a given Number. - dynamic-programming

Ex. Set of Coins - {1,2,5,10} ; MaxSum -20
We have to find a set of coins with minimum coins which can make any number up to 20.
I came up with a greedy approach depending on division of the max sum by largest coin gives remainder 0 or 1.
20/10 = 2 -- remainder =0 ; In case of zero remainder, reduce the quotient by 1 to get number of 10 coins(2-1=1) and continue with Maxsum =10(same as coin) and set{1,2,5}
Answer Set={10} (only 1 coin of 10 added - quotient-1)
10/5=2 -- remainder =0 ; Answer Set={10,5} (add only 1(quotient-1) 5-coins) MaxSum=5
Answer Set= {10,5}
set={1,2}
5/2= 2 -- remainder =1; In case of non zero remainder, add coins equal to quotient(add 2 coins of 2 ) and set Maxsum= Subtract one from Coin chosen from set(here it is 2) = 2-1 = 1.
Answer Set = {10,5,2,2} ( coins added =quotient )
Set={1}
Maxsum=1 (one subtracted from coin chosen from set)
Base Case- Set={1} and MaxSum =1 . So we need only 1 coin of 1.
Answer Set= {10,5,2,2,1}
I have tried the same logic on a number of cases. It works but is it correct?

Related

Binary Search Complexity

What is the time complexity of binary search taking an array of n elements as input from user..
As the time complexity of binary search is O(log n)
Whereas, the time complexity of taking the array as input from user is O(n)
For the whole program the answer is: O(logn) + O(n) = O(n)
Why is it? because your input of n numbers into an array and binary search is independent of each other.
Now we need to understand time complexity in general:
In the simplest terms, for a problem where the input size is n:
Best case = fastest time to complete, with optimal inputs chosen.
For example, the best case for a sorting algorithm would be data that's already sorted.
Worst case = slowest time to complete, with pessimal inputs are chosen.
For example, the worst case for a sorting algorithm might be data that are sorted in reverse order (but it depends on the particular algorithm).
Average case = arithmetic mean. Run the algorithm many times, using many different inputs of size n that come from some distribution that generates these inputs (in the simplest case, all the possible inputs are equally likely), and compute the total running time (by adding the individual times), and divide by the number of trials. You may also need to normalize the results based on the size of the input sets.
Example (Binary search):
Suppose we have the following binary search function:
binarySearch(arr, x, low, high)
repeat till low = high
mid = (low + high)/2
if (x == arr[mid])
return mid
else if (x > arr[mid]) // x is on the right side
low = mid + 1
else // x is on the left side
high = mid - 1
Now, let's analyze its time complexity.
Best Case Time Complexity of Binary Search
The best case of Binary Search occurs when:
The element to be searched is in the middle of the list
In this case, the element is found in the first step itself and this involves 1 comparison.
Therefore, Best Case Time Complexity of Binary Search is O(1).
Average Case Time Complexity of Binary Search
Let the input be N distinct numbers: a1, a2, ..., a(N-1), aN
We need to find element P.
There are two cases:
Case 1: The element P can be in N distinct indexes from 0 to N-1.
Case 2: There will be a case when the element P is not present in the list.
There are N case 1 and 1 case 2. So, there are N+1 distinct cases to consider in total.
If element P is in index K, then Binary Search will do K+1 comparisons.
This is because:
The element at index N/2 can be found in 1 comparison as Binary Search starts from middle.
Similarly, in the 2nd comparisons, elements at index N/4 and 3N/4 are compared based on the result of 1st comparison.
On this line, in the 3rd comparison, elements at index N/8, 3N/8, 5N/8, 7N/8 are compared based on the result of 2nd comparison.
Based on this, we know that:
Elements requiring 1 comparison: 1
Elements requiring 2 comparisons: 2
Elements requiring 3 comparisons: 4
Therefore, Elements requiring I comparisons: 2^(I-1)
The maximum number of comparisons = Number of times N is divided by 2 so that result is 1 = Comparisons to reach 1st element = logN comparisons
I can vary from 0 to logN
Total number of comparisons = 1 * (Elements requiring 1 comparison) + 2 * (Elements requiring 2 comparisons) + ... + logN * (Elements requiring logN comparisons)
Total number of comparisons = 1 * (1) + 2 * (2) + 3 * (4) + ... + logN * (2^(logN-1))
Total number of comparisons = 1 + 4 + 12 + 32 + ... = 2^logN * (logN - 1) + 1
Total number of comparisons = N * (logN - 1) + 1
Total number of cases = N+1
Therefore, average number of comparisons = ( N * (logN - 1) + 1 ) / (N+1)
Average number of comparisons = N * logN / (N+1) - N/(N+1) + 1/(N+1)
The dominant term is N * logN / (N+1) which is approximately logN. Therefore, Average Case Time Complexity of Binary Search is O(logN).Let there be N distinct numbers: a1, a2, ..., a(N-1), aN
We need to find element P.
There are two cases:
Case 1: The element P can be in N distinct indexes from 0 to N-1.
Case 2: There will be a case when the element P is not present in the list.
There are N case 1 and 1 case 2. So, there are N+1 distinct cases to consider in total.
If element P is in index K, then Binary Search will do K+1 comparisons.
This is because:
The element at index N/2 can be found in 1 comparison as Binary Search starts from the middle.
Similarly, in the 2nd comparison, elements at index N/4 and 3N/4 are compared based on the result of the 1st comparison.
On this line, in the 3rd comparison, elements at index N/8, 3N/8, 5N/8, and 7N/8 are compared based on the result of the 2nd comparison.
Based on this, we know that:
Elements requiring 1 comparison: 1
Elements requiring 2 comparisons: 2
Elements requiring 3 comparisons: 4
Therefore, Elements requiring I comparisons: 2^(I-1)
The maximum number of comparisons = Number of times N is divided by 2 so that result is 1 = Comparisons to reach 1st element = logN comparisons
I can vary from 0 to logN
Total number of comparisons = 1 * (Elements requiring 1 comparison) + 2 * (Elements requiring 2 comparisons) + ... + logN * (Elements requiring logN comparisons)
Total number of comparisons = 1 * (1) + 2 * (2) + 3 * (4) + ... + logN * (2^(logN-1))
Total number of comparisons = 1 + 4 + 12 + 32 + ... = 2^logN * (logN - 1) + 1
Total number of comparisons = N * (logN - 1) + 1
Total number of cases = N+1
Therefore, average number of comparisons = ( N * (logN - 1) + 1 ) / (N+1)
Average number of comparisons = N * logN / (N+1) - N/(N+1) + 1/(N+1)
The dominant term is N * logN / (N+1) which is approximately logN. Therefore, the Average Case Time Complexity of Binary Search is O(logN).
Worst Case Time Complexity of Binary Search
The worst case of Binary Search occurs when:
The element to search is in the first index or last index
In this case, the total number of comparisons required is logN comparisons.
Therefore, the Worst Case Time Complexity of Binary Search is O(logN).

Given a binary string "10110". Find the count of all the substring with number of set bit count >= n

We could solve this question in brute force, taking all possible substrings and checking if the set bit count is greater n.
I was asked to solve this in o(n). I could not find any answer which could achieve this in o(n).
Is it possible to get all possible substrings of binary string in 0(n)?
Answer changed (noticed >= in problem statement).
Make two indices - left and right.
We want to account substrings starting from position left containing at least k ones.
At first move right until bit count reaches k.
Now we have some "good" substrings starting at left and ending in any position after right, so we can add len(s) - right + 1 to result.
Increment left by 1 until the next one.
Repeat moving right and so on. Algorithm is linear.
Python example:
s = '0010110010'
#s = '110010110010'
k = 2
left = 0
right = 0
res = 0
cnt = 0
while right < len(s):
while (right < len(s)) and (cnt < k):
if s[right] == "1":
cnt += 1
right +=1
while (left <= right) and (cnt >= k):
addend = len(s) + 1 - right
res += addend
print(left, right, addend, res) #intermediate debug output
if s[left] == "1":
cnt -= 1
left +=1
print(res)
0 5 6 6
1 5 6 12
2 5 6 18
3 6 5 23
4 6 5 28
5 9 2 30
30
A useful approach is to ask yourself how many substrings have less than n bits set.
If you can answer this question, then the answer to the original question is right around the corner.
Why is the modified question easier to grasp? Because when you have a substring, say S, with exactly n bits set, then any substring that contains S will have at least n bits set, so you don't need to examine any of those.
So let's say you have a substring. If it has less than n bits set, you can grow it to accommodate more bits. If it has n or more bits set, it cannot grow, you must shrink it.
Suppose you start from the leftmost empty substring, start index 0, end index 0, length 0. (Of course it's a half-open interval). It has no bits set, so you can grow it. The only direction it can grow is to the right, by increasing its end index. It grows and grows and grows until it eats n 1-bits; now it must shrink. How should it shrink? Obviously shrinking it in the opposite direction (decreasing its end index) would accomplish nothing. You would arrive at a substring you have just examined! So you should shrink it from the left, by increasing its start index. So it shrinks and shrinks and shrinks until it excretes a 1-bit from its rear end. Now it has n-1 1-bits, and it can grow again.
It is not difficult to show that you would enumerate all strings with less than n bits set this way.
let N = count of '1'
And let M = count of '0'
int sum = 0 ;
for( int i = n ; i <= N; i++ ) sum += C(N,i) ;
sum *= 1<<M ;
sum is your answer.

How to calculate the time complexity for nested for loops in the following example?

So in the following code, I am trying I am passing a (huge)number-string to the function where I have to find the maximum product of consecutive m digits
So, first, I am looping through let's say n-string and then the inner loop looping through m numbers.
So the inner loop is affected by the if-statement which makes a jump of m indexes if the next number is 0.
EDIT : 1
Actual Problem Question:
The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.
731671765313306249192251....(1000digits)
Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?
Example:
m = 12 number = "1234567891120123456704832...(1000 digits)"
So in 1st iteration function will calculate the product of 1st 12 digits(i.e. from index-11 to index-0 - "1234567891120123456704832..."
Now, in 2nd iteration when it checks the value at index-12 which is 0 then index will jump to index-13. This way the loop will skip 11 iterations.
For the 3rd Iteration, the inner loop will execute for 4 iterations until it finds 0 ("0123456704832...".
def LargestProductInSeries_1(number,m):
max = -1
product = 1
index = 0
x = 0
while index < len(number)-(m-1):
for j in range(index+(m-1), index-1, -1):
num = int(number[j])
if(not num):
index = j
break
product = product * int(number[j])
max = product if max < product else max
product = 1
index += 1
return max
So according to me, the Worst Case Time Complexity would be O(n*m)
I think the Best Time would be O(n/m) if only once the inner loop is completely iterated or every mth digit is 0 which will make the outer loop execute but the index will jump to every mth digit.
Is my analysis correct?
What will be the Average Time for this case?
Will it be O(n*(log m)). Can anyone explain how? Or how to find Complexity in such cases?

What is the error in following program in GW BASIC?

I was making a program which could tell if a given number is a prime number or not. No matter whether I enter a prime number or another number, it always shows "it is not a prime number". Is there any fault in it?
10 input "what is the number";a
20 let b=1
30 let b=b+1
40 let k=a/b
50 let p=fix(k)
60 if p=k then goto 100
70 if b<a then goto 30
80 print "it is a prime number"
90 goto 110
100 print "it is not a prime number"
110 end
run
Follow the logic:
You enter a number, a.
The program creates b as 1.
The program immediately adds 1 to b, so that b is now 2.
The program sets k to a/b. This means that k is now half of a.
The program sets p to k without the .5 that may or may not be there.
If p (half of a rounded down) is equal to k (half of a not rounded down), that is, if a is divisible by b, it goes to 100 and says it is not a prime number.
Otherwise, if b (which is 2) is less than a the program goes to line 30 and adds another 1 to b and repeats the process, but now b is 3.
Otherwise, if b (which is 2) is equal to a or greater than it, it prints that this is a prime number.
Let's say that the number you enter is 2. Two is, in fact, a prime number. Follow the logic above, however, and you will see that the program will tell us that it is not a prime number, because at step 6, two divided by two is one, and one truncated is still one. The same should be true for any number except 1, because all numbers are divisible by themselves.
My guess is that in your testing, you never tested 1; the program should say that 1 is a prime number (this is because even though 1 is divisible by itself, you start at b=2).
(Note also that this is also technically wrong: one is not a prime number.)
This code describes determining a prime number in basic:
10 INPUT p
20 FOR l = 2 TO INT(SQR(p))
30 LET a = p / l
40 LET b = FIX(a)
50 IF a = b THEN GOTO 80
60 NEXT l
70 PRINT "prime"
80 END

Dynamic Programming : Why the 1?

The following pseudocode finds the smallest number of coins needed to sum upto S using DP. Vj is the value of coin and min represents m as described in the following line.
For each coin j, Vj≤i, look at the minimum number of coins found for the i-Vjsum (we have already found it previously). Let this number be m. If m+1 is less than the minimum number of coins already found for current sum i, then we write the new result for it.
1 Set Min[i] equal to Infinity for all of i
2 Min[0]=0
3
4 For i = 1 to S
5 For j = 0 to N - 1
6 If (Vj<=i AND Min[i-Vj]+1<Min[i])
7 Then Min[i]=Min[i-Vj]+1
8
9 Output Min[S]
Can someone explain the significance of the "+1 " in line 6? Thanks
The +1 is because you need one extra coin. So for example, if you have:
Vj = 5
Min[17] = 4
And you want to know the number of coins it will take to get 22, then the answer isn't 4, but 5. It takes 4 coins to get to 17 (according to the previously calculated result Min[17]=4), and an additional one coin (of value Vj = 5) to get to 22.
EDIT
As requested, an overview explanation of the algorithm.
To start, imagine that somebody told you you had access to coins of value 5, 7 and 17, and needed to find the size of the smallest combination of coins which added to 1000. You could probably work out an approach to doing this, but it's certainly not trivial.
So now let's say in addition to the above, you're also given a list of all the values below 1000, and the smallest number of coins it takes to get those values. What would your approach be now?
Well, you only have coins of value 5, 7, and 23. So go back one step- the only options you have are a combination which adds to 995 + an extra 5-value coin, a combination which adds to 993 + an extra 7-value, or a combination up to 977 + an extra 23-value.
So let's say the list has this:
...
977: 53 coins
...
993: 50 coins
...
995: 54 coins
(Those examples were off the top of my head, I'm sure they're not right, and probably don't make sense, but assume they're correct for now).
So from there, you can see pretty easily that the lowest number of coins it will take to get 1000 is 51 coins, which you do by taking the same combination as the one in the list which got 993, then adding a single extra 7-coin.
This is, more or less, what your algorithm does- except instead of aiming just to calculate the number for 1000, it's aim would be to calculate every number up to 1000. And instead of being passed the list for lower numbers in from somewhere external, it would keep track of the values it had already calculated.

Resources