What is the time complexity of below string matching program? - python

t= total string and s= test string if its present in t
t=input() #main string
s=input() #check for substring
print(any(s==t[i:i+len(s)] for i in range(len(t)-len(s))))
the give time complexity is O( (s)(t-s) ) but i did't understand how

Your complexity is more O(len(s).(len(t)-len(s))) than O((s)(t-s)) because
The loop size is len(t)-len(s) because of the range(len(t)-len(s))
Then each round loop does s == t[i:i+len(s)] which is a string comparison where both part have a length of len(s), so len(s) char to compare
Multiply them : len(s).(len(t)-len(s))

Related

Time Complexity for LeetCode 3. Longest Substring Without Repeating Characters

Problem: Given a string s, find the length of the longest substring
without repeating characters.
Example: Input: s = "abcabcbb" Output: 3 Explanation: The answer is
"abc", with the length of 3.
My solution:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
seen = set()
l = r = curr_len = max_len = 0
n = len(s)
while l < n:
if r < n and s[r] not in seen:
seen.add(s[r])
curr_len += 1
max_len = max(curr_len, max_len)
r += 1
else:
l += 1
r = l
curr_len = 0
seen.clear()
return max_len
I know this is not an efficient solution, but I am having trouble figuring out its time complexity.
I visit every character in the string but, for each one of them, the window expands until it finds a repeated char. So every char ends up being visited multiple times, but not sure if enough times to justify an O(n2) time complexity and, obviously, it's way worse than O(n).
You could claim the algorithm to be O(n) if you know the size of the character set your input can be composed of, because the length your window can expand is limited by the number of different characters you could pass over before encountering a duplicate, and this is capped by the size of the character set you're working with, which itself is some constant independent of the length of the string. For example, if you are only working with lower case alphabetic characters, the algorithm is O(26n) = O(n).
To be more exact you could say that it runs in O(n*(min(m,n)) where n is the length of the string and m is the number of characters in the alphabet of the string. The reason for the min is that even if you're somehow working with an alphabet of unlimited unique characters, at worst you're doing a double for loop to the end of the string. That means however that if the number of possible characters you can encounter in the string exceeds the string's length you have a worst case O(n^2) performance (which occurs when every character of the string is unique).

How can I make this 2 strings matching algorithm more efficient?

So I am working on this exercise on code wars and my code does what it is supposed to do, but it needs to be more efficient and I don't know what else I can do. Below are the exercise and code I wrote.
Complete the function scramble(str1, str2) that returns true if a portion of str1 characters can be rearranged to match str2, otherwise returns false.
Notes:
Only lower case letters will be used (a-z). No punctuation or digits will be included.
Performance needs to be considered
Input strings s1 and s2 are null terminated.
Examples
scramble('rkqodlw', 'world') ==> True
scramble('cedewaraaossoqqyt', 'codewars') ==> True
scramble('katas', 'steak') ==> False
def scramble(s1, s2):
#initiate variables
i,j,count =0,0,0
#sorting our 2 strings
s1, s2="".join(sorted(s1)),"".join(sorted(s2))
#for loop to go over each character in the str we want to match, s2
for j in range(len(s2)):
#while loop to go over s1 to match characters to s2 char
i=0
while i<len(s1):
#when 2 chars match, count increases by 1, i increases to exit while loop
#s1 sliced for increasing efficiency in the next loop
if s1[i]==s2[j]:
count+=1
x=i
i=len(s1)
s1=s1[x+1:]
#if character larger in s1, no need to go through the whole string
#therefore, exits while loop and slices
elif s1[i]>s2[j]:
x=i
i=len(s1)
s1=s1[x+1:]
#increases iterator
else: i+=1
#return statement, if count equals length of s2 then it must be true
if len(s2)==count: return True
else: return False
Side question: is the time complexity for this code O(n^2)?
You could make use of the fact that an exception is thrown if you try to find and pop an element from a list which does not exist:
def scramble(s1,s2):
l1 = list(s1)
for c in s2:
try:
i = l1.index(c)
l1.pop(i)
except:
return False
return True
So here you are sorting both strings which gives O(n log n + m log m) complexity for n and m being sizes of s1 and s2. Then you are running two nested loops to check for characters from s2 to exist in s1 and then rewriting s1 if the character in question does exist. This is actually super inefficient, and it indeed gives you O(nm) complexity for that part with quite a big constant on top (since you are rewriting a string over and over).
Instead you can just count occurrences of each character in each string to see if you have enough characters to compose s2 from s1. That would give you linear time plus the size of an alphabet, which is a small constant (26 in your case since only lower-case alphabetic characters are allowed according to the challenge prompt).

What is the time and space complexity of the count string function

def count(substring, string):
"""
>>> count("bc","abcabcabc")
3
"""
counter = 0
for i in range(len(string) - len(substring) + 1):
counter += string.startswith(substring, i)
return counter
This is a function to count the number of recurrence of a substring in the base string. I think the time complexity is O(n) since I only iterate the string once. I think the space complexity is O(n) as well because I increment the counter in the loop N times. Can someone tell me if I am right or wrong?
The time complexity is O(nm) where n=len(s) and m=len(t) for the reason you provide, but incrementing counter doesn't cause it take up more space, so the space complexity of this function is O(1). No matter how long the input string is, you still only store a single variable, count.
[Edited to correct egregious error pointed out by poster]

Number of Palindromic Slices in a string with O(N) complexity

def solution(S):
total = 0
i = 1
while i <= len(S):
for j in range(0, len(S) - i + 1):
if is_p(S[ j: j + i]):
total += 1
i += 1
return total
def is_p(S):
if len(S) == 1:
return False
elif S == S[::-1]:
return True
else:
return False
I am writing a function to count the number of Palindromic Slices(with length bigger than 1) in a string. The above code is in poor time complexity. Can someone help me to improve it and make it O(N) complexity?
Edit: It is not duplicate since the other question is about finding the longest Palindromic Slices
Apply Manacher's Algorithm, also described by the multiple answers to this question.
That gives you the length of the longest palindrome centered at every location (centered at a character for odd-length, or centered between characters for even-length). You can use this to easily calculate the number of palindromes. Note that every palindrome must be centered somewhere, so it must be a substring (or equal to) the longest palindrome centered there.
So consider the string ababcdcbaa. By Manacher's Algorithm, you know that the maximal length palindrome centered at the d has length 7: abcdcba. By the properties of palindromes, you immediately know that bcdcb and cdc and d are also palindromes centered at d. In fact there are floor((k+1)/2) palindromes centered at a location, if you know that the longest palindrome centered there has length k.
So you sum the results of Manacher's Algorithm to get your count of all palindromes. If you want to only count palindromes of length > 1, you just need to subtract the number of length-1 palindromes, which is just n, the length of your string.
This can be done in linear time using suffix trees:
1) For constant sized alphabet we can build suffix trees using Ukkonen's Algorithm in O(n).
2) For given string S, build a generalized suffix tree of S#S' where S' is reverse of string S and # is delimiting character.
3) Now in this suffix tree, for every suffix i in S, look for lowest common ancestor of (2n-i+1) suffix is S'.
4) count for all such suffixes in the tree to get total count of all palindromes.

