Обратный цифр целого числа


Обратный цифр целого числа.

Пример1:

х = 123,

возвращение 321 Пример 2:

х = -123,

возвращение -321

Возвращает 0, если результат переполняет и не вмещается в 32-битное целое

Это мой подход:

public class Solution {
    public int reverse(int A) {

        String ans = " ";
        String finalAns = " ";
        int range = 2147483647;
        if( (A > 0) && (A <= range))
            {
                ans = String.valueOf(A);
                return (Integer.parseInt(new StringBuilder(ans).reverse().toString()));
            }
        if( (Math.abs(A) > range))
            return 0;

        else if ( (A > - (range + 1)) && (A < 0) )
            {
                ans = String.valueOf(Math.abs(A));

                if( Math.abs(A) > range)
                    return 0;

                finalAns =  (new StringBuilder(ans).reverse().toString());

                double d = Double.parseDouble(finalAns);
                if( d  == (int)d )
                    return Integer.parseInt( "-" + finalAns);
                else
                    return 0;
            }
        else
            return 0;
    }
}

У меня есть следующие вопросы относительно моего кода:

1) Есть ли лучший подход, чтобы решить этот вопрос?

2) есть ли в Java конвенций кодирования, что у меня серьезные нарушения?

3) я делаю лишние шаги?

Ссылка



Комментарии
4 ответа

Если бы я представил это решение как ответ на вопрос во время интервью, я бы наверняка вопрос ваше суждение и вкус, даже если решение работало правильно — ее нет.

Значение range, 2147483647Это магическое число, лучше записать как Integer.MAX_VALUE. Однако, даже если (A > 0) && (A <= range) правда, обратный результат может не поместиться в intв этом случае Integer.parseInt(…) бы бросить NumberFormatException.

Я уже ранее советовал , чтобы избежать использования операций с плавающей запятой при работе с целочисленной арифметикой. Если ваша цель справиться int переполнения, а затем использовать long.

В любом случае, используя StringBuilder.reverse() это, на мой взгляд, плохая идея. Процессоры являются очень эффективными в арифметике, но менее искусны в обработке строк. Оба String.valueOf(<em>int</em>) и Integer.parseInt(<em>String</em>) делать много работы за кулисами. Хотя неэффективность является вполне приемлемой для всех практических целей, я хотел бы рассмотреть решение промазали, если судить как решение интервью.

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

public int reverse(int a) {
long reversed = 0;
while (a != 0) {
reversed = 10 * reversed + (a % 10);
a /= 10;
}
return (reversed == (int)reversed) ? (int)reversed
: 0; // int overflow detected
}

Обратите внимание, что обнаружение переполнения тоже гораздо проще. Нет никаких особых случаев — мы просто проверить, есть ли приведения типов из long для int можно спокойно сделать. Также обратите внимание, что (a % 10) производит отрицательный результат, когда a отрицательно, так что никакой специальной обработки необходим для отрицательных чисел тоже.

5
ответ дан 27 марта 2018 в 10:03 Источник Поделиться

Вот мои замечания, в порядке тяжести:

Ошибки

Вы проверяли ваше решение? потому что он не работает должным образом.
Попробуйте вызвать метод с аргументом 2147483646 (максимальное число - 1)

Производительности

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

Ясность Кода


  1. Вы использовать избыточные скобки в нескольких местах:
    например: if( (Math.abs(A) > range))
    а также, в ряде заданий, как
    finalAns = (new StringBuilder(ans).reverse().toString());
    все эти не влияют на правильность, ни ясность кода.
    что касается использования скобок для операндов && оператор, лично я думаю, что это еще один случай резервирования, но есть и другие, кто утверждает, что это нормально.

  2. В Java константы для определения минимальных/максимальных значений для типов число. Они определяются по количеству классов-оболочек, как Integer.MAX_VALUE

Соглашение Об Именовании


  1. правила именования переменных Java верблюд-дело, значит, они должны начать со строчной буквы (я имею в виду аргумент)

