Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 20.03.12 13:29
Оценка:

Ввести с консоли n целых чисел и поместить их в массив. На консоль вывести:
1. Четные и нечетные числа.
2. Наибольшее и наименьшее число.
3. Числа, которые делятся на 3 или на 9.
4. Числа, которые делятся на 5 и на 7.
5. Элементы, расположенные методом пузырька по убыванию модулей.
6. Все трехзначные числа, в десятичной записи которых нет одинаковых цифр.
7. Наибольший общий делитель и наименьшее общее кратное этих чисел.
8. Простые числа.
9. Отсортированные числа в порядке возрастания и убывания.
10. Числа в порядке убывания частоты встречаемости чисел.
11. “Счастливые” числа.
12. Числа Фибоначчи: f0 = f1 = 1, f (n) = f (n–1) + f (n–2).
13. Числа-палиндромы, значения которых в прямом и обратном порядке совпадают.
14. Элементы, которые равны полусумме соседних эле¬ментов.
15. Период десятичной дроби p = m/n для первых двух целых положительных чисел n и m, расположенных подряд.
16. Построить треугольник Паскаля для первого положительного числа.


Привет, решение данных заданий на Java — ниже. Покритикуйте.


package chapt01.b;

import java.util.*;
import java.util.Map.Entry;

import static java.util.Collections.*;

/**
 * @author m1st
 */

// TODO translate rus to eng

public class OperationsWithNumbers2 {
    private static void findEvenAndOddNumbers(Integer[] sourceNumbers) {
        List<Integer> evens = new ArrayList<Integer>();
        List<Integer> odds = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            if (sourceNumber % 2 == 0) {
                evens.add(sourceNumber);
            } else {
                odds.add(sourceNumber);
            }
        }
        System.out.println("Чётные числа: " + evens);
        System.out.println("Нечётные числа: " + odds);
    }

    private static void findMaxAndMinNumbers(Integer[] sourceNumbers) {
        List<Integer> numbers = Arrays.asList(sourceNumbers);
        System.out.println("Наибольшее число: " + max(numbers));
        System.out.println("Наименьшее число: " + min(numbers));
    }

    private static void findModNumbers(int divider, Integer[] sourceNumbers) {
        System.out.print("Числа, которые делятся на " + divider + ": ");
        for (Integer sourceNumber : sourceNumbers) {
            if (sourceNumber % divider == 0) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    private static void sortNumbersWithBubbleReverseByAbs(
            Integer[] sourceNumbers) {
        Integer[] result = sourceNumbers.clone();
        boolean swapped = true;
        int j = 0;
        int temp;
        while (swapped) {
            swapped = false;
            j++;
            for (int i = 0; i < result.length - j; i++) {
                if (Math.abs(result[i]) < Math.abs(result[i + 1])) {
                    temp = result[i];
                    result[i] = result[i + 1];
                    result[i + 1] = temp;
                    swapped = true;
                }
            }
        }
        System.out.println("Элементы, расположенные методом пузырька "
                + "по убыванию модулей: " + Arrays.asList(result));
    }

    private static void findNumbersWithThreeDifferentDigits(
            Integer[] sourceNumbers) {
        String number;
        List<Integer> result = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            number = sourceNumber.toString();
            if (number.length() == 3 && number.charAt(0) != number.charAt(1)
                    && number.charAt(1) != number.charAt(2)
                    && number.charAt(0) != number.charAt(2)) {
                result.add(sourceNumber);
            }
        }
        System.out.println("Все трехзначные числа, "
                + "в десятичной записи которых нет одинаковых цифр: " + result);
    }

    private static long findGreatestCommonDivisor(long a, long b) {
        while (b > 0) {
            long temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    private static void findGreatestCommonDivisor(Integer[] sourceNumbers) {
        long result = sourceNumbers[0];
        for (int i = 1; i < sourceNumbers.length; i++) {
            result = findGreatestCommonDivisor(result, sourceNumbers[i]);
        }
        System.out.println("Наибольший общий делитель: " + result);
    }

    private static long findLeastCommonMultiple(long a, long b) {
        return a * (b / findGreatestCommonDivisor(a, b));
    }

    private static void findLeastCommonMultiple(Integer[] sourceNumbers) {
        long result = sourceNumbers[0];
        for (int i = 1; i < sourceNumbers.length; i++) {
            if ((sourceNumbers[i] == 0 || sourceNumbers[0] == 0)
                    || (sourceNumbers[i] < 0 || sourceNumbers[0] < 0)) {
                break;
            }
            result = findLeastCommonMultiple(result, sourceNumbers[i]);
        }
        System.out.println("Наименьшее общее кратное: " + result);
    }

    public static boolean isPrimeNumber(int n) {
        boolean prime = true;
        for (long i = 3; i <= Math.sqrt(n); i += 2) {
            if (n <= 1)
                return false;
            if (n == 2)
                return true;
            if (n % i == 0) {
                prime = false;
                break;
            }
        }
        return (n % 2 != 0 && prime && n > 2) || n == 2;
    }

    public static void findPrimeNumbers(Integer[] sourceNumbers) {
        List<Integer> result = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            if (isPrimeNumber(sourceNumber)) {
                result.add(sourceNumber);
            }
        }
        System.out.println("Простые числа: " + result);
    }

    public static void sortNumbersByAscAndDesc(Integer[] sourceNumbers) {
        List<Integer> numbers = Arrays.asList(sourceNumbers.clone());
        sort(numbers);
        System.out.println("Отсортированные числа в порядке возрастания: "
                + numbers);
        reverse(numbers);
        System.out.println("Отсортированные числа в порядке убывания: "
                + numbers);
    }

    private static Map<Integer, Integer> sortNumbersWithDescByValue(
            Map<Integer, Integer> map) {
        List<Map.Entry<Integer, Integer>> frequencyList = new LinkedList<Map.Entry<Integer, Integer>>(
                map.entrySet());
        sort(frequencyList, new Comparator<Object>() {
            @SuppressWarnings("unchecked")
            public int compare(Object o1, Object o2) {
                return ((Entry<Integer, Integer>) (o2)).getValue().compareTo(
                        ((Map.Entry<Integer, Integer>) (o1)).getValue());
            }
        });
        Map<Integer, Integer> result = new LinkedHashMap<Integer, Integer>();
        for (Entry<Integer, Integer> frequency : frequencyList) {
            result.put(frequency.getKey(), frequency.getValue());
        }
        return result;
    }

    private static void findNumbersFrequencyByDesc(Integer[] sourceNumbers) {
        Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            map.put(sourceNumber,
                    frequency(Arrays.asList(sourceNumbers), sourceNumber));
        }
        System.out.println("Числа в порядке убывания частоты встречаемости "
                + "чисел <Число=Встречаемость>: "
                + sortNumbersWithDescByValue(map));
    }

    private static void findHappyNumbers(Integer[] sourceNumbers) {
        String number;
        List<Integer> result = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            number = sourceNumber.toString();
            if (number.length() == 4
                    && number.charAt(0) + number.charAt(1) == number.charAt(2)
                            + number.charAt(3)) {
                result.add(sourceNumber);
            }
        }
        System.out.println("“Счастливые” числа (Сумма 1-ой пары чисел "
                + "= Сумме 2-ой пары): " + result);
    }

    private static void findFibonacciNumbers(Integer[] sourceNumbers) {
        // TODO не отображает 2 последних числа, если они являются числами
        // Фибоначчи
        List<Integer> result = new ArrayList<Integer>();
        for (int i = 0; i < sourceNumbers.length - 2; i++) {
            if (sourceNumbers.length < 3)
                break;
            else if (sourceNumbers[i + 2] == sourceNumbers[i]
                    + sourceNumbers[i + 1])
                result.add(sourceNumbers[i]);
        }
        System.out.println("Числа Фибоначчи: " + result);
    }

    private static void findPalindromicNumbers(Integer[] sourceNumbers) {
        List<StringBuilder> result = new ArrayList<StringBuilder>();
        for (Integer sourceNumber : sourceNumbers) {
            StringBuilder s = new StringBuilder(sourceNumber.toString());
            if (s.toString().equals(s.reverse().toString())) {
                result.add(s);
            }
        }
        System.out.println("Числа-палиндромы: " + result);
    }

    private static void findNumbersOfHalfSumOfNeighbors(Integer[] sourceNumbers) {
        Integer[] numbers = sourceNumbers.clone();
        List<Integer> result = new ArrayList<Integer>();
        for (int i = 1; i < numbers.length - 1; i++) {
            if (numbers.length < 3) {
                break;
            }
            if (numbers[i] == (numbers[i - 1] + numbers[i + 1]) / 2) {
                result.add(numbers[i]);
            }
        }
        System.out.println("Элементы, которые равны полусумме соседних "
                + "элементов: " + result);
    }

    private static void findPeriodForTwoFirstPositiveNumbersInARow(
    // Algorithm @author is RodionGork
            Integer[] sourceNumbers) {
        long p, q, r, l, t, i;
        for (int n = 0; n < sourceNumbers.length - 1; n++) {
            if (sourceNumbers.length < 2) {
                break;
            } else if (sourceNumbers[n] >= 0 && sourceNumbers[n + 1] >= 0) {
                p = sourceNumbers[n];
                q = sourceNumbers[n + 1];
                r = p;
                for (i = 0; i < q; i++) {
                    r = (r * 10) % q;
                }
                t = r;
                l = 0;
                do {
                    r = (r * 10) % q;
                    l++;
                } while (r != t);
                t = r = p;
                System.out.print("Период десятичной дроби p = m/n для "
                        + "первых двух целых положительных чисел n и m, "
                        + "расположенных подряд: 0.");
                for (i = 0; i < l; i++) {
                    r = (r * 10) % q;
                }
                for (i = 0; r != t; i++) {
                    System.out.print(t * 10 / q);
                    r = (r * 10) % q;
                    t = (t * 10) % q;
                }
                System.out.print('(');
                for (i = 0; i < l; i++) {
                    System.out.print(t * 10 / q);
                    t = (t * 10) % q;
                }

                System.out.println(')' + " = " + p + "/" + q);
                break;
            }
        }
    }

    private static void buildPascalTriangleForFirstPositiveNumber(
            Integer[] sourceNumbers) {
        List<Integer> positiveNumbers = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            if (sourceNumber >= 0) {
                positiveNumbers.add(sourceNumber);
            } else {
                break;
            }
        }
        int firstPositiveNumber = positiveNumbers.get(0);
        System.out.print("Сколько строк треугольника Паскаля для числа "
                + firstPositiveNumber + " отображать? ");
        Scanner in = new Scanner(System.in);
        int rows = in.nextInt();
        for (int y = 0; y < rows; y++) {
            int c = firstPositiveNumber;
            for (int i = 0; i < rows - y; i++) {
                System.out.print("   ");
            }
            for (int x = 0; x <= y; x++) {
                System.out.print("   " + c + " ");
                c = c * (y - x) / (x + 1);
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        // 0. Ввести с консоли n целых чисел и поместить их в массив.
        System.out.print("Сколько целых чисел вы собираетесь ввести? ");
        Scanner in = new Scanner(System.in);
        int size = in.nextInt();
        if (size == 0) {
            System.out.print("Программа завершена.");
            System.exit(0);
        }
        Integer[] sourceNumbers = new Integer[size];
        System.out.print("Введите целые числа через пробел "
                + "и нажмите <Enter>: ");
        for (int i = 0; i < size; i++) {
            sourceNumbers[i] = in.nextInt();
        }
        // 1. Четные и нечетные числа
        findEvenAndOddNumbers(sourceNumbers);

        // 2. Наибольшее и наименьшее число.
        findMaxAndMinNumbers(sourceNumbers);

        // 3. Числа, которые делятся на 3 или на 9.
        findModNumbers(3, sourceNumbers);
        findModNumbers(9, sourceNumbers);

        // 4. Числа, которые делятся на 5 и на 7.
        findModNumbers(5, sourceNumbers);
        findModNumbers(7, sourceNumbers);

        // 5. Элементы, расположенные методом пузырька по убыванию модулей.
        sortNumbersWithBubbleReverseByAbs(sourceNumbers);

        // 6. Все трехзначные числа, в десятичной записи которых нет одинаковых
        // цифр.
        findNumbersWithThreeDifferentDigits(sourceNumbers);

        // 7. Наибольший общий делитель и наименьшее общее кратное этих чисел.
        findGreatestCommonDivisor(sourceNumbers);
        findLeastCommonMultiple(sourceNumbers);

        // 8. Простые числа.
        findPrimeNumbers(sourceNumbers);

        // 9. Отсортированные числа в порядке возрастания и убывания.
        sortNumbersByAscAndDesc(sourceNumbers);

        // 10. Числа в порядке убывания частоты встречаемости чисел.
        findNumbersFrequencyByDesc(sourceNumbers);

        // 11. “Счастливые” числа.
        findHappyNumbers(sourceNumbers);

        // 12. Числа Фибоначчи: f0 = f1 = 1, f (n) = f (n–1) + f (n–2).
        findFibonacciNumbers(sourceNumbers);

        // 13. Числа-палиндромы, значения которых в прямом и обратном порядке
        // совпадают.
        findPalindromicNumbers(sourceNumbers);

        // 14. Элементы, которые равны полусумме соседних элементов.
        findNumbersOfHalfSumOfNeighbors(sourceNumbers);

        // 15. Период десятичной дроби p = m/n для первых двух целых
        // положительных чисел n и m, расположенных подряд.
        findPeriodForTwoFirstPositiveNumbersInARow(sourceNumbers);

        // 16. Построить треугольник Паскаля для первого положительного числа.
        buildPascalTriangleForFirstPositiveNumber(sourceNumbers);
    }
}
Re: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: Blazkowicz Россия  
Дата: 20.03.12 13:47
Оценка:
Здравствуйте, m1st, Вы писали:

