Given 2 integers l and r, calculate how many numbers in [l, r] that meet these constraints
1) The number should be divisible by 7
2) The number contains at least three digit 7
3) The number contains more digit 7 than digit 4
777, 774746 meet those constraints, 7771, 77, 747474 are not.
Using brute force can easily find the answer but when the range is very large then it might take a lot of time.
I think dynamic programming can help to solve this problem, but i can't think of the solution
Can someone give me some guide?
Taking from the original brute-force version:
Iterate with i over numbers between [l,r]
Use modulo to check if i is divisible by 7
Use modulo and division to get counts of digits in i
digit_count(7) >= 3
digit_count(7) > digit_count(4)
here's some ideas I came up with...
1. Use only multiples of 7, implicitly fulfilling the first criterion:
This one is really simple. We can improve this to only use i that is divisible by 7. If I give you a number x and ask you to generate me numbers divisible by n until you reach y, then you'd best do:
for (auto i = x + x % n; i < y; i += n)
So for the case of multiples of 7 between l and r, all you need to do is run the loop for (auto i = l + l % 7; i < r; i += 7) This will give you 7x speed-up from the brute-force version.
2. Remember the digit counts
There's no need to execute numerous divisions and modulos to get you the count of digits of each number you go through. Since you know by how much you increment, you also know what digits change to what. This way, you'd only need to split into digits the starting number (e.g. l % 7 + l).
Now what we'd be storing isn't the count of digits but actually something very much resembling BCDs - an array of digits that represent the number we are currently working with. You'd then get something like std::vector<int> expressing the array of [7, 7, 2, 4, 5, 7] for number 772457. Now all you need to do is to use the BCD arithmetic inside the array every time you increment the loop counter, going [7, 7, 2, 4, 5, 7] + 6 = [7, 7, 2, 4, 6, 3].
The other thing we'd need to store are two ints - sevens and fours. In the intitialization phase, once you "disintegrate" the first number into the array, you'd just go through it and increment sevens for each 7, fours for each 4. And you'd just keep this numbers up to date: with each update of the array, you'd decrement fours for each 4 you took away and increment it for each 4 you created in the array. And the same for number 7. You can then compare sevens >= 3 && sevens > fours and know the result fast.
Funny thing is, that this gives you no theoretical improvement in the complexity and it might not work, but I suspect it should... It's quite a lot of code so I'm not going to provide it. You might end up working with the BCD array inverted or starting with the r end of iteration range so you don't need to resize the array. And maybe you can come up with many more improvements and tweaks. However, I have strong doubt that the solution can be made asymptotically less complex this way.
3. More thoughts
Now this wasn't dynamic programming at all. Or was it? If you think about it, I have a gut feeling that this idea of an array of numbers as BCD can now be converted to a problem where you look for permutations containing a given combination. You can make a graph out of it and search it. And that's where you'd go dynamic. I'm afraid, however, that this would make for quite a longer post...
But I already got the first doubt about that and that's the check for divisibility by 7 which would then be applied to all the numbers that are found in the graph (the graph would only support criterions 2 and 3 by its nature and yield all numbers containing the combinations). So in the end, it boils down to sizes of ranges that should be supported by the alrgorithm and the ratio of numbers fulfilling the first criterion and the numbers fulfilling the second and third ones in those ranges.
EDIT:
I have since found that my idea of computing the count of numbers fitting the criteria is incorrect. Some small comparisons table:
| range | numbers f/ c2 | c2_groups | c2_total | c1_total |
| 0 - 1k | 777 | 1 | 1 | ~143 |
| 1k - 10k | _777, 7_77, 77_7, 777_ | 4 | 40 | ~1286 |
| 10k - 100k | __777, _7_77, ... | 10 | 1000 | ~12857 |
Where numbers f/ c2 are numbers fulfilling criterion 2, c2_groups is count of possible combinations of any digit and 7s in the number, cx_total is total count of numbers fulfilling criterion x in the range.
Having that, it looks like it's quite questionable whether it would be efficient to filter by the number of digits criteria first. I suppose that would require some mathematical analysis that would take longer than implement the solution...
Space search
With having state equivalent to method #2, it is possible to do DFS in the numbers range. Instead of incrementing by 7, it would store a digits vector and increment values in it based on an offset that would be movable, e.g.
increment [1, 0, 7, _] -> [1, 0, 8, _]
^ ^
This is what the algorithm will be doing in the core loop. You can then check whether the current digits vector setup can fulfill the criteria - e.g. [0, p, _, _] can fulfill them, while [0, 0, p, _] cannot (p is the element that is being pointed to). This way, you will keep incrementing the highest possible digit, skipping a lot of numbers. Every time there is a possibility to fulfill the requirements, you will increment the offset and repeat the process:
push [7, 7, _, _] -> [7, 7, 0, _]
^ ^
Once you're at the least significant digit position, you'll also start checking the divisibility by 7 of each candidate. You can try either converting the digits to int and using modulo or using some sort of divisibility algorithm (these use digits so that's a pleasant coincidence).
This way, you'll get a number that passes all criteria and return it. Now you might come to a situation where you exhaust all the digits in given digit range. In that case, you need to move the offset one place back:
pop [7, 7, 7, 9] -> [7, 7, 7, _]
^ ^
Now, you'd use increment, see that [7, 7, 8, _] can fulfill the criteria and push again. Then run through 0, 1, 2, ... sequence until you come to 7, see that 7787 is ok with both 2nd and 3rd criteria but fails division by 7. And so on...
You'll also need to check whether you're not already over the r limit. I guess that can be done in quite a sane manner by splitting r to digits as well and comparing it from the most significant digit.
Given that we have no math analysis for this, and that this is still going through quite a lot of numbers (especially in case that 7 is the least significant digit), I wonder whether this is really worth implementing. But it's not something super-complex either. Good luck!
For 1: if(yourint % 7 == 0)
For 2: check this link split int into digits, check if digit equals 7 and count to 3.
For 3: expend link 2 with an if a digit equals 7 or 4 than counter++
At the end you should check your counters (7 an 4) which one is the highest.
Related
assume array of N (N<=100000) elements a1, a2, .... ,an, and you are given range in it L, R where 1<=L<=R<=N, you are required to get number of values in the given range which are divisible by at least one number from a set S which is given also, this set can be any subset of {1,2,....,10}. a fast way must be used because it may ask you for more than one range and more than one S (many queries Q, Q<=100000), so looping on the values each time will be very slow.
i thought of storing numbers of values divisible by each number in the big set {1,2,....,10} in 10 arrays of N elements each, and do cumulative sum to get the number of values divisible by any specific number in any range in O(1) time, for example if it requires to get number of values divisible by at least one of the following: 2,3,5, then i add the numbers of values divisible by each of them and then remove the intersections, but i didn't properly figure out how to calculate the intersections without 2^10 or 2^9 calculations each time which will be also very slow (and possibly hugely memory consuming) because it may be done 100000 times, any ideas ?
Your idea is correct. You can use inclusion-exclusion principle and prefix sums to find the answer. There is just one more observation you need to make.
If there's a pair of numbers a and b in the set such that a divides b, we can remove b without changing the answer to the query (indeed, if b | x, then a | x). Thus, we always get a set such that no element divides any other one.
The number of such mask is smaller than 2^10. In facts, it's 102. Here's the code that computes it:
def good(mask):
for i in filter(lambda b: mask & (1 << (b - 1)), range(1, 11)):
if (any(i % j == 0 for j in filter(lambda b: mask & (1 << (b - 1)), range(1, i)))):
return False
return True
print(list(filter(good, range(1, 2 ** 10)))))
Thus, we the preprocessing requires approximately 100N operations and numbers to store (it looks reasonably small).
Moreover, there are most 5 elements in any "good" mask (it can be checked using the code above). Thus, we can answer each query using around 2^5 operations.
Let's say you have a group of numbers. You need to eliminate numbers until there is only one left. This is hard to explain, so let me provide you with an example.
The numbers are 3, 6, 9, and 10.
You pair 3 with 9. You eliminate 3. (Note: either one of them could be eliminated). Now there are 6, 9, and 10 left. You pair 6 with 9. You eliminate 9. Now there are 6 and 10 left. You pair 6 with 10 (only option).
The problem is: I want to find the maximum value obtained from this elimination. Each time a number is eliminated, the XOR value of those two numbers is added to the count. In the previous example, the total value would be (3 ^ 6) + (6 ^ 9) + (6 ^ 10) = 10 + 15 + 12 = 37. This happens to be the maximum value that can be obtained from any elimination combination.
How would I solve this problem in Java with 2000 numbers? I know I can find every possible combination using brute force, but the run time of this was more than two seconds, and I prefer my solutions to be under two seconds. The only option left is Dynamic Programming.
Does anyone know how to solve this with Dynamic Programming?
Suppose you have a string S = {2,0,9,0}. The values that meet the conditions are 2009,
2090, 2900, 9002, 9020 and 9200 (all permutations of S = {2,0,9,0}). Among those, only 2090 and 9020 satisfy the second condition (divisible by 11), so the answer for S = {2,0,9,0} is 2.
What if the string S can go up to 100 digits? Brute force would never end.
Thanks in advance.
By brute fore, there are n! strings to consider.
If we notice that all that matters about a digit is whether it is in an odd or even position, that reduces it to n!/(n/2)!2.
Then we remember that there aren't very many possible digits. We can count how many of each numeral there are, then all we have to do is iterate over all possible partitions of each into two bins (odd and even positions). This is costly, but not totally intractable.
If the strings were really big, thousands of digits, then it would be worth considering the fact that 11 of the same digit in either bin is equivalent to nothing, but for only 100 digits it's probably not worth the effort.
Once we verify that a certain partition corresponds to numbers that are divisible by eleven, we can count how many ways to arrange all of the digits in one bin into all the available positions, which is O(1).
I'm stuck at solving Subset_sum_problem.
Given a set of integers(S), need to compute non-empty subsets whose sum is equal to a given target(T).
Example:
Given set, S{4, 8, 10, 16, 20, 22}
Target, T = 52.
Constraints:
The number of elements N of set S is limited to 8. Hence a NP time solution is acceptable as N has a small upperbound.
Time and space complexities are not really a concern.
Output:
Possible subsets with sum exactly equal to T=52 are:
{10, 20, 22}
{4, 10, 16, 22}
The solution given in Wiki and in some other pages tries to check whether there exists such a subset or not (YES/NO).
It doesn't really help to compute all possible subsets as outlined in the above example.
The dynamic programming approach at this link gives single such subset but I need all such subsets.
One obvious approach is to compute all 2^N combinations using brute force but that would be my last resort.
I'm looking for some programmatic example(preferably C++) or algorithm which computes such subsets with illutrations/examples?
When you construct the dynamic-programming table for the subset sum problem you intialize most of it like so (taken from the Wikipedia article referenced in the question):
Q(i,s) := Q(i − 1,s) or (xi == s) or Q(i − 1,s − xi)
This sets the table element to 0 or 1.
This simple formula doesn't let you distinguish between those several cases that can give you 1.
But you can instead set the table element to a value that'd let you distinguish those cases, something like this:
Q(i,s) := {Q(i − 1,s) != 0} * 1 + {xi == s} * 2 + {Q(i − 1,s − xi) != 0} *4
Then you can traverse the table from the last element. At every element the element value will tell you whether you have zero, one or two possible paths from it and their directions. All paths will give you all combinations of numbers summing up to T. And that's at most 2N.
if N <= 8 why don't just go with 2^n solution?? it's only 256 possibilities that will be very fast
Just brute force it. If N is limited to 8, your total number of subsets is 2^8, which is only 256. They give constraints for a reason.
You can express the set inclusion as a binary string where each element is either in the set or out of the set. Then you can just increment your binary string (which can simply be represented as an integer) and then determine which elements are in the set or not using the bitwise & operator. Once you've counted up to 2^N, you know you've gone through all possible subsets.
The best way to do it is using a dynamic programming approach.However, dynamic programming just answers whether a subset sum exits or not as you mentioned in your question.
By dynamic programming, you can output all the solutions by backtracking.However, the overall time complexity to generate all the valid combinations is still 2^n.
So, any better algorithm than 2^n is close to impossible.
UPD:
From #Knoothe Comment:
You can modify horowitz-sahni's algorithm to enumerate all possible subsets.If there are M such sets whose sum equals S, then overall time complexity is in O(N * 2^(N/2) + MN)
I got the following questions in one of the interviews plz help me some ideas to solve it as am completely unaware how to proceed
A non-empty array A of N elements contains octal representation of a non-negative integer K, i.e. each element of A belongs to the interval [0; 7]
Write a function:
int bitcount_in_big_octal(const vector<int> &A);
that returns the number of bits set to 1 in the binary representation of K. The function should return -1 if the number of bits set to 1 exceeds 10,000,000.
Assume that the array can be very large.
Assume that N is an integer within the range [1..100,000].
is there any time restriction?
I have one idea: at first, make the following dictionary, {0->0, 1->1, 2->1, 3-> 2, 4->1, 5->1, 6->2, 7->3}. then, loop the array A to sum the 1s in every elements using the dictionary.
Iterate over your representation
for-each element in that iterate, convert the representation to its number of bits. #meteorgan's answer is a great way to do just that. If you need the representation for something other than bit counts, you'll probably want to convert it to some intermediate form useful for whatever else you'll be using - e.g. to byte[]: each octet in the representation should correspond to a single byte and since all you're doing is counting bits it doesn't matter that Java's byte is signed. then for-each byte in the array, use an existing bit counting lib, cast the byte to an int and use Integer.bitCount(...), or roll your own, etc - to count the bits
add the result to a running total, escape the iteration if you hit your threshold.
That's a Java answer in the details (like the lib I linked), but the algorithm steps are fine for C++, find a replacement library (or use the dictionary answer).
Here's the solution using the indexed (dictionary) based approach.
INDEX = [0, 1, 1, 2, 1, 2, 2, 3]
def bitcount_in_big_octal(A):
counter = 0
for octal in A: counter += INDEX[octal]
return counter