Цикл Do-while продолжает цикл, прежде чем принимать какие-либо дополнительные [дубликаты]

Версия PHP, вдохновленная версией C # Кейта Беллера.

PHP-версия bala не работала для меня, потому что мне не нужно было группировать числа. Мне нужна более простая реализация с одним целевым значением и пулом чисел. Эта функция также сократит любые повторяющиеся записи.

/**
 * Calculates a subset sum: finds out which combinations of numbers
 * from the numbers array can be added together to come to the target
 * number.
 * 
 * Returns an indexed array with arrays of number combinations.
 * 
 * Example: 
 * 
 * <pre>
 * $matches = subset_sum(array(5,10,7,3,20), 25);
 * </pre>
 * 
 * Returns:
 * 
 * <pre>
 * Array
 * (
 *   [0] => Array
 *   (
 *       [0] => 3
 *       [1] => 5
 *       [2] => 7
 *       [3] => 10
 *   )
 *   [1] => Array
 *   (
 *       [0] => 5
 *       [1] => 20
 *   )
 * )
 * </pre>
 * 
 * @param number[] $numbers
 * @param number $target
 * @param array $part
 * @return array[number[]]
 */
function subset_sum($numbers, $target, $part=null)
{
    // we assume that an empty $part variable means this
    // is the top level call.
    $toplevel = false;
    if($part === null) {
        $toplevel = true;
        $part = array();
    }

    $s = 0;
    foreach($part as $x) 
    {
        $s = $s + $x;
    }

    // we have found a match!
    if($s == $target) 
    {
        sort($part); // ensure the numbers are always sorted
        return array(implode('|', $part));
    }

    // gone too far, break off
    if($s >= $target) 
    {
        return null;
    }

    $matches = array();
    $totalNumbers = count($numbers);

    for($i=0; $i < $totalNumbers; $i++) 
    {
        $remaining = array();
        $n = $numbers[$i];

        for($j = $i+1; $j < $totalNumbers; $j++) 
        {
            $remaining[] = $numbers[$j];
        }

        $part_rec = $part;
        $part_rec[] = $n;

        $result = subset_sum($remaining, $target, $part_rec);
        if($result) 
        {
            $matches = array_merge($matches, $result);
        }
    }

    if(!$toplevel) 
    {
        return $matches;
    }

    // this is the top level function call: we have to
    // prepare the final result value by stripping any
    // duplicate results.
    $matches = array_unique($matches);
    $result = array();
    foreach($matches as $entry) 
    {
        $result[] = explode('|', $entry);
    }

    return $result;
}
10
задан Pshemo 20 May 2016 в 12:30
поделиться

4 ответа

В вашем последнем блоке else вам нужно очистить «w» или другой недопустимый ввод от сканера. Вы можете сделать это, вызвав next() на сканере и проигнорировав его возвращаемое значение, чтобы выбросить этот недопустимый вход, следующим образом:

else
{
      System.out.println("You have entered an invalid input. Try again.");
      in.next();
}
15
ответ дан Kaleb Brasee 16 August 2018 в 03:36
поделиться

Переменные флагов слишком подвержены ошибкам для использования. Вместо этого используйте явный контроль цикла с комментариями. Кроме того, hasNextInt() не блокируется. Это неблокирующая проверка, чтобы увидеть, может ли будущий вызов next получить вход без блокировки. Если вы хотите заблокировать, используйте метод nextInt() .

