В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.
При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.
Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».
Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this
. Возьмем этот пример:
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
И в другом месте вашего кода:
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference
и otherReference
оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.
@Torlack, @Jason Cohen: Рекурсия является плохой идеей здесь, потому что там "перекрывают подпроблемы". Т.е. Если Вы выбираете a
как 1
и b
как 2
, затем у Вас есть 3 переменные, оставленные, который должен составить в целом 497; Вы прибываете в ту же подпроблему путем выбора a
как 2
и b
как 1
. (Количество таких совпадений взрывается, когда числа растут.)
Традиционным способом приняться за решение такой проблемы является динамическое программирование: создайте таблицу вверх дном решений подпроблем (запускающийся с, "сколько комбинации 1 переменной составляют в целом 0?") затем растущий посредством повторения (решение, "сколько комбинаций n переменных составляет в целом k?" сумма решений к, "сколько комбинаций n-1 переменных составляет в целом j?" с 0 <= j <= k).
public static long getCombos( int n, int sum ) {
// tab[i][j] is how many combinations of (i+1) vars add up to j
long[][] tab = new long[n][sum+1];
// # of combos of 1 var for any sum is 1
for( int j=0; j < tab[0].length; ++j ) {
tab[0][j] = 1;
}
for( int i=1; i < tab.length; ++i ) {
for( int j=0; j < tab[i].length; ++j ) {
// # combos of (i+1) vars adding up to j is the sum of the #
// of combos of i vars adding up to k, for all 0 <= k <= j
// (choosing i vars forces the choice of the (i+1)st).
tab[i][j] = 0;
for( int k=0; k <= j; ++k ) {
tab[i][j] += tab[i-1][k];
}
}
}
return tab[n-1][sum];
}
$ time java Combos 2656615626 real 0m0.151s user 0m0.120s sys 0m0.012s
Ответ на Ваш вопрос равняется 2656615626.
Вот код, который генерирует ответ:
public static long getNumCombinations( int summands, int sum )
{
if ( summands <= 1 )
return 1;
long combos = 0;
for ( int a = 0 ; a <= sum ; a++ )
combos += getNumCombinations( summands-1, sum-a );
return combos;
}
В Вашем случае, summands
5 и sum
500.
Обратите внимание, что этот код является медленным. Если Вы нуждаетесь в скорости, кэшируете результаты summand,sum
пары.
Я предполагаю, что Вы хотите числа >=0
. Если Вы хотите >0
, замените инициализацию цикла a = 1
и условие цикла с a < sum
. Я также предполагаю, что Вы хотите перестановки (например. 1+2+3+4+5
плюс 2+1+3+4+5
и т.д.). Вы могли изменить для цикла, если бы Вы хотели a >= b >= c >= d >= e
.
Я решил эту проблему для своего папы, которого пара несколько месяцев назад... расширяет для Вашего использования. Они имеют тенденцию быть проблемами времени, таким образом, я не пошел для самого допускающего повторное использование...
a+b+c+d = сумма
i = количество комбинаций
for (a=0;a<=sum;a++)
{
for (b = 0; b <= (sum - a); b++)
{
for (c = 0; c <= (sum - a - b); c++)
{
//d = sum - a - b - c;
i++
}
}
}
Это на самом деле было бы хорошим вопросом спросить относительно интервью, поскольку это достаточно просто, который Вы могли описать на белой доске, но достаточно комплекс, что это могло бы сбить кого-то с толку, если они не думают достаточно тщательно об этом. Кроме того, Вы можете также для двух различных ответов, которые заставляют реализацию очень отличаться.
Вопросы порядка
Если порядок имеет значение затем, что любое решение должно позволить, чтобы нуль появился для любой из переменных; таким образом самое прямое решение было бы следующие:
public class Combos {
public static void main() {
long counter = 0;
for (int a = 0; a <= 500; a++) {
for (int b = 0; b <= (500 - a); b++) {
for (int c = 0; c <= (500 - a - b); c++) {
for (int d = 0; d <= (500 - a - b - c); d++) {
counter++;
}
}
}
}
System.out.println(counter);
}
}
Который возвращается 2656615626.
Порядок не имеет значения
Если порядок не имеет значения затем, что решение не состоит в том, что намного тяжелее, поскольку просто необходимо удостовериться, что нуль не возможен, если сумма не была уже найдена.
public class Combos {
public static void main() {
long counter = 0;
for (int a = 1; a <= 500; a++) {
for (int b = (a != 500) ? 1 : 0; b <= (500 - a); b++) {
for (int c = (a + b != 500) ? 1 : 0; c <= (500 - a - b); c++) {
for (int d = (a + b + c != 500) ? 1 : 0; d <= (500 - a - b - c); d++) {
counter++;
}
}
}
}
System.out.println(counter);
}
}
Который возвращается 2573155876.
Один способ посмотреть на проблему следующие:
Во-первых, банка быть любым значением от 0 до 500. Затем, если следует за этим b+c+d+e = 500-a. Это уменьшает проблему одной переменной. Рекурсивно вызовите, пока не сделано.
Например, если 500, то b+c+d+e=0, что означает, что для случая = 500, существует только одна комбинация значений для b, c, d и e.
Если 300, то b+c+d+e=200, который является на самом деле той же проблемой как исходная проблема, просто уменьшенная одной переменной.
Примечание: Как Chris указывает, это - ужасный способ фактической попытки решить проблему.
Если они - вещественные числа, затем бесконечные... иначе это немного более хитро.
(Хорошо, для любого компьютерного представления вещественного числа было бы конечное количество..., но это будет большим!)
Включая отрицательные стороны? Бог.
Только включая положительные стороны? В этом случае их не назвали бы "целыми числами", но "naturals", вместо этого. В этом случае... Я не могу действительно решить это, мне жаль, что я не мог, но моя математика слишком ржава. Существует, вероятно, некоторый сумасшедший интегральный способ решить это. Я могу дать некоторые подсказки для математики, квалифицированной вокруг.
будучи x конечным результатом, диапазоном быть от 0 до x, диапазон b был бы от 0 до (x - a), диапазон c будет от 0 до (x - b), и т.д до e.
Ответ является суммой всех тех возможностей.
Я пытаюсь найти некоторую более прямую формулу на Google, но я являюсь действительно низким на своем Google-Fu сегодня...