Печать чисел вида 2 ^ i * 5 ^ j в порядке возрастания - PullRequest
16 голосов
/ 27 сентября 2011

Как вы печатаете номера формы 2^i * 5^j в порядке возрастания.

For eg:
1, 2, 4, 5, 8, 10, 16, 20

Ответы [ 10 ]

2 голосов
/ 28 сентября 2011

Для решения O (N) вы можете использовать список чисел, найденных до сих пор, и два индекса: один представляет следующее число, которое нужно умножить на 2, а другой - следующее число, которое нужно умножить на 5. Затем вНа каждой итерации у вас есть два возможных значения, из которых можно выбрать меньшее.

В Python:

 numbers = [1]
 next_2 = 0
 next_5 = 0

 for i in xrange(100):
     mult_2 = numbers[next_2]*2
     mult_5 = numbers[next_5]*5

     if mult_2 < mult_5:
        next = mult_2
        next_2 += 1
     else:
        next = mult_5
        next_5 += 1

     # The comparison here is to avoid appending duplicates
     if next > numbers[-1]:
        numbers.append(next)

 print numbers
2 голосов
/ 27 сентября 2011

Это хорошо подходит для функционального стиля программирования. В F #:

let min (a,b)= if(a<b)then a else b;;
type stream (current, next)=
    member this.current = current
    member this.next():stream = next();;
let rec merge(a:stream,b:stream)=
    if(a.current<b.current) then new stream(a.current, fun()->merge(a.next(),b))
    else new stream(b.current, fun()->merge(a,b.next()));;

let rec Squares(start) = new stream(start,fun()->Squares(start*2));;

let rec AllPowers(start) = new stream(start,fun()->merge(Squares(start*2),AllPowers(start*5)));;
let Results = AllPowers(1);;

Хорошо работает с Результатами, будучи типом потока с текущим значением и следующим методом.

Проходя через это:

  1. Я определяю мин для полных.
  2. Я определяю тип потока, чтобы иметь текущее значение, и метод, который возвращает новую строку, по существу, заголовок и хвост потока чисел.
  3. Я определяю функцию слияния, которая берет меньшее из текущих значений двух потоков и затем увеличивает этот поток. Затем он возвращается для обеспечения остальной части потока. По сути, если два потока находятся в порядке, он создаст новый поток в порядке.
  4. Я определяю квадраты как поток, увеличивающийся в степени 2.
  5. AllPowers принимает начальное значение и объединяет поток, полученный из всех квадратов с этим числом степеней 5., с потоком, полученным в результате умножения его на 5, так как это только ваши два варианта. Вы фактически остаетесь с деревом результатов

В результате объединяется все больше и больше потоков, поэтому вы объединяете следующие потоки

1, 2, 4, 8, 16, 32 ...

5, 10, 20, 40, 80, 160 ...

25, 50, 100, 200, 400 ...

.

.

. Объединение всего этого оказывается довольно эффективным с хвостовой рекурсией, оптимизацией компилятора и т. Д.

Они могут быть выведены на консоль следующим образом:

let rec PrintAll(s:stream)=
    if (s.current > 0) then
        do System.Console.WriteLine(s.current)
        PrintAll(s.next());;

PrintAll(Results);

let v = System.Console.ReadLine();

Подобные вещи могут быть выполнены на любом языке, который допускает рекурсию и передачу функций в качестве значений (это немного сложнее, если вы не можете передавать функции в качестве переменных).

2 голосов
/ 27 сентября 2011

На самом деле это очень интересный вопрос, особенно если вы не хотите, чтобы он был сложностью N ^ 2 или NlogN.

