Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions day29/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
question of the day: https://codefights.com/interview/vzzkv5NHFMELWSwAS

Given an integer len, count the number of different good strings that
have a length of exactly len. A good string is a string for which the
following conditions are true:

1. A good string contains only lowercase English letters.
2. Each character in a good string is unique.
3. Exactly one character in a good string is lexicographically greater
than the character that precedes it.

**Example**

For `len = 2`, the output should be
`goodStringsCount(len) = 325`.

If the first symbol is 'a', there are 25 possible good strings: "ab", "ac", ...
If the first symbol is 'b', there are 24 possible good strings: "bc", "bd", ...

If the first symbol is 'z', there are 0 possible good strings because there is
no character that is lexicographically greater.

There are 25 + 24 + 23 + ... + 0 = 325 good strings that have a length of 2.

For len = 1, the output should be goodStringsCount(len) = 0.

The 3rd rule for good strings can't be true if there is only one character in the string.

## Ideas

Brute force: enumerate all possible permutations and check whether the
constraints are satisfied. In this solution, 'aa', 'ab', etc. will be checked,
but so will 'za', 'zb', 'zc', ..., 'zz', etc. which is a lot of wasted
work. It also runs in `O(26**len)` which is exponential time which is horrible.

How do we save work? Let's look at the constraints and factor them into the
enumeration of permutations. We should never use upper case letters. We should
not use duplicate letters, i.e. if we've placed the letter 'a' as we're
constructing a good string, we should not place another letter 'a' in the same
good string. And likewise, we shouldn't place letters into the good string
if they are lexicographically less than the characters that precede it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you misread the 3rd rule. note that it says "exactly one" and not "every"

len = 2
'ab', 'ac', 'ad', 'ae', ... 'az' -> 25 possible strings

len = 3
'abc', 'abd', 'abe', ... 'abz' -> 24 possible strings
'acd', 'ace', ... , 'acz' -> 23 possible strings
...
'ayz' -> 1 possible strings
'az' -> 0 possible strings

'bcd' -> 23
'bde' -> 22

0 1 -> 25
1 2 -> 24
2 3 -> 23
3 4 -> 22
...
25 26 -> 1

0 1 2 -> 24
1 2 3 -> 23
2 3 4 -> 22
3 4 5 -> 21
..
23 24 25 -> 1
24 25 _ -> 0

## Code

[Python](./goodStringscount.py)

## Follow up

I cheated today: http://blog.codefights.com/goodstringscount-solution/

Be sure to read this and understand the combinatorics theory! I think it'd be
a great exercise to break down a couple more combination questions. A lot of
companies seem to ask these kinds of questions, and it's a really useful math
skill for calculating possibilities / probabilities / counting.


18 changes: 18 additions & 0 deletions day29/goodStringsCount.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from math import factorial

def nChooseR(n, r):
return factorial(n) / (factorial(n-r) * factorial(r))

def goodStringsCount(n):
return nChooseR(26, n) * (2**n - n - 1)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this solution works but it doesn't follow from the examples in your ideas section


def testGoodStringsCount():
assert goodStringsCount(1) == 0
assert goodStringsCount(2) == 325
assert goodStringsCount(3) == 10400

def main():
testGoodStringsCount()

if __name__ == "__main__":
main()