2

Write a function repfree(s) that takes as input a string s and checks whether any character appears more than once. The function should return True if there are no repetitions and False otherwise.

I have tried this but I don't feel this is an efficient way of solving it. Can you suggest an efficient code for this, thanks?

def repfree(s):
    newlist = []
    for i in range(0, len(s)):
        newlist.append(s[i])
    newlist2 = set(newlist)
    if len(newlist) == len(newlist2):
        print("True")
   else:
        print("False")
Guy
  • 46,488
  • 10
  • 44
  • 88
Praveen KUMAR
  • 61
  • 2
  • 9
  • 1
    now we just need someone pointing out you could use `return collections.Counter(s).most_common(1)[0][1]==1` ... and some esoteric numpy and pandas solutions :bangs head against laptop: – Patrick Artner Feb 11 '20 at 07:42
  • 1
    @PatrickArtner - the function is only supposed to print the result, not return it, otherwise that would have been great! :provides a pillow: – Sayse Feb 11 '20 at 07:48
  • 1
    `print("True" if collections.Counter(s).most_common(1)[0][1] else "False")` terniary ftw. :goes to sleep: – Patrick Artner Feb 11 '20 at 07:50
  • Possible duplicate of [checking-if-all-elements-in-a-list-are-unique](https://stackoverflow.com/questions/5278122/checking-if-all-elements-in-a-list-are-unique) - lists and strings are both iterables, solution for list will work for this as well. – Patrick Artner Feb 11 '20 at 07:55
  • @PatrickArtner Solutions for lists will work here, but problems on strings are generally not duplicates of problems on lists because (1) strings have different methods and behaviour for e.g. the `in` operator, and (2) strings have finite alphabets, so algorithms can exploit this (see e.g. the first example in the accepted answer). – kaya3 Feb 11 '20 at 08:28
  • @PatrickArtner Both of your attempts fail (crash!) for `s = ''`. – Kelly Bundy Feb 11 '20 at 20:39
  • @Heap yepp - they do. So what? If my comemnts were a full fledged answer (which they are not) you would do `if not s: print("True"); return;` first to handle this important edge case. – Patrick Artner Feb 12 '20 at 08:27

8 Answers8

3

One easy way to meet this requirement is to use regular expressions. You may not be allowed to use them, but if you can, then consider this:

def repfree(s):
    if re.search(r'^.*(.).*\1.*$', s):
        print("True")
    else:
        print("False")
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • Despite the regex having to backtrack to match `\1`, this solution is actually linear time, because the alphabet has a fixed size so the number of backtracks is at most a constant. Nice one! – kaya3 Feb 11 '20 at 07:45
1

Believe it or not, this problem can be solved in O(1) time, because every sufficiently large string contains at least one duplicate character. There are only a finite number of different Unicode characters, after all, so a string cannot be arbitrarily long while also using each Unicode character at most once.

For example, if you happen to know that your strings are formed of only lowercase letters, you can do this:

def has_repeated_char(s):
    return len(s) > 26 or len(s) != len(set(s))

Otherwise you can replace the 26 with whatever number of characters your string could possibly contain; e.g. 62 for upper- and lowercase letters and digits.

As of February 2020, the whole of Unicode has 137,994 distinct characters (Wikipedia), so if your string length is 150,000 then you can return True without searching.

kaya3
  • 47,440
  • 4
  • 68
  • 97
  • What about `s = ''.join(map(chr, range(1_114_112)))`? – Kelly Bundy Feb 11 '20 at 18:50
  • @HeapOverflow Most of those aren't "characters", per the Unicode spec. – kaya3 Feb 12 '20 at 01:06
  • I was hoping you'd say that :-). Then I can add non-characters to make the string arbitrarily long while not having repeated characters, invalidating your method :-P – Kelly Bundy Feb 12 '20 at 01:09
  • I think the problem requirements ought to be interpreted as taking a string which is a sequence of characters, as it's rather more complicated if you have to filter out non-characters before checking for duplicates (none of the other answers do this either). The way I see it, using a string containing non-characters is analogous to doing binary search on an unordered array; though I get that some people would disagree with me on that. – kaya3 Feb 12 '20 at 01:13
  • Where do the Python docs say that? I see *"Textual data in Python is handled with `str` objects, or strings. Strings are immutable sequences of Unicode **code points**"* [here](https://docs.python.org/3.8/library/stdtypes.html#text-sequence-type-str) (which I think is *the* place to look for it). – Kelly Bundy Feb 12 '20 at 01:18
  • Yep, I got that wrong; was going from memory (the docs say "character" a lot) and on mobile, but I checked after posting and edited. It doesn't change my opinion; if we take it literally then all the answers on this page (and probably all the submissions by everyone attempting this exercise) fail on a string containing two identical non-characters. – kaya3 Feb 12 '20 at 01:25
  • 1
    Yeah, I agree it would be annoying if we had to distinguish, and most likely the strings will only contain characters, maybe even just ASCII or a-z. – Kelly Bundy Feb 12 '20 at 02:13
0

You could do this way:

Method 1:

def repfree(s):
  if len(set(s)) == len(s):
    return True
  return False

Method 2:

def repfree(s):

  return len(set(s)) == len(s)

Why set?

set will return the list of all unique characters in the string in sorted order

Example :

set('shubham')

Output:

{'a', 'b', 'h', 'm', 's', 'u'}

So,if a character in a string appears more than once,it will not be equal to the length of string itself.

Shubham Shaswat
  • 1,250
  • 9
  • 14
  • Just `return len(set(s)) == len(s)`; no need to consume the boolean result in an `if` statement, just return it directly. – kaya3 Feb 11 '20 at 07:37
  • @kaya3 yes you right,I just want the user understand what is going on,it is a trivial question,I think I should edit my answer as it may appear to be duplicate – Shubham Shaswat Feb 11 '20 at 07:40
0

You could split the string characters to a set and compare the length

def repfree(s):
    se = set(string)
    print(len(se) == len(s))
Guy
  • 46,488
  • 10
  • 44
  • 88
0

You can make your approach more efficient by removing the for loop.

len(s) == len(set(s))

Otherwise, try using any

any(s.count(c) > 1 for c in s)
Sayse
  • 42,633
  • 14
  • 77
  • 146
  • The solution using `any` is O(n^2), because `count` is an O(n) operation and you're doing it O(n) times. – kaya3 Feb 11 '20 at 07:38
  • @kaya3 - I didn't see much wrong with the OPs original approach, `any` was just an alternative that may have been faster for short strings that contain more than one duplicate letter but I doubt it – Sayse Feb 11 '20 at 07:40
  • @kaya3 With your finite alphabet argument, the `any` solution is O(n) as well, right? – Kelly Bundy Feb 12 '20 at 14:45
  • Yes, I suppose so. – kaya3 Feb 12 '20 at 15:03
0

Try

chars = 'abcdefghijklmnopqrstuvwxyz'
def repfree(s):
    for char in chars:
        count = s.count(char)
        if count > 1:
            return False
    return True

But, this is a long way as it scans the list 26 times. A much better and Pythonic way would be

import collections
def repfree(s):
    results = collections.Counter(s)
    for i in results:
        if results[i] > 1:
            return False
    return True

Here, results is a dictionary that contains all the characters of s as key, and their respective frequency as value. Further, it is checked if any value is greater than 1, repetition has occurred.

Swati Srivastava
  • 1,102
  • 1
  • 12
  • 18
  • 1
    @PatrickArtner That's what I have mentioned in my answer. The first is not a very good approach. It can be used for smaller strings only, or where the repetitions are less. – Swati Srivastava Feb 11 '20 at 07:59
0
def repfree(str):
l=list(str)
for i in range(len(l)):
    check=str.count(l[i])
    if check>1:
        flag=1
    else:
        flag=0
if(flag==1):
    return False
else:
    return True
  • Hello and welcome to StackOverflow! Although your answer might give the answer to the question, it lacks any kind of context to help other users understand *how* it helps solve the problem. You could for instance elaborate on the reason why your code is efficient. – Alvae Feb 13 '20 at 15:53
-2

def matched(s): stack = [] for char in s: if char == '(': stack.append(char) elif char == ')': if not stack: return False stack.pop() return not stack

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 09 '23 at 15:40