Я бы сделал следующее:

  • Определите структуру данных, содержащую 2 значения (i и j) и результат формулы.
  • Определить коллекцию (например, std :: vector), содержащую эти структуры данных
  • Инициализировать коллекцию значением (0,0) (в данном случае результат равен 1)
  • Теперь в цикле сделайте следующее:
    • Просмотрите коллекцию и возьмите экземпляр с наименьшим значением
    • Удалить из коллекции
    • Распечатайте это
    • Создайте 2 новых экземпляра на основе только что обработанного экземпляра.
      • В первом инкременте инкремент i
      • Во втором инкременте увеличение j
    • Добавить оба экземпляра в коллекцию (если их еще нет в коллекции)
  • Цикл, пока вам этого не надоест

Производительность можно легко настроить, выбрав правильную структуру данных и сбор данных. Например. в C ++ вы можете использовать std :: map, где ключ - это результат формулы, а значение - пара (i, j). Взять наименьшее значение - это просто взять первый экземпляр на карте (* map.begin ()).

Я быстро написал следующее приложение, чтобы проиллюстрировать его (оно работает !, но не содержит дальнейших комментариев, извините):

#include <math.h>
#include <map>
#include <iostream>

typedef __int64 Integer;

typedef std::pair<Integer,Integer> MyPair;
typedef std::map<Integer,MyPair> MyMap;

Integer result(const MyPair &myPair)
{
return pow((double)2,(double)myPair.first) * pow((double)5,(double)myPair.second);
}

int main()
{
MyMap myMap;
MyPair firstValue(0,0);

myMap[result(firstValue)] = firstValue;

while (true)
   {
   auto it=myMap.begin();
   if (it->first < 0) break;        // overflow

   MyPair myPair = it->second;
   std::cout << it->first << "= 2^" << myPair.first << "*5^" << myPair.second << std::endl;

   myMap.erase(it);

   MyPair pair1 = myPair;
   ++pair1.first;
   myMap[result(pair1)] = pair1;

   MyPair pair2 = myPair;
   ++pair2.second;
   myMap[result(pair2)] = pair2;
   }
}
1 голос
/ 11 октября 2011

Я представляю эту проблему в виде матрицы M, где M(i,j) = 2^i * 5^j. Это означает, что количество строк и столбцов увеличивается.

Подумайте о том, чтобы провести линию через записи в порядке возрастания, четко начиная с записи (1,1). При посещении записей условия увеличения строки и столбца гарантируют, что форма, сформированная этими ячейками, всегда будет целочисленным разделом (в английской записи). Следите за этим разделом (mu = (m1, m2, m3, ...), где mi - количество меньших записей в строке i - следовательно, m1 >= m2 >= ...). Тогда единственные записи, которые вам нужно сравнить, - это те записи, которые можно добавить в раздел.

Вот грубый пример. Предположим, что вы посетили все x s (mu = (5,3,3,1)), тогда вам нужно только проверить @ s:

x x x x x @
x x x @
x x x 
x @
@

Следовательно, количество проверок - это количество добавляемых ячеек (эквивалентно количеству способов подняться в порядке Брюа , если вы хотите думать в терминах поэт).

Учитывая раздел mu, легко определить, какие состояния могут быть добавлены. Изображение бесконечной строки 0 с после последней положительной записи. Тогда вы можете увеличить mi на 1 тогда и только тогда, когда m(i-1) > mi.

Возвращаясь к примеру, для mu = (5,3,3,1) мы можем увеличить m1 (6,3,3,1) или m2 (5,4,3,1) или m4 (5,3,3,2) или m5 (5,3,3,1,1).

Тогда решение проблемы находит правильную последовательность разбиений (насыщенная цепочка). В псевдокоде:

mu = [1,0,0,...,0];
while (/* some terminate condition or go on forever */) {
    minNext = 0;
    nextCell = [];
    // look through all addable cells
    for (int i=0; i<mu.length; ++i) {
        if (i==0 or mu[i-1]>mu[i]) {
            // check for new minimum value
            if (minNext == 0 or 2^i * 5^(mu[i]+1) < minNext) {
                nextCell = i;
                minNext = 2^i * 5^(mu[i]+1)
            }
        }
    }
    // print next largest entry and update mu
    print(minNext);
    mu[i]++;
}

