我对这个问题非常困惑。我知道使用递归和动态编程作为改进来找到2个字符串之间的编辑距离,但是对于如何使用这个来感到困惑。
不确定我的想法是否正确。但是我们有一串不平衡的括号说
String s = "((())))";
如何找到平衡括号的字符串,需要最少的编辑次数?
有人可以用一个例子来解释这个吗?
我仍然不确定我是否正确解释。
答案 0 :(得分:5)
给定由左括号和右括号组成的字符串,我们被要求通过执行最少数量的删除,插入和替换操作来平衡它。
首先,让我们查看输入字符串,并将匹配的对与不匹配的字符区分开来。我们可以通过执行以下算法来标记属于匹配对的所有字符:
标记对已经以零成本平衡,因此最佳行动方案是不再采取任何措施。
现在让我们考虑一下没有标记的字符。请注意,没有未标记的'('后面跟未标记的')',否则该对将被标记。因此,如果我们从左到右扫描未标记的字符,我们会发现零或更多“'”'字符后跟零或更多'('字符。
要平衡')的序列。对于字符,最好将每一个字段重写为'(',从第一个字母开始,排除最后一个。如果有奇数个')'删除最后一个字符是最佳的。
对于'('字符的序列,最好将每隔一个字符重写为'),从第二个开始。如果有剩余的'('字符,我们会将其删除。 以下Python代码实现上述步骤并显示中间结果。
def balance(s): # s is a string of '(' and ')' characters in any order
n = len(s)
print('original string: %s' % s)
# Mark all matched pairs
marked = n * [ False ]
left_parentheses = []
for i, ch in enumerate(s):
if ch == '(':
left_parentheses.append(i)
else:
if len(left_parentheses) != 0:
marked[i] = True
marked[left_parentheses.pop()] = True
# Display the matched pairs and unmatched characters.
matched, remaining = [], []
for i, ch in enumerate(s):
if marked[i]:
matched.append(ch)
remaining.append(' ')
else:
matched.append(' ')
remaining.append(ch)
print(' matched pairs: %s' % ''.join(matched))
print(' unmatched: %s' % ''.join(remaining))
cost = 0
deleted = n * [ False ]
new_chars = list(s)
# Balance the unmatched ')' characters.
right_count, last_right = 0, -1
for i, ch in enumerate(s):
if not marked[i] and ch == ')':
right_count += 1
if right_count % 2 == 1:
new_chars[i] = '('
cost += 1
last_right = i
if right_count % 2 == 1: # Delete the last ')' if we couldn't match it.
deleted[last_right] = True # The cost was incremented during replacement.
# Balance the unmatched '(' characters.
left_count, last_left = 0, -1
for i, ch in enumerate(s):
if not marked[i] and ch == '(':
left_count += 1
if left_count % 2 == 0:
new_chars[i] = ')'
cost += 1
else:
last_left = i
if left_count % 2 == 1: # Delete the last '(' if we couldn't match it.
deleted[last_left] = True # This character wasn't replaced, so we must
cost += 1 # increment the cost now.
# Display the outcome of replacing and deleting.
balanced = []
for i, ch in enumerate(new_chars):
if marked[i] or deleted[i]:
balanced.append(' ')
else:
balanced.append(ch)
print(' balance: %s' % ''.join(balanced))
# Display the cost of balancing and the overall balanced string.
print(' cost: %d' % cost)
result = []
for i, ch in enumerate(new_chars):
if not deleted[i]: # Skip deleted characters.
result.append(ch)
print(' new string: %s' % ''.join(result))
balance(')()(()())))()((())((')
对于测试用例')()(()())))()((())(('
,输出如下。
original string: )()(()())))()((())((
matched pairs: ()(()()) () (())
unmatched: ) )) ( ((
balance: ( ) ( )
cost: 4
new string: (()(()()))()((()))
答案 1 :(得分:2)
这个想法很简单:
以下是正在运行的代码:http://codeshare.io/bX1Dt
让我知道你的想法。
答案 2 :(得分:1)
虽然这个有趣的问题可以通过评论中提到的动态编程来解决,但它有一个更简单的解决方案。你可以用贪心算法解决它。
这种贪婪算法的想法来自于我们如何检查括号表达式的有效性。您将counter设置为0并遍历括号字符串,在"("和和#34;)中添加1;"。如果计数器始终保持在0或0并且在0结束,则表示您有一个有效的字符串。
这意味着如果我们在遍历时遇到的最低值是-maxi,我们需要准确添加-maxi"("在开始时。调整最终计数器值以添加"( "并添加足够的")"在结尾处以0结束。
以下是算法的伪代码:
counter = 0
mini = 0
for each p in string:
if p == "(":
counter++
else:
counter--
mini = min(counter, mini)
add -mini "(" at the start of the string
counter -= mini
add counter ")" at the end of the string
答案 3 :(得分:0)
我厌倦了用DP算法解决问题,它通过了我自己编写的一些测试用例。如果您认为这是正确的,请告诉我。
让P(i,j)
成为使字符串S[i..j]
达到平衡的最低编辑次数。
当S[i]
等于S[j]
时,最低编辑数明显为P(i+1,j-1)
有一些选项可以在S[i] != S[j]
时使字符串保持平衡,但最后我们可以添加'('到i的前面或')&# 39;在j的末尾,或删除i或j处的括号。在所有这些情况下,最低编辑数为min{P(i+1, j), P(i, j-1)} + 1
。
因此,我们有以下DP公式:
P(i,j) = 0 if i > j
= P(i + 1, j - 1) if S[i] matches S[j] OR S[i] and S[j] are not parenthesis
= min{P(i + 1, j), P(i, j - 1)} + 1
答案 4 :(得分:0)
我会使用堆栈来有效地平衡它们。这是python代码:
a=['(((((','a(b)c)','((())))',')()(()())))()((())((']
def balance(s):
st=[]
l=len(s)
i=0
while i<l:
if s[i]=='(':
st.append(i)
elif s[i]==')':
if st:
st.pop()
else:
del s[i]
i-=1
l-=1
i+=1
while st:
del s[st.pop()]
return ''.join(s)
for i in a:
print balance(list(i))
<强>输出强>:
Empty
a(b)c
((()))
()(()())()(())
答案 5 :(得分:0)
//fisher
public int minInsertions(String s) {
Stack<Character> stack = new Stack<>();
int insertionsNeeded = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
if (stack.isEmpty()) {
stack.add(c);
} else {
if (stack.peek() == ')') {
//in this case, we need to add one more ')' to get two consecutive right paren, then we could pop the one ')' and one '(' off the stack
insertionsNeeded++;
stack.pop();
stack.pop();
stack.add(c);
} else {
stack.add(c);
}
}
} else if (c == ')') {
if (stack.isEmpty()) {
//in this case, we need to add one '(' before we add this ')' onto this stack
insertionsNeeded++;
stack.add('(');
stack.add(c);
} else {
if (stack.peek() == ')') {
//in this case, we could pop the one ')' and one '(' off the stack
stack.pop();
stack.pop();
} else {
stack.add(c);
}
}
}
}
if (stack.isEmpty()) {
return insertionsNeeded;
} else {
while (!stack.isEmpty()) {
char pop = stack.pop();
if (pop == '(') {
insertionsNeeded += 2;
} else {
insertionsNeeded++;
stack.pop();
}
}
return insertionsNeeded;
}
}
}