refer to: AlgoExpert
Input: string, substring
Output: add underscore at the start and the end of substring found in the string. if overlap or sit side by side, only add underscore at the leftmost and the rightmost positions
Analysis:
step 1
step 2
step 3
time and space complexity
string.find: O(m+n)
traverse length n
upperbound: n(m+n)
def underscorifySubstring(string, substring): locations = collapse(getLocations(string, substring)) return underscorify(string, locations) def getLocations(string, substring): locations = [] startIdx = 0; while startIdx < len(string): nextIdx = string.find(substring, startIdx); if nextIdx != -1: #if substring is found, add the start index and the end index locations.append([nextIdx, nextIdx + len(substring)]) startIdx = nextIdx + 1 #continue to traverse the next one else: break # if not found, break return locations def collapse(locations): # address the special cases: 1. overlap 2. sit side by side if not len(locations): # if the locations array is empty, return [] return locations newLocations = [locations[0]] # newLocations starts from the first element in the 2d array previous = newLocations[0] #initiate the previous(the first position) for i in range(1, len(locations)): # check the following positions current = locations[i] #current defines the following position, from the second array in locations if current[0] <= previous[1]: #[1,3] [2,4] current[0] = 2, previous[1] = 3, overlapping previous[1] = current[1] #[1,3]->[1,4] # update previous else: # no overlapping or sit side by side newLocations.append(current) # append the whole currect array previous = current # update the previous to current return newLocations def underscorify(string, locations): # add underscore locationsIdx = 0 stringIdx = 0 inBetweenUnderscores = False finalChars = [] i = 0 while stringIdx < len(string) and locationsIdx < len(locations): # while we are in the middle od string and the locations array if stringIdx == locations[locationsIdx][i]: finalChars.append("_") inBetweenUnderscores = not inBetweenUnderscores # finished adding _ for one array if not inBetweenUnderscores: #false(initial)-> true -> false(one pass finished, move to another) -> true->false locationsIdx += 1 # go to the next array i = 0 if i == 1 else 1 # if i =1, ->i = 0; if i = 0, ->i = 1, i have two potions: 0 or 1 finalChars.append(string[stringIdx]) # if stringIdx != locations[locationsIdx][i], append the substring directly stringIdx += 1 if locationsIdx < len(locations): # finished traversing the string finalChars.append("_") elif stringIdx < len(string): # finished traversing the locations finalChars.append(string[stringIdx:]) return "".join(finalChars)