Я написал это в остановке Maple после 12 итераций:

1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50

и к выводимой последовательности ячеек добавили и получили:

1  2  3  5  7 10
4  6  8  11 
9  12

соответствует этому матричному представлению:

1, 2, 4, 8, 16, 32...

5, 10, 20, 40, 80, 160...

25, 50, 100, 200, 400...
1 голос
/ 27 сентября 2011

Итак, у нас есть два цикла, один с шагом i, а второй с шагом j, начиная с нуля, верно?(символ умножения сбивает с толку в заголовке вопроса)

Вы можете сделать что-то очень простое:

  1. Добавить все элементы в массив
  2. Сортировать массив

Или вам нужно другое решение с большим количеством математических анализов?

РЕДАКТИРОВАТЬ: Более разумное решение за счет использования сходства с Слияние с сортировкой задача

Если мы представим бесконечный набор чисел 2^i и 5^j как два независимых потока / списка, эта проблема будет очень похожа на хорошо известную проблему Сортировка слиянием .

Итак, шаги решения:

  • Получить два числа по одному из каждого из потоков (из 2 и из 5)
  • Сравнить
  • Вернуть наименьшее
  • получить следующий номер из потока ранее возвращенного наименьшего

и все!;)

PS: сложность сортировки слиянием always равна O(n*log(n))

0 голосов
/ 30 июля 2015

Вопрос, который мне задавали, заключался в том, чтобы вернуть бесконечный набор решений. Я размышлял об использовании деревьев, но чувствовал, что есть проблема с выяснением, когда собирать и обрезать дерево, учитывая бесконечное число значений для i & j. Я понял, что алгоритм сита может быть использован. Начиная с нуля, определите, имеет ли каждое положительное целое число значения для i и j. Этому способствовало обращение ответа = (2 ^ i) * (2 ^ j) и решение вместо него i. Это дало мне i = log2 (answer / (5 ^ j)). Вот код:

class Program
{
static void Main(string[] args)
{
    var startTime = DateTime.Now;

    int potential = 0;

    do
    {
        if (ExistsIandJ(potential))
            Console.WriteLine("{0}", potential);
            potential++;
    } while (potential < 100000);

    Console.WriteLine("Took {0} seconds", DateTime.Now.Subtract(startTime).TotalSeconds);

}

private static bool ExistsIandJ(int potential)
{
    // potential = (2^i)*(5^j)
    // 1 = (2^i)*(5^j)/potential
    // 1/(2^1) = (5^j)/potential or (2^i) = potential / (5^j)
    // i = log2 (potential / (5^j))

    for (var j = 0; Math.Pow(5,j) <= potential; j++)
    {
        var i = Math.Log(potential / Math.Pow(5, j), 2);
        if (i == Math.Truncate(i))
            return true;
    }
    return false;
}
}
0 голосов
/ 20 марта 2013

Я уверен, что каждый, возможно, уже получил ответ, но просто хотел дать направление этому решению.

Это Ctrl C + Ctrl V от http://www.careercup.com/question?id=16378662

 void print(int N)
  {
     int arr[N];
     arr[0] = 1;
     int i = 0, j = 0, k = 1;
     int numJ, numI;
     int num;
       for(int count = 1; count < N; )
        {
          numI = arr[i] * 2;
          numJ = arr[j] * 5;

            if(numI < numJ)
             {
               num = numI;
               i++;
             }

           else
            {
              num = numJ;
              j++;
            }

            if(num > arr[k-1])
            {
             arr[k] = num;
             k++;
             count++;
            }

       }

     for(int counter = 0; counter < N; counter++)
     {
      printf("%d ", arr[counter]);
     }
}
0 голосов
/ 28 сентября 2011

Как математик, первое, о чем я всегда думаю, когда смотрю на что-то вроде этого, «поможет ли логарифм?».

В этом случае это может быть.

