Here is one simple way.
def isComposedOf(A, B):
bset = set(B)
for c in A:
if c not in bset:
return False
return True
This algorithm walks each string once, so it runs in O(len(A) + len(B)) time.
When the answer is yes, you cannot do better than len(A) comparisons even in the best case, because no matter what you must check every letter. And in the worst case one of the characters in A is hidden very deep in B. So O(len(A) + len(B)) is optimal, as far as worst-case performance is concerned.
Similarly: when the answer is no, you cannot do better than len(B) comparisons even in the best case; and in the worst case the character that isn't in B is hidden very deep in A. So O(len(A) + len(B)) is again optimal.
You can reduce the constant factor by using a better data structure for bset
.
You can avoid scanning all of B in some (non-worst) cases where the answer is yes by building it lazily, scanning more of B each time you find a character in A that you haven't seen before.