Java Fish
import java.util.ArrayDeque;
import java.util.Deque;

public class Solution {
    public static int fish(int[] a, int[] b) {
        int size = a.length;
        int dead = 0;
        Deque<Integer> fish = new ArrayDeque<>();

        for (int i = 0; i < size; i++) {
            if (b[i] == 1) {
                fish.push(a[i]);
            } else if (!fish.isEmpty()) {
                while (!fish.isEmpty()) {
                    dead++;
                    if (a[i] > fish.peek()) {
                        fish.pop();
                    } else {
                        break;
                    }
                }
            }
        }

        return size - dead;
    }
}

This uses a stack for downstream fish and resolves fights only when opposite directions meet.

Lisp Fish
(defun fish (a b)
  (let* ((veca (coerce a 'vector))
         (vecb (coerce b 'vector))
         (size (length veca))
         (dead 0)
         (stack '()))
    (dotimes (i size)
      (if (= (aref vecb i) 1)
          (push (aref veca i) stack)
          (when stack
            (loop while stack
                  do (progn
                       (incf dead)
                       (if (> (aref veca i) (first stack))
                           (pop stack)
                           (return)))))))
    (- size dead)))

This uses a stack for downstream fish and resolves fights only when opposite directions meet.

PHP Fish
function fish(array $a, array $b): int
{
    $size  = count($a);
    $dead = 0;
    $fish  = [];
    for ($i = 0; $i < $size; $i++) {
        if ($b[$i] === 1) {
            $fish[] = $a[$i];
        } elseif (isset($fish[0])) {
            while (isset($fish[0])) {
                $dead++;
                if ($a[$i] > end($fish)) {
                    array_pop($fish);
                } else {
                    break;
                }
            }
        }
    }

    return $size - $dead;
}

This uses a stack for downstream fish and resolves fights only when opposite directions meet.

Python Fish
def fish(a: list[int], b: list[int]) -> int:
    size = len(a)
    dead = 0
    downstream: list[int] = []

    for i in range(size):
        if b[i] == 1:
            downstream.append(a[i])
        else:
            while downstream:
                dead += 1
                if a[i] > downstream[-1]:
                    downstream.pop()
                else:
                    break

    return size - dead

This uses a stack for downstream fish and resolves fights only when opposite directions meet.

Rust Fish
fn fish(a: &[i64], b: &[i64]) -> i64 {
    let size = a.len();
    let mut dead = 0i64;
    let mut fish: Vec<i64> = Vec::new();

    for i in 0..size {
        if b[i] == 1 {
            fish.push(a[i]);
        } else if !fish.is_empty() {
            while let Some(&last) = fish.last() {
                dead += 1;
                if a[i] > last {
                    fish.pop();
                } else {
                    break;
                }
            }
        }
    }

    size as i64 - dead
}

This uses a stack for downstream fish and resolves fights only when opposite directions meet.

TypeScript Fish
function fish(a: number[], b: number[]): number {
  const size = a.length;
  let dead = 0;
  const downstream: number[] = [];

  for (let i = 0; i < size; i++) {
    if (b[i] === 1) {
      downstream.push(a[i]);
    } else if (downstream.length > 0) {
      while (downstream.length > 0) {
        dead++;
        if (a[i] > downstream[downstream.length - 1]) {
          downstream.pop();
        } else {
          break;
        }
      }
    }
  }

  return size - dead;
}

This uses a stack for downstream fish and resolves fights only when opposite directions meet.

Bash Flags
flags() {
    local -n _a="$1"
    local _size=${#_a[@]}
    local -a _peak _nxt
    _peak[0]=0
    local _i
    for ((_i = 1; _i < _size; _i++)); do
        local _right=0
        (( _i + 1 < _size )) && _right=${_a[_i+1]}
        if (( _a[_i-1] < _a[_i] && _a[_i] > _right )); then _peak[_i]=1; else _peak[_i]=0; fi
    done
    _nxt[_size-1]=-1
    for ((_i = _size - 2; _i >= 0; _i--)); do
        if (( _peak[_i] )); then _nxt[_i]=$_i; else _nxt[_i]=${_nxt[_i+1]}; fi
    done
    _i=1
    local _result=0
    while (( _i * (_i - 1) <= _size )); do
        local _pos=0 _num=0
        while (( _pos < _size && _num < _i )); do
            _pos=${_nxt[_pos]}
            if (( _pos == -1 )); then break; fi
            ((_num++))
            _pos=$(( _pos + _i ))
        done
        ((_i++))
        (( _num > _result )) && _result=$_num
    done
    echo "$_result"
}

This finds all peaks first, then checks how many flags can be placed while keeping the required distance.

C++ Flags
#include <algorithm>
#include <vector>

int flags(const std::vector<int>& a)
{
    int size = static_cast<int>(a.size());
    if (size == 0) {
        return 0;
    }

    std::vector<bool> peaks(size, false);
    for (int i = 1; i < size; ++i) {
        int nextVal = (i + 1 < size) ? a[i + 1] : 0;
        peaks[i] = a[i - 1] < a[i] && a[i] > nextVal;
    }

    std::vector<int> next(size);
    next[size - 1] = -1;
    for (int i = size - 2; i >= 0; --i) {
        next[i] = peaks[i] ? i : next[i + 1];
    }

    int i = 1;
    int result = 0;
    while (i * (i - 1) <= size) {
        int pos = 0;
        int num = 0;
        while (pos < size && num < i) {
            pos = next[pos];
            if (pos == -1) {
                break;
            }
            ++num;
            pos += i;
        }
        ++i;
        result = std::max(result, num);
    }

    return result;
}

This finds all peaks first, then checks how many flags can be placed while keeping the required distance.

C# Flags
static int Flags(int[] a)
{
    var size = a.Length;
    if (size == 0)
    {
        return 0;
    }

    var peaks = new bool[size];
    var next = new int[size];

    for (int i = 1; i < size; i++)
    {
        var right = i + 1 < size ? a[i + 1] : 0;
        peaks[i] = a[i - 1] < a[i] && a[i] > right;
    }

    next[size - 1] = -1;
    for (int i = size - 2; i >= 0; i--)
    {
        next[i] = peaks[i] ? i : next[i + 1];
    }

    var result = 0;
    for (int i = 1; i * (i - 1) <= size; i++)
    {
        var pos = 0;
        var num = 0;
        while (pos < size && num < i)
        {
            pos = next[pos];
            if (pos == -1)
            {
                break;
            }
            num++;
            pos += i;
        }
        result = Math.Max(result, num);
    }

    return result;
}

This finds all peaks first, then checks how many flags can be placed while keeping the required distance.

Elixir Flags
defmodule Flags do
  def flags(a) do
    size = length(a)
    a_map = a |> Enum.with_index() |> Map.new(fn {v, i} -> {i, v} end)

    peaks =
      for i <- 1..(size - 1), into: %{} do
        prev = Map.get(a_map, i - 1)
        cur = Map.get(a_map, i)
        nxt = Map.get(a_map, i + 1, 0)
        {i, prev < cur and cur > nxt}
      end

    next_map = build_next(size, peaks)

    search(1, size, next_map, 0)
  end

  defp build_next(size, peaks) do
    Enum.reduce((size - 2)..0//-1, %{size - 1 => -1}, fn i, next_map ->
      value = if Map.get(peaks, i, false), do: i, else: Map.get(next_map, i + 1)
      Map.put(next_map, i, value)
    end)
  end

  defp search(i, size, next_map, result) when i * (i - 1) <= size do
    num = walk(0, i, 0, size, next_map)
    search(i + 1, size, next_map, max(result, num))
  end

  defp search(_i, _size, _next_map, result), do: result

  defp walk(pos, step, num, size, next_map) when pos < size and num < step do
    next_pos = Map.get(next_map, pos)

    if next_pos == -1 do
      num
    else
      walk(next_pos + step, step, num + 1, size, next_map)
    end
  end

  defp walk(_pos, _step, num, _size, _next_map), do: num
end

This finds all peaks first, then checks how many flags can be placed while keeping the required distance.