solutions

forward iteration (list of lists)

We go through each replacement, making sure not to directly change the value of s while we’re iterating, so we don’t mess up indexing for future changes.

Instead, we use a list to store replaced values, making sure to clear out any value that have been replaced.

def findReplaceString(self, s: str, indices: List[int], sources: List[str], targets: List[str]) -> str:
	modified = list(s)
 
	for idx, source, target in zip(indices, sources, targets):
		if not s[idx:].startswith(source):
			continue
 
		modified[idx] = target
		for i in range(idx+1, idx+len(source)):
			modified[i] = ""
 
	return "".join(modified)

reverse-iteration by index

If we first check validity of replacements, and then iterate backwards through the queries (by index), we can be sure that the changes we make to s don’t affect indexing for replacements as we move left.

def findReplaceString(self, s: str, indices: List[int], sources: List[str], targets: List[str]) -> str:
	ans = s
	combined = [
		(idx, source, target) for idx, source, target in zip(
			indices, sources, targets
		)
	]
	combined.sort(key=lambda x: -x[0])
	  
	# clear invalid replacements
	for i, (idx, source, target) in enumerate(combined):
		if ans[idx:idx+len(source)] != source:
			combined[i] = (None, None, None)
	  
	for idx, source, target in combined:
		if idx == None:
			continue
		ans = ans[:idx] + target + ans[idx+len(source):]
	return ans