Find the longest substring with contiguous characters, where the string may be jumbled

Given a string, find the longest substring whose characters are contiguous (i.e. they are consecutive letters) but possibly jumbled (i.e. out of order). For example:
Input : "owadcbjkl"
Output: "adcb"
We consider adcb as contiguous as it forms abcd.
(This is an interview question.)
I have an idea of running a while loop with 2 conditions, one that checks for continuous characters using Python's ord and another condition to find the minimum and maximum and check if all the following characters fall in this range.
Is there any way this problem could be solved with low running time complexity? The best I can achieve is O(N^2) where N is the length of the input string and ord() seems to be a slow operation.
If the substring is defined as ''.join(sorted(substr)) in alphabet then:
there is no duplicates in the substring and therefore the size of
the longest substring is less than (or equal to) the size of the alphabet
(ord(max(substr)) - ord(min(substr)) + 1) == len(substr), where
ord() returns position in the alphabet (+/- constant) (builtin
ord() can be used for lowercase ascii letters)
Here's O(n*m*m)-time, O(m)-space solution, where n is len(input_string) and m is len(alphabet):
from itertools import count
def longest_substr(input_string):
maxsubstr = input_string[0:0] # empty slice (to accept subclasses of str)
for start in range(len(input_string)): # O(n)
for end in count(start + len(maxsubstr) + 1): # O(m)
substr = input_string[start:end] # O(m)
if len(set(substr)) != (end - start): # found duplicates or EOS
break
if (ord(max(substr)) - ord(min(substr)) + 1) == len(substr):
maxsubstr = substr
return maxsubstr
Example:
print(longest_substr("owadcbjkl"))
# -> adcb

Categories