2

Problem: Longest Substring Without Repeating Characters.

I have this solution. But I do not have much of theoretical knowledge about DSA. Trying to understand which algorithm it comes under and will it be efficient than 'Sliding Window' approach. Per my understanding the time complexity is o(n). What will be the space complexity? Any help/guidance will be appreciated. Thanks!

public class Solution {
    public int LengthOfLongestSubstring(string s) {
        
        List<char> list = new List<char>();
        int output = 0;
        
        foreach(char c in s)
        {
            if(list.Contains(c))
            {
                if(list.Count > output)
                    output=list.Count;
                int index = list.IndexOf(c);
                list.RemoveRange(0,index+1);
                list.Add(c);
            }
            else
            {
                list.Add(c);
            }
        }
        
        return list.Count > output ? list.Count : output;
    }
}

  • And DSA is?. I'm guessing not the _Democratic Socialists of America_ (likeliest on the internet) or the California _Division of the State Architect_ or the _Direct Selling Association_ or any of the other things the internet turned up – Flydog57 Sep 17 '22 at 18:12
  • sorry. I should have been more specific here. I meant Data Structure and Algorithm here. – shantanu ghosh Sep 17 '22 at 18:15
  • And, is _repeating characters_ like the two `e`s in _repeating_ or like the `s`s and `p`s in _Mississippi_ – Flydog57 Sep 17 '22 at 18:15
  • Like the 's's and 'p's in Mississippi. Input : "abcabcbb", Answer: abc/cab, Output: 3. Input: "dvdf", Answer: vdf, Output:3. Input:"pwwkew", Answer:wke/kew, Output: 3. Input: "bbbb" Answer: b, output :1 . Input: "Mississippi", Answer: mis/sip ,Output: 3 – shantanu ghosh Sep 17 '22 at 18:18
  • 1
    Read your code. The only storage you use is the list. It will never be longer than `s.Length`. By the way, you might consider creating the list to be `s.Length` when you construct it `var list = new List(s.Length);`. That way, the list doesn't need to expand as you add things to it. It may seem wasteful in space, but it churns out less garbage (making the GC's life easier) and it will be quickly cleaned up at the next Gen0 collection – Flydog57 Sep 17 '22 at 18:24
  • 2
    You need as much storage as your alphabet and that is usually constant, so O(1) storage. But I think your implementation is only O(n) because of that reason, you should use a hash set instead of a list to get real O(n) independently of the alphabeth size. The contains on list is O(n). Not O(1). – maraca Sep 17 '22 at 18:36

1 Answers1

0

Memory complexity of you solution is O(a) (I'm not counting in the s string size - in ideal situation in could be a generator) and pessimistic time complexity is O(a*n) where:

n - length of the s input string

a - alphabet size |A|

For s repeating whole alphabet multiple times:

s = "abcd...xyzabcd...xyzabcd...xyz"

After first a iterations the list size is a and it contains every letter.

Then for each consecutive iteration we remove first element, which means all elements have to shift - the cost of this operation is a-1.

We end up with O((n-a) * (a-1)) = O(a * n).

The solution could be to use LinkedList, but as @maraca mentioned in the comment - Contains pessimistic complexity is also O(L) where L is list length and we again get O(a * n) for s that rarely empties the list.

How to get real O(n)?

As comment suggest use HashMap to store on what index the element was last seen. Update the indexes as you process the array. Calculate the output as difference between current position and last seen index (if it's less than current length).

You could also say, that for a-z alphabet the constant of hashing algorithm is bigger than a (24) and either way it's O(n). Requires testing times for real world examples :D

yjay
  • 942
  • 4
  • 11