替换字符串中的括号内容

标签: 数组 哈希表 字符串

难度: Medium

给你一个字符串 s ,它包含一些括号对,每个括号中包含一个 非空 的键。

  • 比方说,字符串 "(name)is(age)yearsold" 中,有 两个 括号对,分别包含键 "name" 和 "age" 。

你知道许多键对应的值,这些关系由二维字符串数组 knowledge 表示,其中 knowledge[i] = [keyi, valuei] ,表示键 keyi 对应的值为 valuei 

你需要替换 所有 的括号对。当你替换一个括号对,且它包含的键为 keyi 时,你需要:

  • 将 keyi 和括号用对应的值 valuei 替换。
  • 如果从 knowledge 中无法得知某个键对应的值,你需要将 keyi 和括号用问号 "?" 替换(不需要引号)。

knowledge 中每个键最多只会出现一次。s 中不会有嵌套的括号。

请你返回替换 所有 括号对后的结果字符串。

示例 1:

输入:s = "(name)is(age)yearsold", knowledge = [["name","bob"],["age","two"]]
输出:"bobistwoyearsold"
解释:
键 "name" 对应的值为 "bob" ,所以将 "(name)" 替换为 "bob" 。
键 "age" 对应的值为 "two" ,所以将 "(age)" 替换为 "two" 。

示例 2:

输入:s = "hi(name)", knowledge = [["a","b"]]
输出:"hi?"
解释:由于不知道键 "name" 对应的值,所以用 "?" 替换 "(name)" 。

示例 3:

输入:s = "(a)(a)(a)aaa", knowledge = [["a","yes"]]
输出:"yesyesyesaaa"
解释:相同的键在 s 中可能会出现多次。
键 "a" 对应的值为 "yes" ,所以将所有的 "(a)" 替换为 "yes" 。
注意,不在括号里的 "a" 不需要被替换。

提示:

  • 1 <= s.length <= 105
  • 0 <= knowledge.length <= 105
  • knowledge[i].length == 2
  • 1 <= keyi.length, valuei.length <= 10
  • s 只包含小写英文字母和圆括号 '(' 和 ')' 。
  • s 中每一个左圆括号 '(' 都有对应的右圆括号 ')' 。
  • s 中每对括号内的键都不会为空。
  • s 中不会有嵌套括号对。
  • keyi 和 valuei 只包含小写英文字母。
  • knowledge 中的 keyi 不会重复。

Submission

运行时间: 85 ms

内存: 49.2 MB

from typing import List

class Solution:
    def evaluate(self, s: str, knowledge: List[List[str]]) -> str:
        # 构建键值对字典
        knowledge_dict = {key: value for key, value in knowledge}
        
        result = []
        i = 0
        while i < len(s):
            if s[i] == '(':
                j = i + 1
                while s[j] != ')':
                    j += 1
                # 提取括号内的键
                key = s[i+1:j]
                # 检查键是否在知识中存在
                if key in knowledge_dict:
                    result.append(knowledge_dict[key])
                else:
                    result.append('?')
                # 更新索引位置
                i = j + 1
            else:
                # 非括号字符直接添加到结果中
                result.append(s[i])
                i += 1
        
        return ''.join(result)

solution = Solution()
s = "(name)is(age)yearsold"
knowledge = [["name", "bob"], ["age", "two"]]
print(solution.evaluate(s, knowledge))  # 输出: "bobistwoyearsold"

Explain

该题解采用了 hash map 和线性扫描的方法来解决问题。首先,使用一个字典(knowledge_dict)来存储知识库中的键值对,以便快速查找。接着,通过遍历字符串s,每当遇到'('时,就开始搜索对应的')',提取括号内的字符串作为键,并查询字典中是否有对应的值。如果有,就将这个值添加到结果列表中;如果没有,就添加一个'?'。这个过程中,非括号内容直接添加到结果列表。最后,使用join方法将列表中的内容合并成一个字符串,这就是最终的结果。

时间复杂度: O(N)

空间复杂度: O(N)

from typing import List

class Solution:
    def evaluate(self, s: str, knowledge: List[List[str]]) -> str:
        # 构建键值对字典
        knowledge_dict = {key: value for key, value in knowledge}
        
        result = []  # 用于存储最终结果的字符列表
        i = 0  # 初始索引
        while i < len(s):
            if s[i] == '(':
                j = i + 1  # 寻找配对的 ')'
                while s[j] != ')':
                    j += 1
                # 提取括号内的键
                key = s[i+1:j]
                # 检查键是否在字典中存在
                if key in knowledge_dict:
                    result.append(knowledge_dict[key])
                else:
                    result.append('?')  # 未找到对应键时添加 '?'
                # 更新索引位置到 ')' 后一个字符
                i = j + 1
            else:
                # 非括号字符直接添加到结果中
                result.append(s[i])
                i += 1
        
        return ''.join(result)  # 将结果列表转换为字符串

solution = Solution()
print(solution.evaluate('(name)is(age)yearsold', [['name', 'bob'], ['age', 'two']]))  # 输出: 'bobistwoyearsold'

Explore

在处理字符串时,可以通过维护一个索引变量来确保每个 '(' 找到匹配的 ')'。具体方法是,每当遇到一个 '(',就从该位置开始向后搜索,每次遇到 '(' 就增加一个计数,每次遇到 ')' 就减少一个计数,当计数归零时,当前的 ')' 就是匹配的括号。这样可以处理嵌套括号的情况,确保每个 '(' 都能找到正确的 ')'。

当前的算法在处理嵌套括号时可能会遇到问题。算法是寻找第一个未匹配的 ')' 来与 '(' 配对,这在没有嵌套的情况下是有效的。但在嵌套的情况下,如 '(name(is(age)))',算法会将第一个 '(' 与第一个 ')' 匹配,导致无法正确处理嵌套结构。需要改进算法以正确处理嵌套括号,例如使用栈来跟踪括号的匹配。

选择使用列表来存储结果而不是直接修改字符串,是因为字符串在Python中是不可变的数据类型,每次修改字符串都会生成一个新的字符串对象,这样会导致额外的内存分配和释放,效率较低。相反,列表是可变的,可以在原地修改,添加元素的操作效率更高。最后可以使用 join 方法将列表中的所有字符串元素合并成一个新的字符串,这样更加高效。