Если наша серия Азатем увеличивается число log (A) также увеличивается.Поскольку все члены A имеют вид 2 ^ i.5 ^ j, то все члены ряда log (A) имеют вид i.log (2) + j.log (5)

Мызатем можно посмотреть на серию log (A) / log (2), которая также увеличивается, и ее элементы имеют вид i + j. (log (5) / log (2))

Если мы работаемi и j, которые генерируют полный упорядоченный список для этой последней серии (назовите его B), затем i и j также будут правильно генерировать серию A.

Это просто меняет природу проблемы, но, надеюсь,к тому, где становится легче решить.На каждом шаге вы можете увеличивать i и уменьшать j или наоборот.

Глядя на некоторые из ранних изменений, которые вы можете внести (которые я, возможно, буду называть преобразованиями i, j или просто преобразованиями), вы получитенам некоторые подсказки о том, куда мы идем.

Явное увеличение i на 1 увеличит B на 1. Однако, учитывая, что log (5) / log (2) составляет примерно 2,3, затем увеличиваем j на 1, уменьшая iна 2 дается увеличение всего на 0,3.Тогда проблема заключается в том, чтобы на каждом этапе найти минимально возможное увеличение B для изменений i и j.

Для этого я просто вел учет по мере увеличения наиболее эффективных преобразований i и j (т.е. чтоскладывать и вычитать из каждого), чтобы получить наименьшее возможное увеличение в серии.Затем применили, какой бы из них ни был действителен (т.е. убедившись, что i и j не становятся отрицательными).

Поскольку на каждом этапе вы можете либо уменьшить i, либо уменьшить j, фактически существуют два класса преобразований, которые можно проверить по отдельности,Новое преобразование не обязательно должно иметь лучший общий балл, чтобы быть включенным в наши будущие проверки, просто лучше, чем любой другой в своем классе.

Чтобы проверить свои мысли, я написал своего рода программу в LinqPad.Ключевыми моментами, которые следует отметить, является то, что метод Dump () просто выводит объект на экран и что синтаксис / структура недопустимы для реального файла c #.Преобразовать его, если вы хотите запустить, должно быть легко.

Надеемся, что все, что не объяснено явно, будет понятно из кода.

void Main()
{
    double C = Math.Log(5)/Math.Log(2);
    int i = 0;
    int j = 0;
    int maxi = i;
    int maxj = j;

    List<int> outputList = new List<int>();
    List<Transform> transforms = new List<Transform>();
    outputList.Add(1);
    while (outputList.Count<500)
    {
    Transform tr;
        if (i==maxi)
        {
            //We haven't considered i this big before. Lets see if we can find an efficient transform by getting this many i and taking away some j.
            maxi++;
            tr = new Transform(maxi, (int)(-(maxi-maxi%C)/C), maxi%C);
            AddIfWorthwhile(transforms, tr);
        }
        if (j==maxj)
        {
            //We haven't considered j this big before. Lets see if we can find an efficient transform by getting this many j and taking away some i.
            maxj++;
            tr = new Transform((int)(-(maxj*C)), maxj, (maxj*C)%1);
            AddIfWorthwhile(transforms, tr);
        }
        //We have a set of transforms. We first find ones that are valid then order them by score and take the first (smallest) one.
        Transform bestTransform = transforms.Where(x=>x.I>=-i && x.J >=-j).OrderBy(x=>x.Score).First();
        //Apply transform
        i+=bestTransform.I;
        j+=bestTransform.J;
        //output the next number in out list.
        int value = GetValue(i,j);
        //This line just gets it to stop when it overflows. I would have expected an exception but maybe LinqPad does magic with them?
        if (value<0) break;
        outputList.Add(value);
    }
    outputList.Dump();

}

public int GetValue(int i, int j)
{
    return (int)(Math.Pow(2,i)*Math.Pow(5,j));
}

