It's probably not as fast as the mathematical solutions, but I think that it is easier to understand. It is still O(n) (except for the final ordering which could be easily avoided) and is fast enough to pass OJ. Plus it can be easily adapted to properly handle invalid strings by checking if anything remains at the end in S.

```
def originalDigits(self, s):
numbers = [('zero',0),('two',2),('eight',8),('four',4),('one',1),('three',3),('five',5),('six',6),('seven',7),('nine',9)]
res, S = [], collections.Counter(s)
for n in numbers:
c = collections.Counter(n[0])
while c&S == c:
res.append(n[1])
S -= c
return ''.join([str(i) for i in sorted(res)])
```