Find the Oxidation States

Ruby, 288 255 bytes

->m{h={[?O]=>-2,%w[F Cl]=>-1,%w[H Li Na K Rb Cs Fr]=>1,%w[Be Mg Ca Sr Ba Ra]=>2};a=m.scan /([A-Z][a-z]*\d*)/;r=a.flat_map{|(b)|b=~/(\D+)(\d*)/;[a.size==1?0:h[h.keys.find{|v|v.include?$1}]]*($2=='' ? 1:$2.to_i)};r.map{|j|j||-((r-[p]).inject:+)/r.count(p)}}

Try it online!

  • Saved 1 byte thanks to Jenkar
  • Saved 32 more bytes by inlining definitions and removing parentheses

Ungolfed

oxidation_state = -> molecule {
    h = {
        %w[H] => 1,
        %w[O] => -2,
        %w[F] => -1,
        %w[Cl] => -1,
        %w[Li Na K Rb Cs Fr] => 1,
        %w[Be Mg Ca Sr Ba Ra] => 2,
    }
    find_oxidation = -> a {
        k = h.keys.find { |as| as.include?(a) }
        h[k]
    }
    atoms = molecule.scan(/([A-Z][a-z]*\d*)/)
    r = atoms.flat_map { |(a)|
        a.match(/([^\d]+)(\d*)/)
        [atoms.length == 1 ? 0 : find_oxidation[$1]] * ($2=='' ? 1 : $2.to_i)
    }
    r.map { |j|
        sum = r.compact.inject(:+)
        !j ? -sum / r.count(nil) : j
    }
}