2015-08-17 3 views
9

Предположим, учитывая некоторые номераНайти количество пар, где первый элемент делится на второй элемент

8, 7, 6, 5, 4, 3, 2 

вы должны найти все пары (a, b) где a появится в списке до того b и a%b = 0.

Здесь, такие пары:

(8, 4), (8, 2), (6, 3), (6, 2), (4, 2) 

Есть ли лучший алгоритм, чем О (п)?

+0

Есть ли какие-либо ограничения? Насколько велико каждый номер? –

+0

каждый элемент находится между 1 и 10^5 –

+0

нет, цифры могут быть в любом случайном порядке –

ответ

0

Используя динамическое программирование, это можно решить со сложностью O (nlogn). Подобно проблеме деноминации монет.

Пожалуйста, обратитесь к следующей ссылке для решения проблемы монеты номинала Coin Denomination problem

+0

Это кажется расплывчатым в лучшем случае. Как вы относитесь к дублирующим значениям? –

1

Вы можете предвычисление списка всех делителей возможных чисел на входе = O (п^1,5)

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

Для каждого числа на входе вам нужно итератора над всеми его делителей, т.е. O (п^1,5)

Таким образом, общая сложность O (п^1,5) где п максимум 100000 и размер вашего ввода.

class Denominators {               

    public static void main (String[] a) {         
     int maxValue = 100000;            
     int[] problemSet = {8, 7, 6, 5, 4, 3, 2};       
     System.out.println (new Denominators().solve(problemSet, maxValue)); 
    }                  


    int solve (int[] problemSet, int maxValue) {        
     List<List<Integer>> divisors = divisors(maxValue);     
     int[] values = new int[maxValue + 1];        
     int result = 0;              
     for (int i : problemSet) {           
      result += values[i];            
      for (int d : divisors.get(i)) {         
       values[d]++;             
      }                
     }                 
     return result;              
    }                  


    private List<List<Integer>> divisors (int until) {      
     List<List<Integer>> result = new ArrayList<>();      
     for (int i = 0; i <= until; i++) {         
      result.add (new ArrayList<Integer>());       
     }                 
     for (int i = 1; i * i <= until; i++) {        
      for (int j = i; j * i <= until ; j++) {       
       result.get (i * j).add(i);         
       if (i != j) result.get (i * j).add(j);      
      }                
     }                 
     return result;              
    }                  

} 
+0

«Для каждого числа на входе вам потребуется итератор по всем его делителям, т. Е. O (n log n)». На самом деле число может иметь гораздо больше, чем O (log n) делителей, поэтому я думаю, что это больше похоже на O (n^(1 + eps)) для некоторого eps <1/2. Однако наибольшее число делителей в диапазоне 1..10^5 равно 29, что довольно мало –

+0

На самом деле это 128, а не 29, поэтому вы должны учитывать это: http://oeis.org/A066150 Очевидно, что n^1/3) является довольно полезным приближением числа делителей n для малых n –

+0

@NiklasB., Где вы обнаружили, что «наибольшее количество делителей в диапазоне 1,10^5 равно 29», (FYI: no of divisors of 720 is 30) – vish4071

Смежные вопросы