M>Привет, решение данных заданий на Java — ниже. Покритикуйте.


Думаешь тут что-то новое расскажут?
Re: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: Donz Россия http://donz-ru.livejournal.com
Дата: 20.03.12 13:48
Оценка: 7 (1) +1
Здравствуйте, m1st, Вы писали:

M>Привет, решение данных заданий на Java — ниже. Покритикуйте.


Как минимум надо разделить на стартовый класс с main(String[] args) и класс, содержащий сами методы вычислений.

        // 3. Числа, которые делятся на 3 или на 9.
        findModNumbers(3, sourceNumbers);
        findModNumbers(9, sourceNumbers);

        // 4. Числа, которые делятся на 5 и на 7.
        findModNumbers(5, sourceNumbers);
        findModNumbers(7, sourceNumbers);


В первом случае используется союз "ИЛИ", во втором "И". Второе решение неправильное, так как выведутся числа, которые делятся на пять, а потом числа, делящиеся на семь. Искать пересечение экзаменатор, думаю, сам не захочет.
В первом случае вызов проверки деления на девять не нужен, так как предшествующий вызов с тройкой уже включит в себя все числа, делящиеся на девять.
Re[2]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: Donz Россия http://donz-ru.livejournal.com
Дата: 20.03.12 13:49
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

M>>Привет, решение данных заданий на Java — ниже. Покритикуйте.

B>Думаешь тут что-то новое расскажут?

А где-то уже критиковали старое?
Re[3]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: Blazkowicz Россия  
Дата: 20.03.12 13:53
Оценка:
Здравствуйте, Donz, Вы писали:

M>>>Привет, решение данных заданий на Java — ниже. Покритикуйте.

B>>Думаешь тут что-то новое расскажут?

D>А где-то уже критиковали старое?

http://www.sql.ru/forum/actualthread.aspx?tid=926718
Re[2]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 20.03.12 14:26
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, m1st, Вы писали:


M>>Привет, решение данных заданий на Java — ниже. Покритикуйте.


B>Думаешь тут что-то новое расскажут?

Как видишь... ж)
Re[3]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: Blazkowicz Россия  
Дата: 20.03.12 14:28
Оценка:
Здравствуйте, m1st, Вы писали:

B>>Думаешь тут что-то новое расскажут?

M>Как видишь... ж)
И правда. Причесал код — сразу стало виднее.
Re[2]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 20.03.12 14:29
Оценка:
Здравствуйте, Donz, Вы писали:
D>В первом случае используется союз "ИЛИ", во втором "И". Второе решение неправильное, так как выведутся числа, которые делятся на пять, а потом числа, делящиеся на семь. Искать пересечение экзаменатор, думаю, сам не захочет.
D>В первом случае вызов проверки деления на девять не нужен, так как предшествующий вызов с тройкой уже включит в себя все числа, делящиеся на девять.
Спасибо — "по-своему" понял задание. ж)
Re: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: tavr  
Дата: 21.03.12 06:53
Оценка:
Здравствуйте, m1st, Вы писали:
M>Привет, решение данных заданий на Java — ниже. Покритикуйте.
Что первым бросилось в глаза — во все методы передается массив Integer[], хотя заранее известно что null нет, а значит используются примитивы
Для ввода цифр не нужно запрашивать их количество — вас могут и обмануть! Лучше посчитать самому
если вы хотите гарантированно иметь неизменный исходный массив, клонировать лучше ДО передачи в библиотечный метод
Re[2]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 21.03.12 18:59
Оценка:
Здравствуйте, tavr, Вы писали:

T>Для ввода цифр не нужно запрашивать их количество — вас могут и обмануть! Лучше посчитать самому

T>если вы хотите гарантированно иметь неизменный исходный массив
Как тогда лучше организовать ввод цифр строкой и выйти из ввода, например, по букве 'q'?
Re[3]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 22.03.12 15:18
Оценка:
Добавляю свежую версию программы.

OperationsWithNumbersStarter — стартовый класс:
package chapt01.b;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import static chapt01.b.OperationsWithNumbersSolver.*;

/**
 * @author m1st
 * 
 */

// TODO translate rus text to eng
// TODO for immutable rus text see native2ascii, ResourceBundle

