Warm tip: This article is reproduced from stackoverflow.com, please click
algorithm dictionary lookup python

Find the Letters Occurring Odd Number of Times

发布于 2020-04-11 22:36:31

I came across a funny question, I am wondering whether we can solve it.

The Background

In time complexity O(n), can we find the letters occurring odd number of times, Output a list contain letters and keep the order of letters consistent with original string.

In case of multiple options to choose from, take the last occurence as the unpaired character.

Here is an example:

# note we should keep the order of letters
findodd('Hello World')   ==  ["H", "e", " ", "W", "r", "l", "d"] # it is good
findodd('Hello World')   ==  ["H", "l", " ", "W", "r", "e", "d"] # it is wrong

My attempt

def findodd(s):
    hash_map = {}

    # This step is a bit strange. I will show an example:
    # If I have a string 'abc', I will convert string to list = ['a','b','c']. 
    # Just because we can not use dict.get(a) to lookup dict. However, dict.get('a') works well.
    s = list(s)

    res = []
    for i in range(len(s)):
        if hash_map.get(s[i]) == 1:
            hash_map[s[i]] = 0
            res.remove(s[i])
        else:
            hash_map[s[i]] = 1
            res.append(s[i])

    return res
findodd('Hello World')

Out:

["H", "e", " ", "W", "r", "l", "d"] 

However, since I use list.remove, the time complexity is above O(n) in my solution.

My Question:

  1. Can anyone give some advice about O(n) solution?
  2. If I don't wanna use s = list(s), how to iterate over a string 'abc' to lookup the value of key = 'a' in a dict? dict.get('a') works but dict.get(a) won't work.

Source

Here are 2 webpage I watched, however they did not take the order of letter into account and did not provide O(n) solution.

  1. find even time number, stack overflow
  2. find odd time number, geeks for geeks
Questioner
Travis
Viewed
22
Patrick Artner 2020-02-02 23:31

Python 3.7 up has dictionary keys input ordered. Use collection.OrderedDict for lower python versions.

Go through your word, add letter do dict if not in, else delete key from dict.

Solution is the dict.keys() collection:

t = "Hello World"

d = {}
for c in t:
    if c in d:       # even time occurences: delete key
        del d[c]
    else:
        d[c] = None  # odd time occurence: add key

print(d.keys()) 

Output:

dict_keys(['H', 'e', ' ', 'W', 'r', 'l', 'd'])

Its O(n) because you touch each letter in your input exactly once - lookup into dict is O(1).

There is some overhead by key adding/deleting. If that bothers you, use a counter instead and filter the key() collection for those that are odd - this will make it O(2*n) - 2 is constant so still O(n).