find kth good number - algorithm

Recently, In a competitive coding exam I got this question -
A good number is number whose sum of digits is divisible by 5. example - 5 (5), 14 (1+4), 19(1+9), 23(2+3)
Question is - you are provided a integer n and another integer k you have to find kth good number greater the n.
Constraints - 1<k<10^9
Sample test 1 -
input: n = 6, k = 5
output: 32
Explanation: After 6 good numbers are - 14, 19, 23, 28, 32 (5th is 32)
Sample test 2 -
input: n = 5, k = 1
output: 14
Explanation: 5 is 1st good number but we need greater than 5 so ans is 14
I have tried it with native approach i.e for each number greater then n checking if it is good and loop until I found k good numbers, here is my code -
def solve(n,k):
n+=1
count = 0
while count<k:
if sum(map(int,str(n)))%5==0:
count+=1
n+=1
return n-1
but above code was gave me TLE, how to do it in better time complexity, I have searched on internet for similar question but unable to find, help.

Let's start with a simple question:
I give you a list of five consecutive numbers. How many of those numbers are divisible by 5? (I'm not talking abouts sums of digits yet. Just the numbers, like 18, 19, 20, 21, 22.
No problem there, right? So a slightly different question:
In a list of ten consecutive numbers, how many are divisible by 5?
Still pretty easy, no? Now let's look at your "good" numbers. We'll start by introducing the function digit_sum(n), which is the sum of the digits in n. For now, we don't need to write that function; we just need to know it exists. And here's another simple question:
If n is a number which does not end in the digit 9 and s is digit_sum(n), what is digit_sum(n+1)? (Try a few numbers if that's not immediately clear.) (Bonus question: why does it matter whether the last digit is 9? Or to put it another way, why doesn't it matter which digit other than 9 is at the end? What's special about 9?)
Ok, almost there. Let's put these two ideas together:
Suppose n ends with 0. How many of the ten numbers digit_sum(n), digit_sum(n+1), digit_sum(n+2), … digit_sum(n+9) are divisible by 5? (See question 2).
Does that help you find a quick way to compute the kth good number after n? Hopefully, the answer is yes. Now you just need to generalise a little bit.

maybe your digits algorithm is too time consuming? try this:
def digits(n):
sum = 0
while n:
n, r = divmod(n, 10)
sum += r
return sum
def solve(n,k):
n+=1
count = 0
while count<k:
if digits(n)%5==0:
count+=1
n+=1
return n-1
still it’s a trivial solution, and always you can run it offline and just submit a lookups table.
And here is a link for this sequence: http://oeis.org/A227793

Here's a digit dynamic-program that can answer how many such numbers we can find from 1 to the parameter, k. The function uses O(num_digits) search space. We could use it to search for the kth good number with binary search.
The idea generally is that the number of good numbers that include digit d in the ith position, and have a prefix mod 5 of mod1 so far, is equal to the count of valid digit-suffixes that have the complementary mod, mod2, so that (mod1 + mod2) mod 5 = 0.
JavaScript code comparing with brute force:
function getDigits(k){
const result = [];
while (k){
result.push(k % 10);
k = ~~(k / 10);
}
return result.reverse();
}
function g(i, mod, isK, ds, memo){
const key = String([i, mod, isK]);
if (memo.hasOwnProperty(key))
return memo[key];
let result = 0;
const max = isK ? ds[i] : 9;
// Single digit
if (i == ds.length-1){
for (let j=0; j<=max; j++)
result += (j % 5 == mod);
return memo[key] = result;
}
// Otherwise
for (let j=0; j<=max; j++){
const m = j % 5;
const t = (5 + mod - m) % 5;
const next = g(i+1, t, isK && j == max, ds, memo);
result += next;
}
return memo[key] = result;
}
function f(k){
if (k < 10)
return (k > 4) & 1;
const ds = getDigits(k);
const memo = {};
let result = -1;
for (let i=0; i<=ds[0]; i++){
const m = i % 5;
const t = (5 - m) % 5;
const next = g(1, t, i==ds[0], ds, memo);
result += next;
}
return result;
}
function bruteForce(k){
let result = 0;
//let ns = [];
for (let i=1; i<=k; i++){
const ds = getDigits(i);
const sum = ds.reduce((a, b) => a + b, 0);
if (!(sum % 5)){
//ns.push(i);
result += 1;
}
}
//console.log(ns);
return result;
}
var k = 3000;
for (let i=1; i<k; i++){
const _bruteForce = bruteForce(i);
const _f = f(i);
if (_bruteForce != _f){
console.log(i);
console.log(_bruteForce);
console.log(_f);
break;
}
}
console.log('Done.');

Related

Max Product of a string that requires K multiplication operators to be inserted

Maximum Product.
The input to the problem is a string Z = z1,z2.....zn where each zi is any number between 1...9 and an integer k where 0 <= k < n.
An example string is Z = 8473817, which is of length n = 7. We want to insert k multiplication operators X into the string so that the mathematical result of the expression
is the largest possible. There are n - 1 possible locations for the operators,
namely, after the ith character where i = 1,....., n - 1.
For example, for input Z = 21322 and k = 2, then one possible way to insert the X operators
is: 2 X 1 X 322 = 644, another possibility is 21 X 3 X 22 = 1386.
Design a dynamic programming to output the maximum product
obtainable from inserting exactly k multiplication operators X into the string.
You can assume that all the multiplication operations in your algorithm take
O(1) time.
I am approaching this using the Matrix Chain Multiplication method where you compute smaller subproblem along the upper diagonal.
This works when K=1 i.e. one multiplication operator is inserted.
In the picture below, I have used 8473817 as an example and shown that 8473 X 817 yields the highest product.
How do I scale this solution for K > 1 and K < N.
Update: adding a pseudo code.
let A(i,j) store the max product for the strings A(i...j) 1 < i < j < n
for i = 1 -> n:
A(i,i) = Z(i)
for s = 1 -> n-1:
for i = 1 -> n-s:
j = i + s
A(i,j) = 0
for l = i -> j-1:
A(i,j) = max (A(i,j), A(i,l) * A(l+1,j)
return A(1,n)
The above code works when k = 1. How do I scale this up when k > 1 and less than n
Update
Based on #trincot solution, I revamped the soln to not use memoization
Sub problem Defn
Let T(i) store the start offset where inserting the X operator in Z yields max value for i : 1 < i < k.
Pseudo code
`
T(0) = 0
for i = 1 -> k:
max = 0
for j = T(i-1) + 1 -> n:
result = Z[1..j] * Z[j+1..n]
if result > max
max = result
T(i) = j
val = 1
for i = 1 -> k:
val = val * Z[T(i-1)+1...T(i)]
val = val * Z[T(k)+1..n]
Your pseudo code is a dynamic programming solution where you use memoization for every possible slice of z (2 dimensions, starting and ending offset). However, you would only need to memoize the best result for any suffix of z, so you would only need one (starting) offset. A second dimension in your memoization would then be used for the value of k (the number of remaining multiplications).
So you would still need a 2-dimensional table for memoization, but one index would be for k and the other for an offset in z.
Here is an implementation in JavaScript:
function solve(z, k) {
// Initialise a kxl array (where l is the length of z), filled with zeroes.
const memo = Array.from({length: k + 1}, () => Array(z.length + 1).fill(0));
function recur(z, k) {
if (k == 0) return z;
let result = memo[k][z.length];
if (result == 0) {
for (let i = 1; i <= z.length - k; i++) {
result = Math.max(result, +z.slice(0, i) * recur(z.slice(i), k - 1));
}
memo[k][z.length] = result;
}
return result;
}
return recur(z, k);
}
// A few example runs:
console.log(solve('8473817', 1)); // 6922441
console.log(solve('21322', 2)); // 1368
console.log(solve('191111', 2)); // 10101
Bottom up
The same can be done in an iterative algorithm -- bottom-up instead of top-down. Here we can save one dimension of the memoization array, as the same array can be re-used for the next value of k as it increases from 0 to its final value:
function solve(z, k) {
const memo = Array(z.length);
// Initialise for k=0:
// the best product in a suffix is the suffix itself
for (let i = 0; i < z.length; i++) {
memo[i] = +z.slice(i);
}
for (let kk = 1; kk <= k; kk++) {
for (let i = 0; i < z.length - kk; i++) {
// find best position for multiplication
let result = 0;
for (let j = i + 1; j < z.length - kk + 1; j++) {
result = Math.max(result, +z.slice(i, j) * memo[j]);
}
memo[i] = result;
}
}
return memo[0];
}
// A few example runs:
console.log(solve('8473817', 1)); // 6922441
console.log(solve('21322', 2)); // 1368
console.log(solve('191111', 2)); // 10101
(Code not supplied because this is homework.)
You have found that you can use the method once and get a solution for k=1.
Can you do it and find the best solution ending at every position in the string?
Now can you use the output of that second generalization and a similar method to get a complete solution for k=2?
Now can you write this a loop to solve for arbitrary k?
If you can do all that, then finishing is easy.
You have n-1 positions and k operators to insert. To me that looks like a binary number with n-1 bits including k 1's and the other positions set to 0.
Systematically generate all permutations of [0..01..1], insert multiplication operators at the 1 positions and calculate the result for each permutation.

Find number of positive integers less than or equal to n that doesn't have consecutive '1's in its binary representation

S is defined to be the set of all positive integers whose binary representation does not have consecutive '1's. Find the lexicographical order, i.e. the number of elements of
S less than or equal to it, of the given number.
e.g.
input: 17
output: 9
Explanation: The 8 numbers in the set smaller than 17 are 1, 2, 4, 5, 8, 9, 10 and 16.
*The input is guaranteed to be in the set S.
My attempt:
If the input is an integer power of 2, then it's just a fibonacci-like dynamic programming problem. However, the idea no longer works if the input is not an integer power of 2. So I am thinking about using inclusion-exclusion but so far I haven't found something that can be run in a reasonable time. Any hints are welcomed.
Zeckendorf's theorem says that:
every positive integer can be represented uniquely as the sum of one or more distinct Fibonacci numbers in such a way that the sum does not include any two consecutive Fibonacci numbers.
This means that as your number 17 is the Zeckendorf representation of 9, there are therefore 8 numbers smaller that are in the set.
Therefore to compute the answer:
Convert number into binary (17d -> 10001b bits set at position 1 and 5)
Add the fibonacci number Fi for each set bit at position i (F5+F1 = 8 + 1 = 9)
Subtract 1 (9 - 1 = 8)
For completeness, here is the digit dynamic program with O(log n) time and O(1) space, including a check against brute force.
JavaScript code:
function bruteForce(n){
let result = 0;
let last;
for (let k=1; k<=n; k++){
let i = k;
let prev;
let valid = 1;
while (i){
bit = i & 1;
if (bit && prev){
valid = 0;
break;
}
prev = bit;
i >>= 1;
}
result += valid;
if (valid)
last = k
}
return last == n ? [last, result] : null;
}
function f(n){
// Counts:
// Bit set and bound
// Bit unset and bound
// Bit set and unbound
// Bit unset and unbound
let dp = [0, 0, 0, 0];
let dp_prev = [0, 1, 0, 1];
let result = 0;
while (n){
const bit = n & 1;
n >>= 1;
// Add only the bound result for
// the most significant bit of n
if (!n){
result += dp_prev[1];
break;
}
if (bit){
dp[0] = dp_prev[1];
dp[1] = dp_prev[2] + dp_prev[3];
} else {
dp[0] = 0;
dp[1] = dp_prev[0] + dp_prev[1];
}
// (Fibonacci)
dp[2] = dp_prev[3];
dp[3] = dp_prev[2] + dp_prev[3];
// Add result for all numbers
// with this bit as most significant
if (n)
result += dp[2];
dp_prev = dp;
dp = [0, 0, 0, 0];
}
return result;
}
for (let n=1; n<2000; n++){
const bf = bruteForce(n);
// n must be a member of S,
// which we check in bruteForce
if (bf){
const _f = f(n);
if (_f != bf[1]){
console.log(`Mismatch: ${ n }, b${ n.toString(2) }, brute force: ${ bf[1] }, f: ${ _f }`);
break;
}
}
}
console.log('Done testing.');

Counting number of possible combination to reach a sum with a die

Assume you need n steps (e.g. 100) to visit back to the start point on Monopoly,
how many combination of rolling a die to reach start point again.
The min throw count is round up (n/6), max is n (throwing 1 for n times).
n might be greater than 10000. But I can't think of any better solution other than brute force.
It depends if the order matters or not.
Let's say it doesn't. That is,
throwing 1, 2, 3 is the same as throwing 3, 2, 1. In this case this Scala snippet should work just fine.
def count(n: Int): Int = {
def count(n: Int, dots: List[Int]): Int = dots match {
case _ if n == 0 => 1
case h :: t if n > 0 => count (n - h, h :: t) + count (n, t)
case _ => 0
}
count(n, List(1, 2, 3, 4, 5, 6))
}
If the order matters than this would be the solution.
import java.math.BigInteger;
import java.util.LinkedList;
public class HexabonacciSolver {
public BigInteger solve(int n) {
LinkedList<BigInteger> lastSix = new LinkedList<>();
lastSix.add(new BigInteger("1"));
lastSix.add(new BigInteger("2"));
lastSix.add(new BigInteger("4"));
lastSix.add(new BigInteger("8"));
lastSix.add(new BigInteger("16"));
lastSix.add(new BigInteger("32"));
if (n < 7)
return lastSix.get(n - 1);
for (int i = 0; i < n - 6; i++){
lastSix.add(lastSix.get(0).add(lastSix.get(1).add(lastSix.get(2).add(lastSix.get(3).add(lastSix.get(4).add(lastSix.get(5)))))));
lastSix.removeFirst();
}
return lastSix.get(5);
}
}
Explanation: How does it work?
Let's say you want to know how many different sequences of dice rolls there are to get into the field 100 in Monopoly. You know that to get there the previous rolls had to be either 6, 5, 4, 3, 2 or 1. If you only had the number of different sequences of rolls needed to arrive to the fields 94, 95, 96, 97, 98, 99 you could just sum them up and get the solution for the field 100. This is exactly what the program does. This is very analogous to how the Fibonacci sequence is build with the difference that the next number in the sequence is calculated by summing up 6 previous numbers (hence the name "Hexabonacci")
The solution is linear O(N) in time and constant O(C) in space as we only need to store 6 last numbers of the Hexabonacci sequence.
Since the result for n=10000 has hundreds of digits the Java solution returns a BigInteger.
Let me know if you'd like to see a solution in Scala/Python/JavaScript.
Simple dynamic programming can solve this problem
#include<bits/stdc++.h>
using namespace std;
int n;
int dp[100010] = {0};
int main() {
cin >> n;
dp[0] = dp[1] = 1;
for(int i=2; i<=n ; i++){
for(int j=1; j<=6; j++)
if(i - j >= 0)
dp[i] += dp[i-j];
}
cout << dp[n] << endl;
return 0;
}
Define dp[x] be the total # of the ordered combination to achieve sum x, using 1 to 6 each step,
then dp[x] = sum (dp[x - i]) where 1 <= i <= 6 and x-i >= 0
The base case is dp[0] = dp[1] = 1
One point to note is that the number is growing fast, you may need to use long long / 64bit integer to store the result
For example, to achieve 4 steps in total,
dp(4) = dp(3) + dp(2) + dp(1) + dp(0)
= 4 + 2 + 1 + 1
= 8
Corresponding to [1,2,1], [2,1,1], [1,1,1,1], [3,1], [2,2], [1,1,2], [1,3], [4]

Calculating a Factorial of a number in best time

I am given N numbers i want to calculate sum of a factorial modulus m
For Example
4 100
12 18 2 11
Ans = (12! + 18! +2!+11!)%100
Since the 1<N<10^5 and Numbers are from 1<Ni<10^17
How to calculate it in efficient time.
Since the recursive approach will fail i.e
int fact(int n){
if(n==1) return 1;
return n*fact(n-1)%m;
}
if you precalculate factorials, using every operation %m, and will use hints from comments about factorials for numbers bigger than m you will get something like this
fact = new int[m];
f = fact[0] = 1;
for(int i = 1; i < m; i++)
{
f = (f * i) % m;
fact[i] = f;
}
sum = 0
for each (n in numbers)
{
if (n < m)
{
sum = (sum + fact[n]) % m
}
}
I'm not sure if it's best but it should work in a reasonable amount of time.
Upd: Code can be optimized using knowledge that if for some number j, (j!)%m ==0 than for every n > j (n!)%m ==0 , so in some cases (usually when m is not a prime number) it's not necessary to precalculate factorials for all numbers less than m
try this:
var numbers = [12,18,2,11]
function fact(n) {
if(n==1) return 1;
return n * fact(n-1);
}
var accumulator = 0
$.each(numbers, function(index, value) {
accumulator += fact(value)
})
var answer = accumulator%100
alert(accumulator)
alert(answer)
you can see it running here:
http://jsfiddle.net/orw4gztf/1/

Finding the multiples in form of 0 and 1

I was trying to solve http://poj.org/problem?id=1426 (2002 dhaka regional) . Though I was not able to come up with the exact algorithm required but as n varied from 1 to 200 I precomputed all the values by generating binary numbers and checking for divisibility. Now I have a constant time algorithm :) but I am sure this is not the correct approach for the problem. I don't want use graph search algos as this problem was under basic math in a site so I think there must be a mathematical solution to this problem which does not give TLE.
It's a simple trick on the remainder.
Having to write every multiple with only 0 and 1, means that you want a multiple that is sum of some powers of 10, that means x=\sum{10^a(i)} for some {a(i)}. To find the proper index we want to keep, you must remember that, being a multiple of a number n means that x mon n = 0.
So, it's all about writing the powers of 10 mod n, and find a subset which sum is 0 mod n.
Let's try with 19:
Num -> Num mod 19
1 -> 1
10 -> 10
10^2 -> 5
10^3 -> 12
10^4 -> 6
10^5 -> 3
now, we can see that 10^1 + 10^4 + 10^5 = 19 that is 0 mod 19, so our solution is 110010 .
To find the reminder mod 19 you don't have to calculate every single power, you just can multiply the previous value mod 19 per 10, and then calculate the module.
For instance, 10^4 mod 10 = 10^3 * 10 mod 19 = 12*10 mod 19 = 6 , that is way easier than calculate 10^4 (maybe it's not for small powers, but imagine having to calculato 100^100 before making it mod 19).
EDIT
The only problem left is find a subset that sums to 0 mod n, assuming such a subset exist.
EDIT
Ok, I have got the idea that works up to n = 200 and solve the problem on linear time. Basically, you exploit the fact that sums mod n sooner or later will overlap. This is true because of hte pigeot principle, BUT in the specific case, having only 100 integers, having it working is just a mere case. Anyway, given the list of reminders calculated as shown before, you start calculatin the partial sums. If you meet a value that you already had, you have the solution (i-1 1's followed by j 0). If you meet a reminder 0, you are as well done.
Here is the C# code I've written to test it:
for (int n = 2; n <= 200; n++)
{
int[] reminder = new int[100];
reminder[0] = 1;
for (int i = 1; i < 100; i++)
{
reminder[i] = (10 * reminder[i - 1]) % n;
}
var lst = reminder.Select((x, y) => new TenPower { Reminder = x, Pow = y })
.ToList();
bool cont = true;
for (int i = 1; (i < 100)&&cont; i++)
{
if (lst[i].Reminder == 0)
{
cont = false;
Console.WriteLine(n +" :: " + Math.Pow(10, lst[i].Pow));
}
else
{
lst[i].Reminder = (lst[i].Reminder + lst[i - 1].Reminder) % n;
if (lst[i].Reminder == 0)
{
cont = false;
Console.WriteLine(n + " :: " + Math.Pow(10, lst[i].Pow));
}
for (int j = i - 1; (j > 0) && cont; j--)
{
if (lst[i].Reminder == lst[j].Reminder)
{
cont = false;
Console.Write(n + " :: ");
for (int k = 0; k < i - j; k++)
{
Console.Write("1");
}
for (int k = i - j-1; k < i; k++)
{
Console.Write("0");
}
Console.WriteLine();
}
}
}
}
}

Resources