3
ответ дан 25 марта 2018 в 07:03 Источник Поделиться


  • Назначение " " к String переменные ans и finalAns это бессмысленно, потому что присвоенные значения не используются в коде, прежде чем они будут перезаписаны, так что вы могли бы также просто объявлять переменные без присвоения им значений. Вопрос , где объявлять локальные переменные уже обращались в Тимоти раболепства ответ.

  • Не надо присваивать переменной ans отдельно в двух случаях A быть позитивным и A будучи отрицательным. Вы можете просто назначить String.valueOf(Math.abs(A)) ей изначально, который будет охватывать обоих случаях на одном дыхании. Обратите внимание, что это не будет работать для Integer.MIN_VALUEпотому, что добавки реверс Integer.MIN_VALUE не может быть представлен как целое число, но тогда, есть и другие, фундаментальные проблемы с вашим кодом, так что я бы исключительный случай Integer.MIN_VALUE как ничтожна на данном этапе пересмотра кодекса.

  • В этой строке:

    if( (A > 0) && (A <= range))

    Проверить ли A <= range это бессмысленно, потому что A уже определен как intэто означает, что он по определению в рамках целого и, в свою очередь, меньше или равно Integer.MAX_VALUE (это значение range). Это как если ты делаешь что-то вроде этого:

    void ridiculousMethod(String input) { //input is a variable of type String
    if (!(input instanceof String)) { //WTF?
    throw new IllegalArgumentException("WTF?");
    }
    }

    На самом деле, это имеет даже больше смысла, чем то, что вы делаете, потому что в ridiculousMethod(String)исключение может фактически быть брошен, если input это nullно в вашем случае, A примитивный тип, который не может быть null, так что нет никакого способа, что A <= range может вернуться false.


  • Далее эта строка:

    return (Integer.parseInt(new StringBuilder(ans).reverse().toString()));

    Здесь Integer.parseInt(String) будут бросать NumberFormatException если реверс целое число не может быть представлено как целое число. Я уже указал на это в комментарии на ваш вопрос, но я не думаю, что вы поняли, что я имел в виду, что в ваш ответ, вы просто не признаете тот факт, что эта часть кода не работает, так что я проиллюстрирую проблему шаг за шагом:

    Возьмем, например, входной 1000000009. Этот номер может быть представлено как целое число. Наоборот это число 9000000001, которые могут не быть представлены как целое число, так как оно слишком большое. Так что произойдет, если вы проходите 1000000009 в свой способ? Мы входим в первую if блок и ans расположен в строку "1000000009". Далее StringBuilder построен из ans а затем отменил, так это StringBuilder сейчас он представляет собой последовательность символов "9000000001". Это StringBuilder затем преобразуется обратно в String которое передается Integer.parseInt(String)и теперь это игра закончена. Integer.parseInt(String) обнаруживает, что String "9000000001" не содержит число, которое может быть представлено как целое число, так это то, что его документация Штаты это делают в подобных случаях: бросить NumberFormatException. Однако, требование было то, что, если обратный входной не может быть представлен как целое число, программа должна вернуть 0. Следовательно, ваш код сломан.


  • if( (Math.abs(A) > range))

    Этого никогда не будет. Единственный случай, когда фактическое абсолютное значение A будет превышать Integer.MAX_VALUE если A это Integer.MIN_VALUE. Но Math.abs(Integer.MIN_VALUE) значение Integer.MIN_VALUEпоскольку фактическое абсолютное значение Integer.MIN_VALUE может, как я уже указывал ранее, не будет представлена как int.

    На самом деле, бессмысленность эту строку можно объяснить еще проще: Math.abs(int) возвращает int и, как я уже объяснял, что int не может превышать максимальное значение int.


  • else if ( (A > - (range + 1)) && (A < 0) )

    Выражение - (range + 1) не делать то, что тебе кажется, что это делает. Это, как ни странно, оценивают Integer.MIN_VALUE в конце концов, что, вероятно, то, что вы хотите, но это не есть так, как вы ожидали, если вы просто видели это выражение вне контекста программирования и максимальные/минимальные значения переменных. Проблема в том, что range + 1 не дает 2147483648, но -2147483648, что эквивалентно Integer.MIN_VALUEпотому что range это intтак 1 интерпретируется как int тоже и добавив две intы всегда приводят к int (в этом случае, переполнение возникает при сложении, поэтому результат не реальный результат сложения). Обратите внимание, что, если вы должны были написать (long) range + 1 или range + 1Lт. е. если вы сделаете одно из двух слагаемых в long вместо intтогда другое слагаемое также быть неявно преобразован в longи результат будет действительно 2147483648 потому что добавление двух longс приведет к longи с longс переполнение не происходит.

    Так range + 1 значение Integer.MIN_VALUEи, как я уже объяснял ранее, аддитивная инверсия Integer.MIN_VALUE будет также оцениваться Integer.MIN_VALUE когда представлено как int.


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

3
ответ дан 27 марта 2018 в 09:03 Источник Поделиться

Спасибо за ваш код.


1) Есть ли лучший подход, чтобы решить этот вопрос?

Вы могли бы использовать регулярное выражение вроде этого:

public class Solution {
public int reverse(int A) {
Matcher signAndNumber =
Pattern.compile("(-)?(\\d+)")
.matcher(Integer.toString(A));
if(signAndNumber.find()) {
try{
return Integer.parseInt(
signAndNumber.group(1)
+ new StringBuilder(signAndNumber.group(2))
.reverse()
.toString());
} catch (Exception e){
// ignore and fall through
}
}
return 0;
}
}



2) есть ли в Java конвенций кодирования, что у меня серьезные нарушения?

Ваш код выглядит довольно хорошо с этой точки зрения. Я вижу только несколько недостатков:


  1. Размещение фигурных скобок {.
    быть последовательным с этим.

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

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


  2. Объявить как можно позже локальных переменных.

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

    Если вы хотели объявить эти переменные (несколько раз) непосредственно перед первым использованием, это поможет вашему Иды автоматизированного рефакторинга извлекать способ для создания методов из этой части:

    С вашей версии рефакторинг будет иметь параметр ненужные вроде этого:

    private int positiveAnswer(int A, String ans){   
    ans = String.valueOf(A);
    return (Integer.parseInt(new StringBuilder(ans).reverse().toString()));
    }

    public int reverse(int A) {
    String ans = " ";
    String finalAns = " ";
    int range = 2147483647;
    if( (A > 0) && (A <= range))
    {
    return positiveAnswer(A, ans);
    }
    // ...

    Версия с "поздним декларации" вышли бы

    private int positiveAnswer(int A){   
    String ans = String.valueOf(A);
    return (Integer.parseInt(new StringBuilder(ans).reverse().toString()));
    }

    public int reverse(int A) {
    int range = 2147483647;
    if( (A > 0) && (A <= range))
    {
    return positiveAnswer(A);
    }
    // ...


1
ответ дан 25 марта 2018 в 07:03 Источник Поделиться