2017-01-24 18 views
1

Я пытаюсь разделить список на подсписки, которые как можно больше. Если список не может быть разделен таким образом, я буду обрабатывать его по мере необходимости, но мне нужно получить наибольшее число, кроме самого N, которое равномерно разделяет N.Наибольший делитель N (исключая себя)

Я написал действительно наивное решение, но я чувствую, что должна быть какая-то формула или что-то делать это в постоянное время. Мой список не такой большой, максимальный размер - 1000. Это, вероятно, не критический путь, но есть ли лучший алгоритм?

public static int largestDivisor(int n){ 
    int divisor = 0; 
    for (int i = 1; i <= n/2; i++) 
     if (n % i == 0) 
      divisor = i; 

    return divisor; 
} 
+0

ahhhh, конечно. Что со мной не так? –

+1

Возможный дубликат [Мне нужен оптимальный алгоритм для нахождения наибольшего делителя числа N. Предпочтительно в C++ или C#] (http://stackoverflow.com/questions/3545259/i-need-an-optimal-algorithm-to -find-the-most-divisor-of-a-number-n-preferabl) – Paul

+0

Возможный дубликат [Java: получить наибольший общий делитель] (http: // stackoverflow.com/questions/4009198/java-get-most-common-divisor) – MikaelF

ответ

4

Итерировать значения в обратном порядке. Просто верните первый, который вы найдете (он будет самым большим). Нечто подобное,

public static int largestDivisor(int n) { 
    for (int i = n/2; i >= 2; i--) { 
     if (n % i == 0) { 
      return i; 
     } 
    } 
    return 1; 
} 

В качестве альтернативы, вы можете сделать небольшое улучшение в @WillemVanOnsem «s answer и начать с нечетными значениями как;

public static int largestDivisor(int n) { 
    if (n % 2 == 0) { 
     return n/2; 
    } 
    final int sqrtn = (int) Math.sqrt(n); 
    for (int i = 3; i <= sqrtn; i += 2) { 
     if (n % i == 0) { 
      return n/i; 
     } 
    } 
    return 1; 
} 
+0

Это быстрее, чем оригинал, но не так быстро, как другие методы. –

1

Вы знаете, что если является делимым по б, также разделяемая на а/б и меньше б есть, тем больше а/б, так сразу вы нашли делитель, возвращение n/divisor:

public static int largestDivisor(int n){ 
    for(int i = 2; i <= n/2; i++) 
     if(n % i == 0) { 
      return n/divisor; 
     } 
    } 
    return 0; //or whatever you decide to return if there is no such divisor 
}

Это также быстрее, потому что:

  1. делители, как правило, становятся более редкими, чем больше они получают; и
  2. вы уже можете отказаться от sqrt(n).

Таким образом, наиболее эффективный подход был бы:

public static int largestDivisor(int n){ 
    int sqrtn = (int) Math.sqrt(n); 
    for(int i = 2; i <= sqrtn; i++) 
     if(n % i == 0) { 
      return n/divisor; 
     } 
    } 
    return 0; 
}
1

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

Начните с 2 и пропустите все числа, проверяя, является ли n делением на это число. Когда вы переходите к числу, которое делит n, вы можете остановиться - ваш ответ n/i. Если вы дойдете до конца и все равно не разделите, то n будет простым, а ответ будет равен 1.

Вместо того, чтобы заканчиваться на n/2, если вы не найдете делителя, вы можете закончить с помощью √ n с этим методом, который уменьшит большой O.

Кроме того, вы можете начать с проверки, если он делится на 2, затем перейдите к 3 и проверьте только нечетные числа оттуда. (Если он был делимым на четное число, то он был делимым на 2.) Это не изменит большой O, но он должен сократить время обработки почти в два раза, так как вы проверяете только половину делителей.

+3

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

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

  • Нет связанных вопросов^_^