Build a Mass Spectrometer!

Mathematica, 108 bytes

Print@@Join@@({Characters@"CHON",#}ᵀ/.a_/;Last@a<2:>Table@@a)&/@{12011,1008,15999,14007}~FrobeniusSolve~#&

Pure function expecting the input as an integer (1000 times the relative molecular mass); it prints all possible answers to STOUD (and returns an array of Nulls).

The heavy lifting is done by the builtin {12011,1008,15999,14007}~FrobeniusSolve~#, which finds all nonnegative integer combinations of the hardcoded weights that equal the input. {Characters@"CHON",#}ᵀ puts each such combination in a form like {{"C", 0}, {"H", 1}, {"O", 2}, {"N", 3}}. ( is actually the 3-byte private Mathematica character U+F3C7.)

The transformation rule /.a_/;Last@a<2:>Table@@a changes pairs of the form {x, 0} to {} and pairs of the form {x, 1} to {x} (and spits out errors as it tries to apply to the whole expression as well). Then Print@@Join@@ prints the result in the correct form, avoiding the need to cast the integers as strings and concatenate.


Python 2, 242 bytes

b=[12011,1008,15999,14007]
def p(m):
 if m in b:x=[0,]*4;x[b.index(m)]=1;return x
 elif m<1:return 0
 else:
  for i in range(4):
   x=p(m-b[i])
   if x:x[i]+=1;return x
  return 0
print''.join(a+`n`*(n>1)for n,a in zip(p(input()),'CHON')if n)

Try it online!
Recursive function, the input is an integer (1000 times the relative molecular mass) thanks Stephen S for the idea


My machine took 40 segs to turn 672336 into C33H115O3N8 with this modified code. It contains a lookup table for hits/fails to reduce the amount of recursive calls and a optimization to count an element multiple times (if the mass is high enough)