public class OperationsWithNumbersStarter {
    public static void main(String[] args) {
        // 0. Ввести с консоли n целых чисел и поместить их в массив. На консоль
        // вывести:
        Scanner in = new Scanner(System.in);
        List<Integer> input = new ArrayList<Integer>();
        System.out.print("Введите целые числа через пробел, "
                + "для окончания введите q: ");
        while (true) {
            String number = in.next();
            if (number.equals("q")) {
                break;
            } else {
                try {
                    input.add(Integer.parseInt(number));
                } catch (NumberFormatException e) {
                    System.out.print("Неправильный формат. Повторите ввод: ");
                }
            }
        }
        if (input.size() == 0) {
            System.exit(0);
        }
        int[] sourceNumbers = new int[input.size()];
        System.arraycopy(toIntArray(input), 0, sourceNumbers, 0, input.size());
        // 1. Четные и нечетные числа
        findEvenAndOddNumbers(sourceNumbers);

        // 2. Наибольшее и наименьшее число.
        findMaxAndMinNumbers(toIntegerList(sourceNumbers));

        // 3. Числа, которые делятся на 3 или на 9.
        findModNumbers(3, sourceNumbers);

        // 4. Числа, которые делятся на 5 и на 7.
        findModNumbers(5, 7, sourceNumbers);

        // 5. Элементы, расположенные методом пузырька по убыванию модулей.
        int[] sourceNumbersClone1 = sourceNumbers.clone();
        sortNumbersWithBubbleReverseByAbs(sourceNumbersClone1);

        // 6. Все трехзначные числа, в десятичной записи которых нет одинаковых
        // цифр.
        findNumbersWithThreeDifferentDigits(sourceNumbers);

        // 7. Наибольший общий делитель и наименьшее общее кратное этих чисел.
        findGreatestCommonDivisor(sourceNumbers);
        findLeastCommonMultiple(sourceNumbers);

        // 8. Простые числа.
        findPrimeNumbers(sourceNumbers);

        // 9. Отсортированные числа в порядке возрастания и убывания.
        sortNumbersByAscAndDesc(toIntegerList(sourceNumbers));

        // 10. Числа в порядке убывания частоты встречаемости чисел.
        findNumbersFrequencyByDesc(toIntegerList(sourceNumbers));

        // 11. “Счастливые” числа.
        findHappyNumbers(sourceNumbers);

        // 12. Числа Фибоначчи: f0 = f1 = 1, f (n) = f (n–1) + f (n–2).
        findFibonacciNumbers(sourceNumbers);

        // 13. Числа-палиндромы, значения которых в прямом и обратном порядке
        // совпадают.
        findPalindromicNumbers(sourceNumbers);

        // 14. Элементы, которые равны полусумме соседних элементов.
        int[] sourceNumbersClone2 = sourceNumbers.clone();
        findNumbersOfHalfSumOfNeighbors(sourceNumbersClone2);

        // 15. Период десятичной дроби p = m/n для первых двух целых
        // положительных чисел n и m, расположенных подряд.
        findPeriodForTwoFirstPositiveNumbersInARow(sourceNumbers);

        // 16. Построить треугольник Паскаля для первого положительного числа.
        buildPascalTriangleForFirstPositiveNumber(sourceNumbers);
    }
}


OperationsWithNumbersSolver — класс, содержащий методы вычислений:
package chapt01.b;

import java.util.*;
import java.util.Map.Entry;

import static java.util.Collections.*;

public class OperationsWithNumbersSolver {
    public static List<Integer> toIntegerList(int[] array) {
        List<Integer> result = new ArrayList<Integer>();
        for (int anArray : array)
            result.add(anArray);
        return result;
    }

    public static int[] toIntArray(List<Integer> list) {
        int[] result = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            result[i] = list.get(i);
        }
        return result;
    }

    public static void findEvenAndOddNumbers(int[] sourceNumbers) {
        List<Integer> evens = new ArrayList<Integer>();
        List<Integer> odds = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            if (sourceNumber % 2 == 0) {
                evens.add(sourceNumber);
            } else {
                odds.add(sourceNumber);
            }
        }
        System.out.println("Чётные числа: " + evens);
        System.out.println("Нечётные числа: " + odds);
    }

    public static void findMaxAndMinNumbers(List<Integer> sourceNumbers) {
        System.out.println("Наибольшее число: " + max(sourceNumbers));
        System.out.println("Наименьшее число: " + min(sourceNumbers));
    }

    public static void findModNumbers(int divider, int[] sourceNumbers) {
        System.out.print("Числа, которые делятся на " + divider + ": ");
        for (Integer sourceNumber : sourceNumbers) {
            if (sourceNumber % divider == 0) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void findModNumbers(int divider1, int divider2,
            int[] sourceNumbers) {
        System.out.print("Числа, которые делятся на " + divider1 + " и на "
                + divider2 + ": ");
        for (Integer sourceNumber : sourceNumbers) {
            if ((sourceNumber % divider1 == 0) && (sourceNumber % divider2 == 0)) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void sortNumbersWithBubbleReverseByAbs(int[] sourceNumbers) {
        boolean swapped = true;
        int j = 0;
        int temp;
        while (swapped) {
            swapped = false;
            j++;
            for (int i = 0; i < sourceNumbers.length - j; i++) {
                if (Math.abs(sourceNumbers[i]) < Math.abs(sourceNumbers[i + 1])) {
                    temp = sourceNumbers[i];
                    sourceNumbers[i] = sourceNumbers[i + 1];
                    sourceNumbers[i + 1] = temp;
                    swapped = true;
                }
            }
        }
        System.out.print("Элементы, расположенные методом пузырька "
                + "по убыванию модулей: ");
        for (int sourceNumber : sourceNumbers)
            System.out.print(sourceNumber + ", ");
    }

    public static void findNumbersWithThreeDifferentDigits(int[] sourceNumbers) {
        String number;
        System.out.print("\nВсе трехзначные числа, "
                + "в десятичной записи которых нет одинаковых цифр: ");
        for (Integer sourceNumber : sourceNumbers) {
            number = sourceNumber.toString();
            if ((number.length() == 3) && (number.charAt(0) != number.charAt(1))
                    && (number.charAt(1) != number.charAt(2))
                    && (number.charAt(0) != number.charAt(2))) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static long findGreatestCommonDivisor(long a, long b) {
        while (b > 0) {
            long temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    public static void findGreatestCommonDivisor(int[] sourceNumbers) {
        long result = sourceNumbers[0];
        for (int i = 1; i < sourceNumbers.length; i++) {
            result = findGreatestCommonDivisor(result, sourceNumbers[i]);
        }
        System.out.println("Наибольший общий делитель: " + result);
    }

    public static long findLeastCommonMultiple(long a, long b) {
        return a * (b / findGreatestCommonDivisor(a, b));
    }

    public static void findLeastCommonMultiple(int[] sourceNumbers) {
        long result = sourceNumbers[0];
        for (int i = 1; i < sourceNumbers.length; i++) {
            if ((sourceNumbers[i] == 0 || sourceNumbers[0] == 0)
                    || (sourceNumbers[i] < 0 || sourceNumbers[0] < 0)) {
                break;
            }
            result = findLeastCommonMultiple(result, sourceNumbers[i]);
        }
        System.out.println("Наименьшее общее кратное: " + result);
    }

    public static boolean isPrimeNumber(int n) {
        boolean prime = true;
        for (long i = 3; i <= Math.sqrt(n); i += 2) {
            if (n <= 1)
                return false;
            if (n == 2)
                return true;
            if (n % i == 0) {
                prime = false;
                break;
            }
        }
        return ((n % 2 != 0) && prime && n > 2) || n == 2;
    }

    public static void findPrimeNumbers(int[] sourceNumbers) {
        System.out.print("Простые числа: ");
        for (Integer sourceNumber : sourceNumbers) {
            if (isPrimeNumber(sourceNumber)) {
                System.out.print(sourceNumber + ", ");
            }
        }
    }

    public static void sortNumbersByAscAndDesc(List<Integer> sourceNumbers) {
        sort(sourceNumbers);
        System.out.println("\nОтсортированные числа в порядке возрастания: "
                + sourceNumbers);
        reverse(sourceNumbers);
        System.out.println("Отсортированные числа в порядке убывания: "
                + sourceNumbers);
    }

    public static Map<Integer, Integer> sortNumbersWithDescByValue(
            Map<Integer, Integer> map) {
        List<Map.Entry<Integer, Integer>> frequencyList = new LinkedList<Map.Entry<Integer, Integer>>(
                map.entrySet());
        sort(frequencyList, new Comparator<Object>() {
            @SuppressWarnings("unchecked")
            public int compare(Object o1, Object o2) {
                return ((Entry<Integer, Integer>) (o2)).getValue().compareTo(
                        ((Map.Entry<Integer, Integer>) (o1)).getValue());
            }
        });
        Map<Integer, Integer> result = new LinkedHashMap<Integer, Integer>();
        for (Entry<Integer, Integer> frequency : frequencyList) {
            result.put(frequency.getKey(), frequency.getValue());
        }
        return result;
    }

    public static void findNumbersFrequencyByDesc(List<Integer> sourceNumbers) {
        Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            map.put(sourceNumber, frequency(sourceNumbers, sourceNumber));
        }
        System.out.println("Числа в порядке убывания частоты встречаемости "
                + "чисел <Число=Встречаемость>: " + sortNumbersWithDescByValue(map));
    }

    public static void findHappyNumbers(int[] sourceNumbers) {
        String number;
        System.out.print("“Счастливые” числа (сумма 1-ой пары чисел "
                + "= сумме 2-ой пары): ");
        for (Integer sourceNumber : sourceNumbers) {
            number = sourceNumber.toString();
            if ((number.length() == 4)
                    && (number.charAt(0) + number.charAt(1) == number.charAt(2)
                            + number.charAt(3))) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void findFibonacciNumbers(int[] sourceNumbers) {
        // TODO не отображает 2 последних числа, если они являются числами
        // Фибоначчи
        System.out.print("Числа Фибоначчи: ");
        for (int i = 0; i < sourceNumbers.length - 2; i++) {
            if (sourceNumbers.length < 3)
                break;
            else if (sourceNumbers[i + 2] == sourceNumbers[i] + sourceNumbers[i + 1])
                System.out.print(sourceNumbers[i] + ", ");
        }
        System.out.println();
    }

    public static void findPalindromicNumbers(int[] sourceNumbers) {
        System.out.print("Числа-палиндромы: ");
        for (Integer sourceNumber : sourceNumbers) {
            StringBuilder s = new StringBuilder(sourceNumber.toString());
            if (s.toString().equals(s.reverse().toString())) {
                System.out.print(s + ", ");
            }
        }
        System.out.println();
    }

    public static void findNumbersOfHalfSumOfNeighbors(int[] sourceNumbers) {
        System.out.print("Элементы, которые равны полусумме соседних "
                + "элементов: ");
        for (int i = 1; i < sourceNumbers.length - 1; i++) {
            if (sourceNumbers.length < 3) {
                break;
            }
            if (sourceNumbers[i] == ((sourceNumbers[i - 1] + sourceNumbers[i + 1]) / 2)) {
                System.out.print(sourceNumbers[i] + ", ");
            }
        }
    }

    public static void findPeriodForTwoFirstPositiveNumbersInARow(
    // Algorithm by RodionGork
            int[] sourceNumbers) {
        long p, q, r, l, t, i;
        for (int n = 0; n < sourceNumbers.length - 1; n++) {
            if (sourceNumbers.length < 2) {
                break;
            } else if ((sourceNumbers[n] >= 0) && (sourceNumbers[n + 1] >= 0)) {
                p = sourceNumbers[n];
                q = sourceNumbers[n + 1];
                r = p;
                for (i = 0; i < q; i++) {
                    r = (r * 10) % q;
                }
                t = r;
                l = 0;
                do {
                    r = (r * 10) % q;
                    l++;
                } while (r != t);
                t = r = p;
                System.out.print("\nПериод десятичной дроби p = m/n для "
                        + "первых двух целых положительных чисел n и m, "
                        + "расположенных подряд: 0.");
                for (i = 0; i < l; i++) {
                    r = (r * 10) % q;
                }
                for (i = 0; r != t; i++) {
                    System.out.print(t * 10 / q);
                    r = (r * 10) % q;
                    t = (t * 10) % q;
                }
                System.out.print('(');
                for (i = 0; i < l; i++) {
                    System.out.print(t * 10 / q);
                    t = (t * 10) % q;
                }

                System.out.println(')' + " = " + p + "/" + q);
                break;
            }
        }
    }

    public static void buildPascalTriangleForFirstPositiveNumber(
            int[] sourceNumbers) {
        // TODO найти первый номер, а не список c первым номером
        List<Integer> positiveNumbers = new ArrayList<Integer>();
        for (Integer sourceNumber : sourceNumbers) {
            if (sourceNumber >= 0) {
                positiveNumbers.add(sourceNumber);
            } else {
                break;
            }
        }
        int firstPositiveNumber = positiveNumbers.get(0);
        System.out.print("Сколько строк треугольника Паскаля для числа "
                + firstPositiveNumber + " отображать? ");
        Scanner in = new Scanner(System.in);
        int rows = in.nextInt();
        for (int y = 0; y < rows; y++) {
            int c = firstPositiveNumber;
            for (int i = 0; i < rows - y; i++) {
                System.out.print("   ");
            }
            for (int x = 0; x <= y; x++) {
                System.out.print("   " + c + " ");
                c = c * (y - x) / (x + 1);
            }
            System.out.println();
        }
    }
}
Re[4]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: maxkar  
Дата: 23.03.12 17:29
Оценка: 7 (1)
Здравствуйте, m1st, Вы писали:

По новой версии.
  1. Везде, где можно, объявить локальные переменные как final. Очень помогает при чтении кода. final-переменная — это "название для ...". non-final-переменная — это ячейка, которая может измениться. За всеми такими переменными нужно особо внимательно следить в цилках и ветвлениях (вдруг они значения поменяют). При чтении кода обработка non-final-переменной требует гораздо больше усилий и времени.
  2. static import для проверки тестовой задачи — огромное зло. Ее без IDE читать совершенно невозможно. Я прекрасно знаю по Collections.sort, Collections.min, Collections.max и прочих. Но вот по распечатке (или листинку) понять, что это именно те самые sort, min и max очень сложно.
  3. Чтение списка стоило бы вынести в метод. Или два — один работает с переданным сканером/потоком, второй — вызывает первый с настройками для System.in
  4. Я бы еще конец файла обрабатывал так же, как и "q".
  5. System.arrayCopy там вроде совсем лишний. toIntArray уже создает новый массив.
  6. Постановка задачи про числа фибоначчи не понятна. Я не понял, что именно нужно из последовательности выделить и зачем в условии f(0)=f(1)=1
  7. toIntegerList, в конструктор ArrayList стоило бы передать array.length. Это поможет убрать лишние реаллокации.
  8. toIntArray, правильно было бы идти по списку итератором и параллельно считать позицию в массиве. Если вдруг в метод будет передан LinkedList, с быстродействием будут проблемы.
  9. toIntArray, а зачем там "строгий" List в параметре? Можно Collection<Integer> получать без ограничения работоспособности метода
  10. findEvenAndOddNumbers, в итерации у sourceNumber должен быть тип int а не Integer. У вас же исходный массив — инты. Вы лишний анбоксинг получаете на проверке делимости.
  11. findMaxAndMinNumbers, конвертацию из массива в список стоило бы сделать в этой функции (для одинаковости интерфейса) или передавать туда исходный список (не создавая новый список из массива)
  12. findModNumbers(int, int[]), sourceNumber должен быть int. Смысла в boxing+unboxing я вообще никакого не вижу. И даже если вдруг он заоптимизируется, все равно смысла в итерации по Integer не вижу.
  13. findModNumbers(int, int, int[]) — аналогично предыдущему.
  14. sortNumbersWithBubbleReverseByAbs, мне кажется, что итерацию было бы логичнее записать как do { ... } while (swapped). Она более четко выражает алгоритм.
  15. sortNumbersWithBubbleReverseByAbs, вывод можно делать с помощью java.util.Arrays.toString (хотя и не обязательно, конечно)
  16. sortNumbersWithBubbleReverseByAbs, у вас вроде бы System.out.println() забыт
  17. findNumbersWithThreeDifferentDigits, опять итерация по Integer вместо int
  18. findNumbersWithThreeDifferentDigits, я бы сначала проверил, сколько у числа цифр, а затем уже конвертировал в строку (если нужно).
  19. findNumbersWithThreeDifferentDigits, а "-27" — это двухзначное или трехзначное число?
  20. findGreatestCommonDivisor(long, long), совершенно некорректно работает с отрицательными числами. На -3, -7 дает почему-то "-3". Если отрицательные числа не поддерживаются, нужно выбрасывать ошибку. Но вообще НОД и для отрицательных чисел нормально определен.
  21. findGreatestCommonDivisor(int[]), некорректно работает с первым нулем в массиве аргументов
  22. findLeastCommonMultiple, лишняя проверка на sourceNumbers[0] в цикле. Оно же у вас не меняется на каждой итерации. Так что можно было бы это проверить ровно один раз.
  23. findLeastCommonMultiple, не очевидно условие останова на 0 и отрицательных числах. Возможно, так должно быть по заданию, но может быть и нет.
  24. findLeastCommonMultiple, что-то нужно делать с переполнениями. Обязательно. Иначе при переполнении чушь получится.
  25. isPrimeNumber, корень из n стоит вычислять всего один раз. Это все же тяжелая операция.
  26. isPrimeNumber, разбор случаев n < 3 нужно вынести из цикла. Заодно и на отрицательных числах метод падать перестанет.
  27. isPrimeNumber, проверку четности n стоило бы сделать до цикла, так было бы понятнее.
  28. isPrimeNumber, я бы вместо prime = false; break сразу делал return false. Так проще читать — не нужно после цикла выяснять, что же это была за переменная и что она значит.
  29. findPrimeNumbers, опять итерация по Integer вместо int
  30. sortNumbersByAscAndDesc, там опять стоило бы, наверное, получать массив int'ов для однородности интерфйса.
  31. sortNumbersWithDescByValue, для списка лучше бы взять ArrayList. Он лишние копирования удаляет (сортируется in-place, а вот LinkedList конвертируется в массив, сортируется, затем конвертируется обратно).
  32. sortNumbersWithDescByValue, SuppressWarnings там совершенно лишний. Лучше с типами разобраться и написать правильный вызов и правильный компаратор.
  33. findNumbersFrequencyByDesc, а там бы лучше HashMap вместо TreeMap. У HashMap ассимптотика вставки гораздо лучше, чем у TreeMap.
  34. findNumbersFrequencyByDesc, реализация с frequency очень неэффективная. Для списка из n элементов построение Map займет n*n операций. Нужно идти линейно по списку, выбирать и обновлять (или добавлять) правильные значения из карты. Это будет всего n операций (с чуть большей константой).
  35. findNumbersFrequencyByDesc, там бы тоже получать массив. Итерацию после переделки можно оставить и по Integer (для работы с Map)
  36. findHappyNumbers, опять итерация по Integer вместо int
  37. findHappyNumbers, до конвертации в строку стоило бы проверить, что число имеет 4 цифры
  38. findHappyNumbers, а "-906" — это счастливое число или нет?
  39. findHappyNumbers, стоило бы на математике сделать, а не на строковых операциях
  40. findFibonacciNumbers, в каждом цикле проверять начальную длину плохо. Да и вообще плохо проверять в цикле, если можно сделать до цикла. Снижается понятность кода.
  41. findFibonacciNumbers, поведение при переполнении не специфицировано. Я думаю, допустимо любое, но выбранное поведение должно быть определено в javadoc. Можно даже, что там будет написано (но явно написано!), что поведение при переполнении не определено.
  42. findPalindromicNumbers, опять итерация по Integer вместо int
  43. findPalindromicNumbers, toString()'ов многовато. Желательно взять один из sourceNumber, а второй из s.rever
  44. findPalindromicNumbers, в качестве упражнения можно сделать то же через математику (можно второй метод написать). Текущий вариант тоже рабочий.
  45. findNumbersOfHalfSumOfNeighbors, проверку на < 3 вынести из цикла
  46. findNumbersOfHalfSumOfNeighbors, работает некорректно на [1, 3, 6]
  47. findNumbersOfHalfSumOfNeighbors, нужно написать про работу с переполнениями, см. комментарий к фибоначчи
  48. findPeriodForTwoFirstPositiveNumbersInARow, поиск двух положительных чисел и нахождение периода должно быть в разных методах. Можно из метода вызывать метод построения периода.
  49. findPeriodForTwoFirstPositiveNumbersInARow, адский набор long p, q, r, l, t, i; нужно бы попереименовывать и поназывать человеческими именами хотя бы половину. Ничего же не понятно
  50. findPeriodForTwoFirstPositiveNumbersInARow, проверку на length < 2 вынести из цикла. Зачем вы это на каждой итерации проверяете?
  51. findPeriodForTwoFirstPositiveNumbersInARow, некорректно работает на [5, 2]
  52. findPeriodForTwoFirstPositiveNumbersInARow, часть long'ов на int'ы стоит заменить. Например, i.
  53. findPeriodForTwoFirstPositiveNumbersInARow, for (i = 0; r != t; i++) {...} — а при чем там i?
  54. findPeriodForTwoFirstPositiveNumbersInARow, for (i = 0; i < l; i++) {...} — а тут?
  55. buildPascalTriangleForFirstPositiveNumber, поиск первого положительного числа вынести в метод
  56. buildPascalTriangleForFirstPositiveNumber, не собирать числа в список, а просто брать первое положительное число.
  57. buildPascalTriangleForFirstPositiveNumber, нужно осмысленно обрабатывать ситуацию, когда положительных чисел нет.

P.S. Если будете отвечать на сообщение с цитированием, спилите, пожалуйста, у него теги list, они вызывают жуткий butthurt все форматирование портят.
Re[5]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 24.03.12 19:41
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Чтение списка стоило бы вынести в метод. Или два — один работает с переданным сканером/потоком, второй — вызывает первый с настройками для System.in

Как сделать с двумя методами — не понял. Можно пример?

M>Я бы еще конец файла обрабатывал так же, как и "q".

У нас же нет чтения из файла. Или вы на будущее предлагаете чтобы метод и чтение из фала решал?

M>Постановка задачи про числа фибоначчи не понятна. Я не понял, что именно нужно из последовательности выделить и зачем в условии f(0)=f(1)=1

Похоже, что автор задания считает, что 1 и 2 элементы числовой последовательности — это единица. Хотя ноль тоже является числом Ф.

M>findLeastCommonMultiple, что-то нужно делать с переполнениями. Обязательно. Иначе при переполнении чушь получится.

В каком именно месте переполнение? Какие варианты решений при переполнениях?
Re[6]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: maxkar  
Дата: 26.03.12 09:07
Оценка:
Здравствуйте, m1st, Вы писали:

M>>Чтение списка стоило бы вынести в метод. Или два — один работает с переданным сканером/потоком, второй — вызывает первый с настройками для System.in

M>Как сделать с двумя методами — не понял. Можно пример?

public static int[] readIntArray(Scanner sc) {
  ... //реализация метода
}

public static int[] readIntArray(InputStream is) {
  return readIntArray(new Scanner(is));
}

public static int[] readIntArray() {
  return readIntArray(System.in);
}

Даже три получилось. Все — в одном классе. Первый метод реализует саму логику чтения на том объекте, к которому "логичнее всего" применим. Остальные методы служат "интерфейсом" для стандартных задач, упрощая подготовку к использованию "ключевого" метода в типичных случаях. Техника важна в основном для библиотек. Но и в обычном коде может быть применима (особенно если код используется во многих местах).

M>>Я бы еще конец файла обрабатывал так же, как и "q".

M>У нас же нет чтения из файла. Или вы на будущее предлагаете чтобы метод и чтение из фала решал?

Методы выше вполне позволят добавить и чтение из файла. Можно при желании и readIntArray(File file) добавить. Но дело не в этом.

Конец файла вполне нормально изображается и при вводе с клавиатуры. В Unix и Linux это Ctrl-d. В Windows Ctrl-z <enter>. При частой работе с консолью к комбинации привыкаешь. Так что для завершения ввода (или последней порции данных, если данных много) в консоли тоже может использоваться конец файла и его стоит обрабатывать.

M>>Постановка задачи про числа фибоначчи не понятна. Я не понял, что именно нужно из последовательности выделить и зачем в условии f(0)=f(1)=1

M>Похоже, что автор задания считает, что 1 и 2 элементы числовой последовательности — это единица. Хотя ноль тоже является числом Ф.

Я про другое. Начало можно определить по-разному, это не проблема. Проблема в том, что в решении вы "начальное" условие не используете (вам достаточно только рекуррентного сообщения). И я плохо представляю, как его вообще можно использовать в решении. Может быть, автор имел в виду для каждого числа n во входных данных вычислить его f(n)

M>>findLeastCommonMultiple, что-то нужно делать с переполнениями. Обязательно. Иначе при переполнении чушь получится.

M>В каком именно месте переполнение? Какие варианты решений при переполнениях?

Переполнение при умножении. НОД всегда вычисляется нормально (он ограничен наименьшим из положительных чисел). А вот НОК ограничен только произведением. Если взять несколько первых простых чисел, то мы получим переполнение. Можно и int переполнить, и long и все, что угодно.

Варианты. Первый — считать и выводить в больших числах. Например, в java.math.BigInteger. Второй — добавить к методу комментарий. Вообще, добавление комментария во всех случаях кроме использования большой арифметики очень полезно. javadoc-комментарии видно в IDE при вызове метода, так что можно уточнить детали (поведение в случае переполнения) не заходя в реализацию. Выглядит так:
/**
 * Метод вычисляет НОК чисел в массиве. Вычисление завершается на первом нулевом или отрицательном числе (оно не входит в НОК).
 * <strong>Результат метода в случае переполнения не определен</strong>
 * @param sourceNumbers числа для нахождения НОК
 * @return НОК. В случае переполнения результат не определен.
 */
public static long findLeastCommonMultiple(int[] sourceNumbers) {
...
}


В данном случае комментарий достаточен, но можно и лучше. Потому что еще одна проблема решения — "неправильное" переполнение. На массиве [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59] НОК (если считать правильно) после переполнения будет 4298966488419271006 (уже обрезано до 64 бит), а ваш алгоритм даст -4304329670229058502 (где-то после переполнения находит общий множитель). Даже предупреждение выше может быть трактовано неправильно и кто-то из пользователей вашего кода подумает, что результат будет корректным, но урезанным до используемого типа данных. Поэтому еще лучше было бы явно проверять "неверные" данные и выдавать соответствующий результат. Выглядит в документации примерно так (поведение должно быть задокументировано все равно!):
/**
 * Метод вычисляет НОК чисел в массиве. Если исходный массив не корректен или при вычислении возникает переполнение, возвращает -1.
 * @param sourceNumbers положительные числа для нахождения НОК
 * @return НОК чисел, если числа в <code>sourceNumbers</code> положительны и НОК помещается в тип long. 
 *         -1 в случае, если <code>sourceNumbers</code> содержит неположительное число, либо НОК не помещается в тип long.
 */
public static long findLeastCommonMultiple(int[] sourceNumbers) {
...
}

// или

/**
 * Метод вычисляет НОК чисел в массиве. 
 * @param sourceNumbers положительные числа для нахождения НОК
 * @return НОК чисел
 * @throws IllegalArgumentException если массив содержит неположительное число
 * @throws LCMTooLargeException если НОК не может быть представлен значением типа long.
 */
public static long findLeastCommonMultiple(int[] sourceNumbers) throws IllegalArgumentException, LCMTooLargeExceptoin{
...
}

Есть и третий вариант — одно исключение и индикаторное значение. Я бы выбрал как раз третий вариант с исключением IllegalArgumentException (аргументы должен корректно формировать вызывающий) и -1 для случая переполнения (при таком API ситуация вполне вероятная, поэтому лучше представлять ее обычным "результатом" чем исключением).
Re[5]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 28.03.12 17:06
Оценка:
Здравствуйте, maxkar, Вы писали:

M>findLeastCommonMultiple, не очевидно условие останова на 0 и отрицательных числах. Возможно, так должно быть по заданию, но может быть и нет.

На отрицательных числах — да, но на 0 — очевидно, т.к нет смысла продолжать искать НОК дальше, если НОК(0)=0;

M>findFibonacciNumbers, поведение при переполнении не специфицировано. Я думаю, допустимо любое, но выбранное поведение должно быть определено в javadoc. Можно даже, что там будет написано (но явно написано!), что поведение при переполнении не определено.

M>findNumbersOfHalfSumOfNeighbors, нужно написать про работу с переполнениями, см. комментарий к фибоначчи
А где в этих двух методах переполнение?
Re[6]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 28.03.12 17:46
Оценка:
Исправленная и улучшенная версия.

OperationsWithNumbersStarter — стартовый класс:
package chapt01.b;

import static chapt01.b.OperationsWithNumbersSolver.*;

/**
 * @author m1st
 * 
 */

// TODO for immutable rus text see native2ascii, ResourceBundle

public class OperationsWithNumbersStarter {
    public static void main(String[] args) {
        // 0. Ввести с консоли n целых чисел и поместить их в массив. На консоль
        // вывести:
        int[] sourceNumbers = readInput();

        // 1. Четные и нечетные числа
        findEvenAndOddNumbers(sourceNumbers);

        // 2. Наибольшее и наименьшее число.
        findMaxAndMinNumbers(sourceNumbers);

        // 3. Числа, которые делятся на 3 или на 9.
        findModNumbers(3, sourceNumbers);

        // 4. Числа, которые делятся на 5 и на 7.
        findModNumbers(5, 7, sourceNumbers);

        // 5. Элементы, расположенные методом пузырька по убыванию модулей.
        int[] sourceNumbersClone1 = sourceNumbers.clone();
        sortNumbersWithBubbleReverseByAbs(sourceNumbersClone1);

        // 6. Все трехзначные числа, в десятичной записи которых нет одинаковых
        // цифр.
        findNumbersWithThreeDifferentDigits(sourceNumbers);

        // 7. Наибольший общий делитель и наименьшее общее кратное этих чисел.
        findGreatestCommonDivisor(sourceNumbers);
        findLeastCommonMultiple(sourceNumbers);

        // 8. Простые числа.
        findPrimeNumbers(sourceNumbers);

        // 9. Отсортированные числа в порядке возрастания и убывания.
        sortNumbersByAscAndDesc(sourceNumbers);

        // 10. Числа в порядке убывания частоты встречаемости чисел.
        findNumbersFrequencyByDesc(sourceNumbers);

        // 11. “Счастливые” числа.
        findHappyNumbers(sourceNumbers);

        // 12. Числа Фибоначчи: f0 = f1 = 1, f (n) = f (n–1) + f (n–2).
        findFibonacciNumbers(sourceNumbers);

        // 13. Числа-палиндромы, значения которых в прямом и обратном порядке
        // совпадают.
        findPalindromicNumbers(sourceNumbers);

        // 14. Элементы, которые равны полусумме соседних элементов.
        int[] sourceNumbersClone2 = sourceNumbers.clone();
        findNumbersOfHalfSumOfNeighbors(sourceNumbersClone2);

        // 15. Период десятичной дроби p = m/n для первых двух целых
        // положительных чисел n и m, расположенных подряд.
        findPeriodForFirstTwoPositiveNumbersInARow(sourceNumbers);

        // 16. Построить треугольник Паскаля для первого положительного числа.
        buildPascalTriangleForFirstPositiveNumber(sourceNumbers);
    }
}


OperationsWithNumbersSolver — класс, содержащий методы вычислений:
package chapt01.b;

import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;

/**
 * @author m1st
 * 
 */

public class OperationsWithNumbersSolver {
    public static int[] readInput(Scanner sc) {
        List<Integer> input = new ArrayList<Integer>();
        System.out.print("Введите целые числа через пробел, "
                + "для окончания введите q: ");
        while (sc.hasNext()) {
            String number = sc.next();
            if (number.equals("q")) {
                break;
            } else {
                try {
                    input.add(Integer.parseInt(number));
                } catch (NumberFormatException e) {
                    System.out.print("Неправильный формат. Программа завершена. ");
                    System.exit(0);
                }
            }
        }
        if (input.size() == 0) {
            System.exit(0);
        }
        return toIntArray(input);
    }

    public static int[] readInput(InputStream is) {
        return readInput(new Scanner(is));
    }

    public static int[] readInput() {
        return readInput(System.in);
    }

    public static List<Integer> toIntegerList(int[] array) {
        List<Integer> result = new ArrayList<Integer>(array.length);
        for (int element : array) {
            result.add(element);
        }
        return result;
    }

    public static int[] toIntArray(Collection<Integer> list) {
        int[] result = new int[list.size()];
        Iterator<Integer> it = list.iterator();
        for (int i = 0; i < list.size(); i++) {
            result[i] = it.next();
        }
        return result;
    }

    public static void findEvenAndOddNumbers(int[] sourceNumbers) {
        List<Integer> evens = new ArrayList<Integer>();
        List<Integer> odds = new ArrayList<Integer>();
        for (int sourceNumber : sourceNumbers) {
            if (sourceNumber % 2 == 0) {
                evens.add(sourceNumber);
            } else {
                odds.add(sourceNumber);
            }
        }
        System.out.println("Чётные числа: " + evens);
        System.out.println("Нечётные числа: " + odds);
    }

    public static void findMaxAndMinNumbers(int[] sourceNumbers) {
        List<Integer> numbers = toIntegerList(sourceNumbers);
        System.out.println("Наибольшее число: " + Collections.max(numbers));
        System.out.println("Наименьшее число: " + Collections.min(numbers));
    }

    public static void findModNumbers(int divider, int[] sourceNumbers) {
        System.out.print("Числа, которые делятся на " + divider + ": ");
        for (int sourceNumber : sourceNumbers) {
            if (sourceNumber % divider == 0) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void findModNumbers(int divider1, int divider2,
            int[] sourceNumbers) {
        System.out.print("Числа, которые делятся на " + divider1 + " и на "
                + divider2 + ": ");
        for (int sourceNumber : sourceNumbers) {
            if ((sourceNumber % divider1 == 0) && (sourceNumber % divider2 == 0)) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void sortNumbersWithBubbleReverseByAbs(int[] sourceNumbers) {
        boolean swapped;
        int j = 0;
        int temp;
        do {
            swapped = false;
            j++;
            for (int i = 0; i < sourceNumbers.length - j; i++) {
                if (Math.abs(sourceNumbers[i]) < Math.abs(sourceNumbers[i + 1])) {
                    temp = sourceNumbers[i];
                    sourceNumbers[i] = sourceNumbers[i + 1];
                    sourceNumbers[i + 1] = temp;
                    swapped = true;
                }
            }
        } while (swapped);
        System.out.print("Элементы, расположенные методом пузырька "
                + "по убыванию модулей: " + Arrays.toString(sourceNumbers) + "\n");
    }

    public static void findNumbersWithThreeDifferentDigits(int[] sourceNumbers) {
        String number;
        System.out.print("Все трехзначные числа, "
                + "в десятичной записи которых нет одинаковых цифр: ");
        for (int sourceNumber : sourceNumbers) {
            if ((int) Math.log10(Math.abs(sourceNumber)) + 1 == 3) {
                number = String.valueOf(sourceNumber);
                if ((number.charAt(0) != number.charAt(1))
                        && (number.charAt(1) != number.charAt(2))
                        && (number.charAt(0) != number.charAt(2))) {
                    System.out.print(sourceNumber + ", ");
                }
            }
        }
        System.out.println();
    }

    public static long findGreatestCommonDivisor(long a, long b) {
        while (b != 0) {
            long temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    public static void findGreatestCommonDivisor(int[] sourceNumbers) {
        long result = sourceNumbers[0];
        if (result == 0) {
            System.out.println("Наибольший общий делитель: " + result);
        } else {
            for (int i = 1; i < sourceNumbers.length; i++) {
                result = findGreatestCommonDivisor(result, sourceNumbers[i]);
            }
            System.out.println("Наибольший общий делитель: " + result);
        }
    }

    public static long findLeastCommonMultiple(long a, long b) {
        return a * (b / findGreatestCommonDivisor(a, b));
    }

    /**
     * Метод вычисляет НОК чисел в массиве. Вычисление завершается на первом
     * нулевом числе (оно не входит в НОК). <strong>Результат метода в случае
     * переполнения не определен</strong>
     * 
     * @param sourceNumbers
     *          числа для нахождения НОК
     * @return НОК. В случае переполнения результат не определен.
     */
    public static void findLeastCommonMultiple(int[] sourceNumbers) {
        long result = sourceNumbers[0];
        if (result == 0) {
            System.out.println("Наименьшее общее кратное: " + result);
        } else {
            for (int i = 1; i < sourceNumbers.length; i++) {
                if (sourceNumbers[i] == 0) {
                    break;
                }
                result = findLeastCommonMultiple(result, sourceNumbers[i]);
            }
        }
        System.out.println("Наименьшее общее кратное: " + result);
    }

    public static boolean isPrimeNumber(int number) {
        final double numberSquareRoot = Math.sqrt(number);
        if (number <= 1) {
            return false;
        }
        if (number == 2) {
            return true;
        }
        for (long i = 3; i <= numberSquareRoot; i += 2) {
            if (number % i == 0) {
                return false;
            }
        }
        return ((number % 2 != 0) && number > 2);
    }

    public static void findPrimeNumbers(int[] sourceNumbers) {
        System.out.print("Простые числа: ");
        for (int sourceNumber : sourceNumbers) {
            if (isPrimeNumber(sourceNumber)) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void sortNumbersByAscAndDesc(int[] sourceNumbers) {
        List<Integer> numbers = toIntegerList(sourceNumbers);
        Collections.sort(numbers);
        System.out.println("Отсортированные числа в порядке возрастания: "
                + numbers);
        Collections.reverse(numbers);
        System.out.println("Отсортированные числа в порядке убывания: " + numbers);
    }

    public static Map<Integer, Integer> sortNumbersWithDescByValue(
            Map<Integer, Integer> map) {
        List<Map.Entry<Integer, Integer>> frequencyList = new ArrayList<Map.Entry<Integer, Integer>>(
                map.entrySet());
        Collections.sort(frequencyList, new Comparator<Object>() {
            @SuppressWarnings("unchecked")
            public int compare(Object o1, Object o2) {
                return ((Entry<Integer, Integer>) (o2)).getValue().compareTo(
                        ((Map.Entry<Integer, Integer>) (o1)).getValue());
            }
        });
        Map<Integer, Integer> result = new LinkedHashMap<Integer, Integer>();
        for (Entry<Integer, Integer> frequency : frequencyList) {
            result.put(frequency.getKey(), frequency.getValue());
        }
        return result;
    }

    public static void findNumbersFrequencyByDesc(int[] sourceNumbers) {
        List<Integer> numbers = toIntegerList(sourceNumbers);
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (Integer number : numbers) {
            map.put(number, Collections.frequency(numbers, number));
        }
        System.out.println("Числа в порядке убывания частоты встречаемости "
                + "чисел (число=встречаемость): " + sortNumbersWithDescByValue(map));
    }

    public static void findHappyNumbers(int[] sourceNumbers) {
        System.out.print("“Счастливые” числа (сумма 1-ой пары чисел "
                + "= сумме 2-ой пары): ");
        int digit1, digit2, digit3, digit4;
        for (int sourceNumber : sourceNumbers) {
            if ((int) Math.log10(Math.abs(sourceNumber)) + 1 == 4) {
                digit1 = sourceNumber / 1000;
                digit2 = sourceNumber / 100 % 10;
                digit3 = sourceNumber % 100 / 10;
                digit4 = sourceNumber % 10;
                if (digit1 + digit2 == digit3 + digit4) {
                    System.out.print(sourceNumber + ", ");
                }
            }
        }
        System.out.println();

    }

    public static void findFibonacciNumbers(int[] sourceNumbers) {
        System.out.print("Числа Фибоначчи: ");
        if (sourceNumbers.length >= 3) {
            if (sourceNumbers[0] == 0) {
                System.out.print("0, ");
                if (sourceNumbers[1] == 1) {
                    System.out.print("1, ");
                }
            }
            for (int i = 2; i < sourceNumbers.length; i++) {
                if (sourceNumbers[i] == sourceNumbers[i - 2] + sourceNumbers[i - 1]) {
                    System.out.print(sourceNumbers[i] + ", ");
                }
            }
        } else {
            System.out.print("sourceNumbers.length < 3");
        }
        System.out.println();
    }

    public static int reverseInt(int value) {
        int result = 0;
        final int limit = (int) Math.log10(Math.abs(value)) + 1;
        for (int i = 0; i < limit; i++) {
            result = result * 10 + value % 10;
            value /= 10;
        }
        return result;
    }

    public static void findPalindromicNumbers(int[] sourceNumbers) {
        System.out.print("Числа-палиндромы: ");
        for (int sourceNumber : sourceNumbers) {
            if (sourceNumber == reverseInt(sourceNumber)) {
                System.out.print(sourceNumber + ", ");
            }
        }
        System.out.println();
    }

    public static void findNumbersOfHalfSumOfNeighbors(int[] sourceNumbers) {
        System.out.print("Элементы, которые равны полусумме соседних "
                + "элементов: ");
        if (sourceNumbers.length >= 3) {
            for (int i = 1; i < sourceNumbers.length - 1; i++) {
                if (sourceNumbers[i] == ((float) (sourceNumbers[i - 1] + sourceNumbers[i + 1]) / 2)) {
                    System.out.print(sourceNumbers[i] + ", ");
                }
            }
        } else {
            System.out.print("sourceNumbers.length < 3");
        }
        System.out.println();
    }

    public static int[] findFirstTwoPositiveNumbersInARow(int[] sourceNumbers) {
        int[] twoPositiveNumbers = new int[2];
        for (int i = 0; i < sourceNumbers.length - 1; i++) {
            if ((sourceNumbers[i] > 0) && (sourceNumbers[i + 1] > 0)) {
                twoPositiveNumbers[0] = sourceNumbers[i];
                twoPositiveNumbers[1] = sourceNumbers[i + 1];
                break;
            }
        }
        return twoPositiveNumbers;
    }

    // Algorithm by RodionGork
    public static void findPeriodForFirstTwoPositiveNumbersInARow(
            int[] sourceNumbers) {
        String message = "Период десятичной дроби для "
                + "первых двух целых положительных чисел, " + "расположенных подряд: ";
        if (sourceNumbers.length >= 2) {
            int r, l, t, i;
            int[] twoPositiveNumbers = findFirstTwoPositiveNumbersInARow(sourceNumbers);
            if (twoPositiveNumbers[0] > 0 || twoPositiveNumbers[1] > 0) {
                int numerator = twoPositiveNumbers[0];
                int denominator = twoPositiveNumbers[1];
                r = numerator;
                for (i = 0; i < denominator; i++) {
                    r = (r * 10) % denominator;
                }
                t = r;
                l = 0;
                do {
                    r = (r * 10) % denominator;
                    l++;
                } while (r != t);
                t = r = numerator;
                System.out.print(message + "0.");
                for (i = 0; i < l; i++) {
                    r = (r * 10) % denominator;
                }
                for (i = 0; r != t; i++) {
                    System.out.print(t * 10 / denominator);
                    r = (r * 10) % denominator;
                    t = (t * 10) % denominator;
                }
                System.out.print('(');
                for (i = 0; i < l; i++) {
                    System.out.print(t * 10 / denominator);
                    t = (t * 10) % denominator;
                }
                System.out.println(')' + " = " + numerator + "/" + denominator);
            } else {
                System.out.println(message + "нету двух целых положительных чисел, "
                        + "расположенных подряд");
            }
        } else {
            System.out.println(message + "sourceNumbers.length < 2");
        }
    }

    public static int findFirstPositiveNumber(int[] sourceNumbers) {
        int positiveNumber = 0;
        for (int sourceNumber : sourceNumbers) {
            if (sourceNumber > positiveNumber) {
                positiveNumber = sourceNumber;
                break;
            }
        }
        return positiveNumber;
    }

    public static void buildPascalTriangleForFirstPositiveNumber(
            int[] sourceNumbers) {
        final int firstPositiveNumber = findFirstPositiveNumber(sourceNumbers);
        if (firstPositiveNumber > 0) {
            System.out.print("Сколько строк треугольника Паскаля для числа "
                    + firstPositiveNumber + " отображать? ");
            Scanner in = new Scanner(System.in);
            if (in.hasNext()) {
                final int rows = in.nextInt();
                for (int y = 0; y < rows; y++) {
                    int c = firstPositiveNumber;
                    for (int i = 0; i < rows - y; i++) {
                        System.out.print("   ");
                    }
                    for (int x = 0; x <= y; x++) {
                        System.out.print("   " + c + " ");
                        c = c * (y - x) / (x + 1);
                    }

                    System.out.println();
                }
            } else {
                System.out.println("!in.hasNext()");
            }
        } else {
            System.out.println("Треугольник Паскаля для первого положительного "
                    + "числа: нет чисел > 0");
        }
    }
}
Re[6]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: maxkar  
Дата: 29.03.12 17:16
Оценка:
Здравствуйте, m1st, Вы писали:

M>>findFibonacciNumbers, поведение при переполнении не специфицировано. Я думаю, допустимо любое, но выбранное поведение должно быть определено в javadoc. Можно даже, что там будет написано (но явно написано!), что поведение при переполнении не определено.

M>>findNumbersOfHalfSumOfNeighbors, нужно написать про работу с переполнениями, см. комментарий к фибоначчи
M>А где в этих двух методах переполнение?

Сумма двух интов всегда имеет тип int. Посмотрите вывод примера ниже. У вас примерно то же может быть. [minvalue, 0, minvalue] даст то, что 0 равен сумме двух других чисел. В фибоначчи похожая ситуация. Нужно явно приводить что-нибудь к long, тогда проблем не возникнет.

public class Main {
    public static void main(String[] args) {
        System.out.println(Integer.MIN_VALUE + Integer.MIN_VALUE);
        System.out.println(Integer.MAX_VALUE + Integer.MAX_VALUE);
    }
}


На следующий ваш вариант отвечу обязательно (там тоже есть интересные моменты), но не сегодня.
Re[7]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: maxkar  
Дата: 30.03.12 16:26
Оценка:
Здравствуйте, m1st, Вы писали:

M>Исправленная и улучшенная версия.


Поехали по новому варианту.
  1. readInput(Scanner). Как-то слишком жестоко делать System.exit в "библиотечном" методе, когда ничего не ввели. Такой выход гораздо лучше смотрелся бы в *Starter.
  2. readInput(Scanner). Если рассматривать метод как библиотечный, в случае ошибки ввода лучше выбросить соответствующее исключение (BadInputException, например). И пусть его правильно обрабатывает вызывающий.
  3. toIntArray. Нормально, такой вариант дальше можно не переделывать. Я бы написал так: int i = 0; for (Integer x : list) { result[i++] = x; }. Такую форму тоже стоит уметь читать. Объективных причин за выбор того или другого варианта не вижу.
  4. sortNumbersWithBubbleReverseByAbs. В тот раз не заметил очень интересную ошибку. У вас сортировка в некоторых случаях работает неправильно. Попробуйте, например, отсортировать [Integer.MIN_VALUE, 0]. И [Integer.MIN_VALUE, 0, Integer.MAX_VALUE]. В Java уравнение (x == -x) имеет два решения, а не одно. Это нужно учитывать (явно разбирая крайний случай).
  5. findNumbersWithThreeDifferentDigits. Логарифм — это слишком сурово для такой задачи. Банальная проверка 100 <= sourceNumber <= 999 гораздо проще для восприятия. Можно еще до if'а написать комментарий "ищем трехзначные числа"
  6. findNumbersWithThreeDifferentDigits. А проверка опять через строку. Отрицательные числа теперь она не пропустит, но это я бы все-таки проверял явно (проверка на трехзначность выше автоматически это делает).
  7. isPrimeNumber. Я бы numberSquareRoot сразу и округлил при вычислении (Math.ceil взял бы на всякий случай). Идея делать преобразования типов в цикле мне не очень нравится.
  8. isPrimeNumber. Проверку делимости на 2 я бы поставил до цикла. Если входные числа распределены равномерно, это быстрее бы отсеивало значения.
  9. isPrimeNumber. В return условие на number > 2 уже не нужно. Там number уже больше двух.
  10. isPrimeNumber. Стоило бы проверить число на неотрицательность до того, как вы из него корень вычисляете. Программа работать будет нормально, но для того, чтобы в этом убедиться, нужно в справку смотреть.
  11. sortNumbersWithDescByValue. Типизацию компаратора стоит доработать. Вполне можно сделать так, что SuppressWarnings("unchecked") там не понадобится.
  12. findNumbersFrequencyByDesc. Все также на ровном месте сложность n*n операций вместо n. Подсчет количества вхождений должен делаться в один проход (с обновлениями мапы при повторе чисел). Иначе на каждое число вы всю коллекцию проходите заново. На больших массивах (от 100000 элементов) вы почувствуете разницу.
  13. findHappyNumbers. Тут тоже логарифм — слишком жестоко. Обычная проверка на диапазон подойдет.
  14. findHappyNumbers. Не проверял, корректно ли работает метод на отрицательных числах. Рекомендую потестировать, могут быть совсем не интуитивные результат.
  15. Фибоначчи. Мне все больше кажется, что автор задачи для каждого числа n в массиве хотел получить его f(n) а не выбрать числа, удовлетворяющие условиям. Ваша трактовка тоже имеет право на существование, но все же слишком натянута на условия задачи. Это претензия не к решению, а к задаче.
  16. reverseInt. Я гляжу, вам логарифм понравился . Заранее вычислять количество итераций не нужно. Есть простая форма while (value != 0) {...}. Для многих случаев такая форма записи лучше всего.
  17. reverseInt. result стоит сделать long'ом. И результат — тоже long'ом. Для int'ов вполне предсказуемо переполнение. А вот в long результат влезет. Тип аргумента оставить int'ом (чтобы не возникало вопросов про переполнение long'а).
  18. findNumbersOfHalfSumOfNeighbors. От переполнения вы не избавились. Результа сложения двух интов будет интом и только после этого будет сконвернирован во float. Судя по вашему предыдущему вопросу вы пока еще не разбирались с переполнением в коде, так что это просто напоминание.
  19. findNumbersOfHalfSumOfNeighbors. Выбор float — очень плохой. Но зато позволяет продемонстрировать "сложную" ошибку. Значения типа float недостаточно для точного представления int. У float-а порядка 6-7 точных десятичных знаков. И выражение (i == (float) (i+1)) истинно на значениях 16777216, 16777219, 16777220 и т.д. (i — целое). Таких аномалий среди положительных интов аж целых 2071968175. Если сравнить с общим количеством int'ов как-то грустно выходит. В данном конкретном случае стоит умножить обе части на два и проверка станет гораздо проще. С переполением вам все равно придется бороться, так что никаких дополнительных проблем умножение на два не добавит.
  20. findPeriodForFirstTwoPositiveNumbersInARow. Два лишних уровня вложенности. Обычно такое регламентируется стандартами кодирования. Но в любом случае два лишних уровня вложенности мне не нравятся. В этом методе проблема усугубляется сложным алгоритмом внутри этой вложенности и обработкой граничных случаев уже где-то за экраном. Стандартное решение — инвертирование условий и выход/возврат в граничных вариантах. Т.е первый if разворачивается в if (sourceNumbers.length < 2) { System.out.println("..."); return;}. Его внутренности при этом получают "-1" к отступу. Аналогично со вторым if'ом. Также при этом сразу видна обработка "граничных" случаев. Когда она в конце, не понятно, что за if там был (искть глазами его сложно).
  21. findPeriodForFirstTwoPositiveNumbersInARow. А ошибку для случая "числитель больше знаменателя" так и не поправили. (Да, я знаю, я зануда)
  22. findFirstPositiveNumber. Лишнее "состояние" в методе (positiveNumber) и сложный поток управления. Гораздо лучше при нахождении числа вернуть его сразу изнутри цикла. Хотя этот момент может диктоваться и стандартами кодирования (но такие стандарты мне тоже не нравятся).
  23. buildPascalTriangleForFirstPositiveNumber. Опять два лишних уровня вложенности (как и в периоде дроби).
Re[8]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: m1st  
Дата: 02.04.12 22:14
Оценка:
Здравствуйте, maxkar, Вы писали:

M> toIntArray. Нормально, такой вариант дальше можно не переделывать. Я бы написал так: int i = 0; for (Integer x : list) { result[i++] = x; }. Такую форму тоже стоит уметь читать. Объективных причин за выбор того или другого варианта не вижу.

По toIntArray мы же уже сказали, что "правильно было бы идти по списку итератором и параллельно считать позицию в массиве. Если вдруг в метод будет передан LinkedList, с быстродействием будут проблемы."

M> findNumbersWithThreeDifferentDigits. Логарифм — это слишком сурово для такой задачи. Банальная проверка 100 <= sourceNumber <= 999 гораздо проще для восприятия. Можно еще до if'а написать комментарий "ищем трехзначные числа"

Согласен, проще и дешевле по времени: в ~1,5 раза.

M> findHappyNumbers. Не проверял, корректно ли работает метод на отрицательных числах. Рекомендую потестировать, могут быть совсем не интуитивные результат.

На отрицательных числах работает корректно.

M> Фибоначчи. Мне все больше кажется, что автор задачи для каждого числа n в массиве хотел получить его f(n) а не выбрать числа, удовлетворяющие условиям. Ваша трактовка тоже имеет право на существование, но все же слишком натянута на условия задачи. Это претензия не к решению, а к задаче.

Как мне кажется, в условии сказано вывести "Числа Фибоначчи", а не "f(n)" — последовательность, предшествующая числу Фибоначчи.

M> reverseInt. result стоит сделать long'ом. И результат — тоже long'ом. Для int'ов вполне предсказуемо переполнение. А вот в long результат влезет. Тип аргумента оставить int'ом (чтобы не возникало вопросов про переполнение long'а).

Если result сделать long'ом, то результат автоматом будет long.

M> findPeriodForFirstTwoPositiveNumbersInARow. А ошибку для случая "числитель больше знаменателя" так и не поправили. (Да, я знаю, я зануда)

Да, проверил 2147483647 / 7, получается: 0.3067833781(428571) вместо 306783378(1428571). Как увеличить длину периода на 1?
Re[9]: Задачи на числа. Решение. Покритикуйте. (часть #1)
От: maxkar  
Дата: 08.04.12 14:55
Оценка:
Здравствуйте, m1st, Вы писали:

M>Здравствуйте, maxkar, Вы писали:


M>> toIntArray. Нормально, такой вариант дальше можно не переделывать. Я бы написал так: int i = 0; for (Integer x : list) { result[i++] = x; }. Такую форму тоже стоит уметь читать. Объективных причин за выбор того или другого варианта не вижу.

M>По toIntArray мы же уже сказали, что "правильно было бы идти по списку итератором и параллельно считать позицию в массиве. Если вдруг в метод будет передан LinkedList, с быстродействием будут проблемы."
В моем варианте тоже итерация по итератору идет, если что .

M>> reverseInt. result стоит сделать long'ом. И результат — тоже long'ом. Для int'ов вполне предсказуемо переполнение. А вот в long результат влезет. Тип аргумента оставить int'ом (чтобы не возникало вопросов про переполнение long'а).

M>Если result сделать long'ом, то результат автоматом будет long.
Еще у функции нужно тип результата сделать long'ом. Я про это писал. Внутри фунции — да, достаточно только у result тип поменять.

M>> findPeriodForFirstTwoPositiveNumbersInARow. А ошибку для случая "числитель больше знаменателя" так и не поправили. (Да, я знаю, я зануда)

M>Да, проверил 2147483647 / 7, получается: 0.3067833781(428571) вместо 306783378(1428571). Как увеличить длину периода на 1?
А в этом примере, похоже, не длину увеличивать нужно, а сдвигать начало на 1. Причем нужно сначала строить весь период и "префикс", а затем уже двигать значения. Я обычно другим алгоритмом период строю (с большим потреблением памяти), но он на некоторых числах вроде бы может давать подобную ошибку (есть ли такие среди интов — не проверял, но теоретически проблема есть).
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.