過去にスタックを使用して平衡方程式をチェックするソフトウェアを作成しましたが、今度は同様のアルゴリズムを再帰的に作成して、適切にネストされたブラケットと括弧をチェックするように求められます。
良い例:()[]()([]()[])
悪い例:((]([)]
私の関数が呼び出されたとします:isBalanced。
各パスは、より小さな部分文字列を評価する必要があります(2の基本ケースに達するまで)。または、常に文字列全体を評価し、インデックスを内側に移動する必要がありますか?
これを行うには多くの方法がありますが、最も単純なアルゴリズムは単純に左から右に処理し、スタックをパラメーターとして渡すことです
FUNCTION isBalanced(String input, String stack) : boolean
IF isEmpty(input)
RETURN isEmpty(stack)
ELSE IF isOpen(firstChar(input))
RETURN isBalanced(allButFirst(input), stack + firstChar(input))
ELSE IF isClose(firstChar(input))
RETURN NOT isEmpty(stack) AND isMatching(firstChar(input), lastChar(stack))
AND isBalanced(allButFirst(input), allButLast(stack))
ELSE
ERROR "Invalid character"
ここでは、Javaで実装されています。便宜上、スタックが文字列のbackの代わりにfrontをプッシュするように切り替えたことに注意してください。また、エラーとして報告するのではなく、括弧以外の記号をスキップするように修正しました。
static String open = "([<{";
static String close = ")]>}";
static boolean isOpen(char ch) {
return open.indexOf(ch) != -1;
}
static boolean isClose(char ch) {
return close.indexOf(ch) != -1;
}
static boolean isMatching(char chOpen, char chClose) {
return open.indexOf(chOpen) == close.indexOf(chClose);
}
static boolean isBalanced(String input, String stack) {
return
input.isEmpty() ?
stack.isEmpty()
: isOpen(input.charAt(0)) ?
isBalanced(input.substring(1), input.charAt(0) + stack)
: isClose(input.charAt(0)) ?
!stack.isEmpty() && isMatching(stack.charAt(0), input.charAt(0))
&& isBalanced(input.substring(1), stack.substring(1))
: isBalanced(input.substring(1), stack);
}
テストハーネス:
String[] tests = {
"()[]<>{}",
"(<",
"]}",
"()<",
"(][)",
"{(X)[XY]}",
};
for (String s : tests) {
System.out.println(s + " = " + isBalanced(s, ""));
}
出力:
()[]<>{} = true
(< = false
]} = false
()< = false
(][) = false
{(X)[XY]} = true
まず、元の質問に対して、非常に長い文字列を使用している場合は、関数呼び出しを行うたびに1文字を除いた正確なコピーを作成したくないことに注意してください。そのため、インデックスの使用を優先するか、選択した言語が舞台裏でコピーを作成していないことを確認する必要があります。
第二に、スタックデータ構造を使用しているすべての回答に問題があります。割り当てのポイントは、再帰によって関数呼び出しスタックの作成を理解することだと思います。各再帰呼び出しは暗黙的なスタック上の新しいエントリであるため、括弧を保持するためにスタックデータ構造を使用する必要はありません。
(
と)
に一致するCプログラムでデモを行います。 [
や]
などの他のタイプを追加することは、読者の課題です。関数で保持するのは、再帰がスタックであるため、文字列内の位置(ポインタとして渡される)です。
/* Search a string for matching parentheses. If the parentheses match, returns a
* pointer that addresses the nul terminator at the end of the string. If they
* don't match, the pointer addresses the first character that doesn't match.
*/
const char *match(const char *str)
{
if( *str == '\0' || *str == ')' ) { return str; }
if( *str == '(' )
{
const char *closer = match(++str);
if( *closer == ')' )
{
return match(++closer);
}
return str - 1;
}
return match(++str);
}
このコードでテスト済み:
const char *test[] = {
"()", "(", ")", "", "(()))", "(((())))", "()()(()())",
"(() ( hi))) (())()(((( ))))", "abcd"
};
for( index = 0; index < sizeof(test) / sizeof(test[0]); ++index ) {
const char *result = match(test[index]);
printf("%s:\t", test[index]);
*result == '\0' ? printf("Good!\n") :
printf("Bad @ char %d\n", result - test[index] + 1);
}
出力:
(): Good!
(: Bad @ char 1
): Bad @ char 1
: Good!
(())): Bad @ char 5
(((()))): Good!
()()(()()): Good!
(() ( hi))) (())()(((( )))): Bad @ char 11
abcd: Good!
アイデアは、開いた括弧のリストを保持し、閉じ括弧を見つけた場合、最後に開いた括弧を閉じるかどうかを確認することです。
文字列が最終的に空になったときに、角かっこのリストも空の場合(したがって、すべての角かっこが閉じられている場合)、true
を返します。それ以外の場合はfalse
[〜#〜] algorithm [〜#〜](Javaの場合):
public static boolean isBalanced(final String str1, final LinkedList<Character> openedBrackets, final Map<Character, Character> closeToOpen) {
if ((str1 == null) || str1.isEmpty()) {
return openedBrackets.isEmpty();
} else if (closeToOpen.containsValue(str1.charAt(0))) {
openedBrackets.add(str1.charAt(0));
return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
} else if (closeToOpen.containsKey(str1.charAt(0))) {
if (openedBrackets.getLast() == closeToOpen.get(str1.charAt(0))) {
openedBrackets.removeLast();
return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
} else {
return false;
}
} else {
return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
}
}
[〜#〜] test [〜#〜]:
public static void main(final String[] args) {
final Map<Character, Character> closeToOpen = new HashMap<Character, Character>();
closeToOpen.put('}', '{');
closeToOpen.put(']', '[');
closeToOpen.put(')', '(');
closeToOpen.put('>', '<');
final String[] testSet = new String[] { "abcdefksdhgs", "[{aaa<bb>dd}]<232>", "[ff{<gg}]<ttt>", "{<}>" };
for (final String test : testSet) {
System.out.println(test + " -> " + isBalanced(test, new LinkedList<Character>(), closeToOpen));
}
}
[〜#〜] output [〜#〜]:
abcdefksdhgs -> true
[{aaa<bb>dd}]<232> -> true
[ff{<gg}]<ttt> -> false
{<}> -> false
次のクラスをインポートしたことに注意してください。
import Java.util.HashMap;
import Java.util.LinkedList;
import Java.util.Map;
public static boolean isBalanced(String str) {
if (str.length() == 0) {
return true;
}
if (str.contains("()")) {
return isBalanced(str.replaceFirst("\\(\\)", ""));
}
if (str.contains("[]")) {
return isBalanced(str.replaceFirst("\\[\\]", ""));
}
if (str.contains("{}")) {
return isBalanced(str.replaceFirst("\\{\\}", ""));
} else {
return false;
}
}
論理的な観点からは重要ではありません。現在のすべての不均衡な括弧を再帰の各ステップに渡すと、後方に目を向ける必要がなくなります。再帰呼び出しごとに文字列を切り取るか、単にインデックスをインクリメントして現在の最初の文字だけを見るかは問題です。
可変ではない文字列を持つほとんどのプログラミング言語では、スタック上で少し大きい文字列を渡すよりも、文字列を短くする方が(パフォーマンス面で)おそらくコストがかかります。一方、Cのような言語では、char配列内のポインターをインクリメントするだけで済みます。これら2つのアプローチのどちらがより「効率的」であるかは、言語にかなり依存していると思います。どちらも概念的な観点からは同等です。
これはあなたのデザイン次第です。 2つのカウンタを使用するか、2つの異なるシンボルでスタックするか、再帰を使用して処理できます。違いは設計アプローチにあります。
func evalExpression(inStringArray:[String])-> Bool{
var status = false
var inStringArray = inStringArray
if inStringArray.count == 0 {
return true
}
// determine the complimentary bracket.
var complimentaryChar = ""
if (inStringArray.first == "(" || inStringArray.first == "[" || inStringArray.first == "{"){
switch inStringArray.first! {
case "(":
complimentaryChar = ")"
break
case "[":
complimentaryChar = "]"
break
case "{":
complimentaryChar = "}"
break
default:
break
}
}else{
return false
}
// find the complimentary character index in the input array.
var index = 0
var subArray = [String]()
for i in 0..<inStringArray.count{
if inStringArray[i] == complimentaryChar {
index = i
}
}
// if no complimetary bracket is found,so return false.
if index == 0{
return false
}
// create a new sub array for evaluating the brackets.
for i in 0...index{
subArray.append(inStringArray[i])
}
subArray.removeFirst()
subArray.removeLast()
if evalExpression(inStringArray: subArray){
// if part of the expression evaluates to true continue with the rest.
for _ in 0...index{
inStringArray.removeFirst()
}
status = evalExpression(inStringArray: inStringArray)
}
return status
}
Scalaプログラミング言語では、次のようにします。
def balance(chars: List[Char]): Boolean = {
def process(chars: List[Char], myStack: Stack[Char]): Boolean =
if (chars.isEmpty) myStack.isEmpty
else {
chars.head match {
case '(' => process(chars.tail, myStack.Push(chars.head))
case ')' => if (myStack.contains('(')) process(chars.tail, myStack.pop)
else false
case '[' => process(chars.tail, myStack.Push(chars.head))
case ']' => {
if (myStack.contains('[')) process(chars.tail, myStack.pop) else false
}
case _ => process(chars.tail, myStack)
}
}
val balancingAuxStack = new Stack[Char]
process(chars, balancingAuxStack)
}
完璧に編集してください。
私はScalaでの変換のみを提案していました。
バランスの取れた括弧をチェックするPHPソリューション
<?php
/**
* @param string $inputString
*/
function isBalanced($inputString)
{
if (0 == strlen($inputString)) {
echo 'String length should be greater than 0';
exit;
}
$stack = array();
for ($i = 0; $i < strlen($inputString); $i++) {
$char = $inputString[$i];
if ($char === '(' || $char === '{' || $char === '[') {
array_Push($stack, $char);
}
if ($char === ')' || $char === '}' || $char === ']') {
$matchablePairBraces = array_pop($stack);
$isMatchingPair = isMatchingPair($char, $matchablePairBraces);
if (!$isMatchingPair) {
echo "$inputString is NOT Balanced." . PHP_EOL;
exit;
}
}
}
echo "$inputString is Balanced." . PHP_EOL;
}
/**
* @param string $char1
* @param string $char2
* @return bool
*/
function isMatchingPair($char1, $char2)
{
if ($char1 === ')' && $char2 === '(') {
return true;
}
if ($char1 === '}' && $char2 === '{') {
return true;
}
if ($char1 === ']' && $char2 === '[') {
return true;
}
return false;
}
$inputString = '{ Swatantra (() {} ()) Kumar }';
isBalanced($inputString);
?>