Question

This is a problem statement.

Consider a number 2345. If you multiply its digits then you get the number 120. Now if you again multiply digits of 120 then you will get number 0 which is a one digit number. If I add digits of 2345 then I will get 14. If I add digits of 14 then I will get 5 which is a one digit number.

Thus any number can be converted into two one digit numbers in some number of steps. You can see 2345 is converted to 0 by using multiplication of digits in 2 steps and it is converted to 5 by using addition of digits in 2 steps. Now consider any number N. Let us say that it can be converted by multiplying digits to a one digit number d1 in n1 steps and by adding digits to one digit number d2 in n2 steps.

Your task is to find smallest number greater than N and less than 1000000000 which can be converted by multiplying its digits to d1 in less than or equal to n1 steps and by adding its digits to d2 in less than or equal to n2 steps.

How to solve it in C#...

Was it helpful?

Solution

I think you're simply approaching / interpreting the problem incorrectly; here's a stab in the dark:

using System;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        // check our math first!

        // You can see 2345 is converted to 0 by using multiplication of digits in 2 steps
        int value, steps;
        value = MultiplyToOneDigit(2345, out steps);
        Debug.Assert(value == 0);
        Debug.Assert(steps == 2);

        // and it is converted to 5 by using addition of digits in 2 steps
        value = SumToOneDigit(2345, out steps);
        Debug.Assert(value == 5);
        Debug.Assert(steps == 2);

        // this bit is any random number
        var rand = new Random();
        for (int i = 0; i < 10; i++)
        {
            int N = rand.Next(0, MAX);
            int result = Execute(N);
            Console.WriteLine("For N={0}, our answer is {1}", N, result);
        }
    }
    const int MAX = 1000000000;
    //Now consider any number N.
    static int Execute(int N)
    {
        // Let us say that it can be converted by multiplying digits to a one digit number d1 in n1
        // steps and by adding digits to one digit number d2 in n2 steps.
        int n1, n2;
        int d1 = MultiplyToOneDigit(N, out n1),
            d2 = SumToOneDigit(N, out n2);

        // Your task is to find smallest number greater than N and less than 1000000000 
        for (int i = N + 1; i < MAX; i++)
        {
            int value, steps;

            // which can be converted by multiplying its digits to d1 in less than or equal to n1 steps
            value = MultiplyToOneDigit(i, out steps);
            if (value != d1 || steps > n1) continue; // no good

            // and by adding its digits to d2 in less than or equal to n2 steps.
            value = SumToOneDigit(i, out steps);
            if(value != d2 || steps > n2) continue; // no good

            return i;
        }
        return -1; // no answer
    }
    static int MultiplyToOneDigit(int value, out int steps)
    {
        steps = 0;
        while (value > 10)
        {
            value = MultiplyDigits(value);
            steps++;
        }
        return value;
    }
    static int SumToOneDigit(int value, out int steps)
    {
        steps = 0;
        while (value > 10)
        {
            value = SumDigits(value);
            steps++;
        }
        return value;
    }
    static int MultiplyDigits(int value)
    {
        int acc = 1;
        while (value > 0)
        {
            acc *= value % 10;
            value /= 10;
        }
        return acc;
    }
    static int SumDigits(int value)
    {
        int total = 0;
        while (value > 0)
        {
            total += value % 10;
            value /= 10;
        }
        return total;
    }
}

OTHER TIPS

There are two memory problems I can see; the first is the generation of lots of strings - you might want to approach that something like:

static int SumDigits(int value)
{
    int total = 0;
    while (value > 0)
    {
        total += value % 10;
        value /= 10;
    }
    return total;
}

(which is completely untested)

The second problem is the huge list; you don't need to store (in lstString) every value just to find a minimum. Just keep track of the best you've done so far. Or if you need the data for every value, then: don't store them as a string. Indeed, the i can be implied anyway (from the position in the list/array), so all you would really need would be an int[] of the cnt values for every value. And int[1000000000] is 4GB just by itself, so would require the large-array support in recent .NET versions (<gcAllowVeryLargeObjects>). But much better would be: just don't store it.

But it's throwing System.OutOfMemoryException .

That simply mean you're running out of memory. Your limit is 1,000,000,000 or roughly 1G. Times 4 bytes for a string reference that's already too large for a 32 bit system. Even without the actual strings.

You can store your answers more compactly in an int[] array but that would still show the same problem.

So, lower your limit or compile and run on a 64 bit PC.

A for effort :)

Now doing together. You can of course do refactoring.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _17082903_smallest_greatest_number
{
    class Program
    {
        static void Main(string[] args)
        {
            int N = 2344;
            int n1 = 0;
            int n2 = 0;

            int d1 = SumDigits(N, ref n1);
            int d2 = ProductDigits(N, ref n2);

            bool sumFound = false, productFound = false;

            for (int i = N + 1; i < 1000000000; i++)
            {
                if (!sumFound)
                {
                    int stepsForSum = 0;
                    var res = SumDigits(i, ref stepsForSum);

                    if (res == d1 && stepsForSum <= n1)
                    {
                        Console.WriteLine("the smallest number for sum is: " + i);
                        Console.WriteLine(string.Format("sum result is {0} in {1} steps only", res, stepsForSum));
                        sumFound = true;
                    }
                    stepsForSum = 0;
                }

                if (!productFound)
                {
                    int stepsForProduct = 0;
                    var res2 = ProductDigits(i, ref stepsForProduct);

                    if (res2 == d2 && stepsForProduct <= n2)
                    {
                        Console.WriteLine("the smallest number for product is: " + i);
                        Console.WriteLine(string.Format("product result is {0} in {1} steps only", res2, stepsForProduct));
                        productFound = true;
                    }
                    stepsForProduct = 0;
                }

                if (productFound && sumFound)
                {
                    break;
                }
            }

        }

        static int SumDigits(int value, ref int numOfSteps)
        {
            int total = 0;
            while (value > 0)
            {
                total += value % 10;
                value /= 10;
            }

            numOfSteps++;

            if (total < 10)
            {
                return total;
            }
            else
            {
                return SumDigits(total, ref numOfSteps);
            }
        }

        static int ProductDigits(int value, ref int numOfSteps)
        {
            int total = 1;
            while (value > 0)
            {
                total *= value % 10;
                value /= 10;
            }
            numOfSteps++;
            if (total < 10)
            {
                return total;
            }
            else
            {
                return ProductDigits(total, ref numOfSteps);
            }
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top