// Scanner that will read the integer
final Scanner in = new Scanner(System.in);
int inputInt;
do {  // Loop until we have correct input
    System.out.print("Specify an integer between 0 and 5: ");
    try {
        inputInt = in.nextInt(); // Blocks for user input
        if (inputInt >= 0 && inputInt <= 5)  { 
            break;    // Got valid input, stop looping
        } else {
            System.out.println("You have not entered a number between 0 and 5. Try again.");
            continue; // restart loop, wrong number
         }
    } catch (final InputMismatchException e) {
        System.out.println("You have entered an invalid input. Try again.");
        in.next();    // discard non-int input
        continue;     // restart loop, didn't get an integer input
    }
} while (true);
1
ответ дан Ben S 16 August 2018 в 03:36
поделиться
  • 1
    есть ли причина, по которой вы делаете финальный сканер? – Tomek 25 November 2009 в 04:19
  • 2
    этот код по-прежнему создает бесконечный цикл – Tomek 25 November 2009 в 04:28
  • 3
    Я делаю это окончательным, так как он не изменится. Из-за этого компилятор может сделать определенные оптимизации. Хорошая привычка объявлять все, что может быть окончательным. Цикл будет нарушен, когда пользователь вводит правильный ввод. Это бесконечно, если пользователь решил сделать его бесконечным. Если вы хотите, я могу отредактировать его так, чтобы он учитывал только определенное количество попыток. – Ben S 25 November 2009 в 04:48
  • 4
    Я имею в виду, если я вхожу в «w», он переходит в бесконечный цикл отображения «Укажите целое число от 0 до 5: вы ввели недопустимый ввод. Повторите попытку. & Quot; & quot; Укажите целое число от 0 до 5: введен неверный вход. Повторите попытку. & Quot; & quot; Укажите целое число от 0 до 5: введен неверный вход. Повторите попытку. & Quot; и так далее. Это произошло только после того, как я добавил in.next () в оператор catch для & quot; чтобы очистить 'w' или другой недопустимый ввод от сканера & quot; как сказал Брасс. Несвязанный, но вы производите код качества – Tomek 25 November 2009 в 04:54
  • 5
    Я исправляю свой пример, чтобы правильно отбрасывать входные данные без ввода. – Ben S 25 November 2009 в 05:05

Проблема заключалась в том, что вы не продвинули Scanner мимо проблематичного ввода. Из документа hasNextInt() :

Возвращает true, если следующий токен в этом входе сканера может быть интерпретирован как значение int в базовом значении по умолчанию, используя nextInt().

Это относится ко всем методам hasNextXXX(): они возвращают true или false, не продвигая Scanner.

Вот фрагмент, иллюстрирующий проблему:

    String input = "1 2 3 oops 4 5 6";
    Scanner sc = new Scanner(input);
    while (sc.hasNext()) {
        if (sc.hasNextInt()) {
            int num = sc.nextInt();
            System.out.println("Got " + num);
        } else {
            System.out.println("int, please!");
            //sc.next(); // uncomment to fix!
        }
    }

Вы обнаружите, что эта программа перейдет в бесконечный цикл, повторно задав int, please!.

Если вы раскомментируйте оператор sc.next(), затем он Scanner пройдет мимо маркера, который не работает hasNextInt(). Затем программа будет печатать:

Got 1
Got 2
Got 3
int, please!
Got 4
Got 5
Got 6

Тот факт, что сбой hasNextXXX() не пропускает вход, преднамерен: он позволяет выполнять дополнительные проверки этого токена, если это необходимо. Вот пример, иллюстрирующий:

    String input = " 1 true foo 2 false bar 3 ";
    Scanner sc = new Scanner(input);
    while (sc.hasNext()) {
        if (sc.hasNextInt()) {
            System.out.println("(int) " + sc.nextInt());
        } else if (sc.hasNextBoolean()) {
            System.out.println("(boolean) " + sc.nextBoolean());
        } else {
            System.out.println(sc.next());
        }
    }

Если вы запустите эту программу, вы получите следующее:

(int) 1
(boolean) true
foo
(int) 2
(boolean) false
bar
(int) 3
9
ответ дан polygenelubricants 16 August 2018 в 03:36
поделиться

Это утверждение Бен С. о неблокирующем вызове ложно:

Также hasNextInt () не блокирует. Это неблокирующая проверка, чтобы увидеть, может ли следующий следующий вызов получить вход без блокировки.

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

Методы next () и hasNext () и их методы примитивного типа (такие как nextInt () и hasNextInt ()) сначала пропускают любой вход, который соответствует шаблону разделителя, а затем пытается вернуть следующий токен. Оба hasNext и следующие методы могут блокировать ожидание дальнейшего ввода. Независимо от того, блокирует ли блок hasNext метод, будет ли заблокирован его связанный следующий метод.

Это, конечно, тонкая точка. Либо говоря: «И hasNext, и следующие методы», либо «Как hasnext (), так и next ()» подразумевали бы, что методы компаньона будут действовать по-разному. Но, видя, что они соответствуют одному и тому же соглашению об именах (и документации, конечно), разумно ожидать, что они будут действовать одинаково, а hasNext () ясно говорит, что он может блокироваться.

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

4
ответ дан Rich Fletcher 16 August 2018 в 03:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: