Вроде код рабочий, но нет. Бесконечное выполнение

Рейтинг: 1Ответов: 3Опубликовано: 19.02.2023

Написан метод, который принимает число, и возвращает его мультипликативную стойкость.

То есть количество раз, которое вы должны умножить на num, пока не получите одну цифру.

Например:

999 --> 4 (потому-что 9*9*9 = 729, 7*2*9 = 126, 1*2*6 = 12, и 1*2 = 2)

Вот сам код:

public static int persistence(long n) {
        int count = 0;
        String ss = Long.toString(n);
        char[] help = ss.toCharArray();
        while (n / 10 != 0) {
            int qq = 1;
            for (int i = 0; i < help.length; i++) {
                qq = qq * help[i];
            }
            n = qq;
            count++;
        }
        return count;
    }

Ответы

▲ 1Принят

Как правильно заметили в комментариях, массив help не обновляется. Получение его, как и получение строки ss из числа, нужно внести внутрь цикла while.

Однако это не единственная проблема. В строке

qq = qq * help[i];

вы перемножаете не цифры, а их коды, так как help - это массив типа char, а цифра с точки зрения char является обыкновенным символом, имеющим свой код. Для нуля, например, это 48, для девяти - 57. Так что перемножать именно цифры можно если, например, из help[i] вычитать 48. С учётом приведённых выше замечаний получим:

public static int persistence(long n) {
    int count = 0;
    while (n / 10 != 0) {
        String ss = Long.toString(n);
        char[] help = ss.toCharArray();
        int qq = 1;
        for (int i = 0; i < help.length; ++i) {
            qq = qq * (help[i] - 48);
        }
        n = qq;
        count++;
    }
    return count;
}

С использованием Stream API, код можно улучшить следующим образом (как один из вариантов):

public static int improvedPersistence(long n) {
    int count = 0;
    while (n > 10) {
        n = String.valueOf(n)
                    .chars()
                    .mapToLong(symbol -> symbol - 48)
                    .reduce(1, (a, b) -> a * b);
        count++;
     }
     return count;
}
▲ 3

Потому что код сложный: два цикла, числа, строки, коды символов.

Так проще:

если n < 10 то persistance(n) = 0
иначе          persistance(n) = 1 + persistance(digital_product(n))

Для digital_product нужна математика: n % 10 - младшая цифра числа, n / 10 - остальные цифры:

если n < 10 то digital_product(n) = n
иначе          digital_product(n) = digital_product(n / 10) * (n % 10)

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

public static int persistence(long n) {
    if (n < 10) {
        return 0;
    }
    return 1 + persistence(digital_product(n));
}

public static long digital_product(long n) {
    if (n < 10) {
        return n;
    }
    return digital_product(n / 10) * (n % 10);
}
▲ 2

Как было отмечено в комментариях, содержимое строки help не меняется, но также есть проблема в умножении не цифр, а их ASCII-кодов: qq = qq * help[i];, так что перемножаться будут не 1, 2, ... 9, а '1', '2', ... '9'.

Для получения цифрового значения можно использовать метод Character::getNumericValue. Также при обнаружении первого 0 можно прекращать вычисления:

public static int persistence(long n) {
    int count = 0;
    
    String s;
    
    while ((s = Long.toString(n)).length() > 1) {
        int p = 1;
        for (char c : s.toCharArray()) {
            int d = Character.getNumericValue(c);
            p *= d;
            if (d == 0) break;
        }
        n = p;
        count++;
    }
    
    return count;
}

Или же вместо вложенного цикла и работы со строками можно воспользоваться рекурсией:

public static int persistence(long n) {
    if (n < 10) {
        return 0;
    }
    
    int p = 1;
    while (n > 0 && p != 0) {
        p *= n % 10;
        n /= 10;
    }
    
    return 1 + persistence(p);
}