public void AddIfWorthwhile(List<Transform> list, Transform tr)
{
    if (list.Where(x=>(x.Score<tr.Score && x.IncreaseI == tr.IncreaseI)).Count()==0)
    {
        list.Add(tr);
    }
}

// Define other methods and classes here
    public class Transform
    {
        public int I;
        public int J;
        public double Score;
        public bool IncreaseI
        {
            get {return I>0;}
        }

        public Transform(int i, int j, double score)
        {
            I=i;
            J=j;
            Score=score;
        }
    }

Я не потрудился посмотреть на эффективностьэто, но я сильно подозреваю, что это лучше, чем некоторые другие решения, потому что на каждом этапе все, что мне нужно сделать, это проверить мой набор преобразований - определить, сколько из них сравнивается с «n», нетривиально.Это явно связано с тем, что чем дальше, тем больше преобразований, но число новых преобразований становится все меньше и меньше при больших числах, так что, возможно, это просто O (1).Эти вещи всегда меня смущали.; -)

Одним из преимуществ перед другими решениями является то, что оно позволяет вычислять i, j без необходимости вычисления продукта, что позволяет мне определить, какой будет последовательность, без необходимости расчета самого фактического числа.

Для чего это стоит после первых 230 nunmbers (когда int исчерпывает пространство) у меня было 9 преобразований для проверки каждый раз.И, учитывая только переполнение моего общего количества, я бежал, если для первого миллиона результатов, и получил i = 5191 и j = 354.Количество преобразований было 23. Размер этого числа в списке составляет примерно 10 ^ 1810.Время выполнения для достижения этого уровня составляло приблизительно 5 секунд.

PS Если вам нравится этот ответ, пожалуйста, не стесняйтесь рассказать своим друзьям, так как я потратил целую вечность на это, и несколько +1 были бы хорошей компенсацией.Или на самом деле просто прокомментируйте, чтобы сказать мне, что вы думаете.:)

0 голосов
/ 28 сентября 2011

Если вы можете сделать это в O (nlogn), вот простое решение:

Get an empty min-heap
Put 1 in the heap
while (you want to continue)
    Get num from heap
    print num
    put num*2 and num*5 in the heap

Вот оно у вас.Под min-heap я имею в виду min-heap

0 голосов
/ 27 сентября 2011

Прежде всего, (как уже упоминалось) этот вопрос очень расплывчатый !!!

Тем не менее, я собираюсь сделать снимок на основе вашего расплывчатого уравнения и схемы в качестве ожидаемого результата. Поэтому я не уверен, что то, что вы пытаетесь сделать, будет справедливо, однако это может дать вам некоторое представление о коллекциях java!

import java.util.List;
import java.util.ArrayList;
import java.util.SortedSet;
import java.util.TreeSet;


public class IncreasingNumbers {

    private static List<Integer> findIncreasingNumbers(int maxIteration) {
        SortedSet<Integer> numbers = new TreeSet<Integer>();
        SortedSet<Integer> numbers2 = new TreeSet<Integer>();

        for (int i=0;i < maxIteration;i++) {
            int n1 = (int)Math.pow(2, i);
            numbers.add(n1);

            for (int j=0;j < maxIteration;j++) {
                int n2 = (int)Math.pow(5, i);
                numbers.add(n2);

                for (Integer n: numbers) {
                    int n3 = n*n1;
                    numbers2.add(n3);
                }
            }
        }

        numbers.addAll(numbers2);

        return new ArrayList<Integer>(numbers);
    }

    /**
     * Based on the following fuzzy question @ StackOverflow
     * /7184894/pechat-chisel-vida-2-i-5-j-v-poryadke-vozrastaniya
     * 
     * 
     * Result:
     * 1 2 4 5 8 10 16 20 25 32 40 64 80 100 125 128 200 256 400 625 1000 2000 10000 
     */
    public static void main(String[] args) {
        List<Integer> numbers = findIncreasingNumbers(5);

        for (Integer i: numbers) {
            System.out.print(i + " ");
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...