递归函数检查字符串是否为“平衡”

时间:2015-01-20 18:49:45

标签: c string algorithm function recursion

我有一个问题,我必须使用递归编写算法(不能使用循环) 问题是我的函数应该检查给定的字符串是否为"平衡"是不是 该字符串仅包含字母(无符号)且仅包含(" ["," ] ")这些括号。
(例如:" [aa] [abbsa] ")。

假设每个"开口支架" (" [")有一个结束的(" ] "),换句话说,字符串中的括号是平衡的,没有必要检查 字符串始终是以下两种格式之一:

  1. 简单字符串: CHARACTERS。
  2. 它只包含没有括号的字符。 (例如:" aaabbcc")。

    1. 包含2个子字符串的字符串:
    2. [ LEFT ] [ RIGHT

      LEFT :本身是一个实际上可以使用两种格式的子字符串(简单字符串或带有2个子字符串的字符串)

      RIGHT :本身是一个实际上可以使用两种格式的子字符串(简单字符串或带有2个子字符串的字符串)

      编辑: 该字符串为有效,无需检查其是否合法。 它总是提到的格式和示例之一(也可能更复杂,但它总是合法的。)

      编辑: 字符串只能采用第一种格式或第二种格式。如果它是第二种格式,那么它包含第一种格式,它必须以" ["并以"]"结束 例子:" aaabbbb" (第1格式)。 " [AA] [BBBB]" (第2格式)。 " [[AA] [B] [[[一个] [BBB] [AAAA]]" (第2格式)。

      如果字符串满足以下至少一个条件,则该字符串为Balanced:

      1. 该字符串来自第一格式。

      2. 该字符串来自第二个格式,左侧的字符数(不带括号)(称为称重)是偶数,右侧的权重也是如此。

      3. 该字符串来自第二格式,左侧的权重也是ODD,右侧的权重也是。

      4. 示例:

        字符串" [abcde] [xyz] "是平衡的,因为正确的重量和左重量都是ODD。

        字符串" [abcde] [xyzw] "没有平衡,因为右权重是偶数(4是偶数)而左权重是奇数(5是奇数)。

        字符串" [abcdef] [[x] [yzw]] "是平衡的 左重是6.
        子串" [x] [yzw] "是平衡的。 (左权重为1,右权重为3(均为ODD)) " [x] [yzw] "的重量是4。 因此," [abcdef] [[x] [yzw]] "是平衡的,因为左右重量都是偶然的。

        "的 [[ABCDE] [XYZW]] [Z] "是平衡的,即使是子串" [abcde] [xyzw] "没有平衡!因为它的重量是9," [Z] "重量为1,它们都是ODD。

        所以,我必须在C中编写一个递归函数,它接收一个"字符串"。

        int verify_weight(char s[])
        {
            //Code I need here
        }
        

        它检查字符串及其中的子字符串,然后如果它们是否平衡则打印每个字符串。
        例如: 字符串" [[aa] [b]] [[[x] [yy]] [hhhhh]] "。
        它打印出这个:
        不平衡:2,1
        不平衡:1,2
        平衡:3,5
        不平衡:3,8

        我也允许创建另一个函数来帮助解决它(仅递归)。

        编辑:(答案)
        感谢大家提供的解决方案,这是@ kolmar的解决方案。

        代码:(在@ kolmar' s对我的函数名称的答案后编辑)

        #include "stdio.h"
        
        int between_balanced(char s[], int n)
        {
          if (!s[0] || (s[0] == ']' && n == 1)) return 0;
          return 1 + between_balanced(s+1, n + (
            s[0] == '[' ? 1 :
            s[0] == ']' ? -1 :
            0
          ));
        }
        
        int verify_weight(char s[])
        {
          if (s[0] == '[') {
            int left = verify_weight(s+1);
            int right = verify_weight(s + between_balanced(s, 0) + 2);
        
            if (left % 2 == right % 2) {
              printf("balanced: ");
            } else {
              printf("imbalanced: ");
            }
            printf("%d,%d\n", left, right);
        
            return left+right;
          } else {
            return between_balanced(s, 1);
          }
        }
        int main() {
            char s[100];
            scanf("%s", s);
                printf("%d\n", verify_weight(s));
        return 0;
        }
        

        很抱歉这个很长的问题,但我真的需要帮助,我花了很多时间试图解决它,但我不能。感谢您的时间和帮助!

4 个答案:

答案 0 :(得分:1)

纯递归版(使用辅助功能)。

想法是找到左侧的结束位置(使用left_side),然后计算每一侧的非括号字符数(使用count_side):

#include <stdio.h>
#include <string.h>

int left_side(char* s, int i, int depth) {
    if (depth == 0) return i;
    if (s[i] == '[') return left_side(s, i+1, depth+1);
    if (s[i] == ']') return left_side(s, i+1, depth-1);
    return left_side(s, i+1, depth);
}

int count_side(char* s, int a, int b) {
    if (a==b) return 0;
    return count_side(s, a+1, b) + (s[a] != '[' && s[a] != ']');
}

int is_balanced(char* s) {
    if (s[0] != '[') return 1;
    int size = strlen(s);
    int left = left_side(s, 1, 1);
    return count_side(s, 0, left)%2 == count_side(s, left, size)%2;
}

int main() {
    char s[256];
    while(scanf("%s", s) != EOF) {
        printf("%s\n", is_balanced(s) ? "YES" : "NO");
    }
}

答案 1 :(得分:1)

单一功能解决方案:

// rs - if we are in the right side bracket now
// ob - unmatched open brackets in the left hand side
// wl - weight of left side
// wr - weight of right side
// call as check(your_string, 0, 0, 0, 0)
int check(char *s, int rs, int ob, int wl, int wr) 
{
  if (!*s) return !rs || wl % 2 == wr % 2;
  if (rs) return check(s+1, rs, ob, wl, wr+1);
  if (s[0] == ']') return check(s+1, ob==1, ob-1, wl, wr);
  if (s[0] == '[') return check(s+1, rs, ob+1, wl, wr);
  return check(s+1, rs, ob, wl+1, wr);
}

修改

这是解决方案,它打印格式2中的每个子字符串,无论是平衡还是不平衡:

#include "stdio.h"

int get_length(char *s, int open_brackets)
{
  if (!*s || (s[0] == ']' && open_brackets == 1)) return 0;
  return 1 + get_length(s+1, open_brackets + (
    s[0] == '[' ? 1 :
    s[0] == ']' ? -1 :
    0
  ));
}

int get_weight(char *s)
{
  if (s[0] == '[') {
    int left = get_weight(s+1);
    int right = get_weight(s + get_length(s, 0) + 2);

    if (left % 2 == right % 2) {
      printf("balanced: ");
    } else {
      printf("imbalanced: ");
    }
    printf("%d, %d\n", left, right);

    return left+right;
  } else {
    return get_length(s, 1);
  }
}

答案 2 :(得分:0)

让我们忘记这样一个事实,即我们暂时不能使用循环并尝试考虑解决它的算法。我们需要做的是为给定字符串中的每个左括号找到匹配的右括号的位置。之后,解决方案几乎变得微不足道:我们可以创建一个辅助函数,它接受一个char数组和两个索引:下限和上限,并执行以下操作(它是伪代码):

// low is inclusive, high is not.
int get_weight(char[] s, int low, int high) {
    if (low == high || s[low] is not a bracket) // The base case: a simple string.
        return high - low;
    int mid = get_matching_index(low); // An index of a matching bracket.
    // Solves this problem recursively for the left and the right substrings.
    int left_weight = get_weight(s, low + 1, mid);
    int right_weight = get_weight(s, mid + 2, high - 1);
    // Prints balanced/imbalanced depending on the left_weight and the right_weight.
    return left_weight + right_weight;
}

所以问题是如何找到匹配的括号对。如果我们可以使用循环,我们可以应用一个标准的基于堆栈的算法(从左到右迭代字符串,如果它是一个左括号,则将一个位置推到堆栈,如果它是一个结束,则从堆栈中弹出顶部元素一)。即使我们不允许使用循环,我们也可以模仿它:

int i;
for (i = 0; i < n; i++) {
    // do something 
}

可以实现为

void iterate_recursively(int i, int n) {
    if (i < n) {
        // do something
        iterate_recursively(i + 1, n);
    }
}

...

iterate_recursively(0, n)

堆栈的实现不需要任何循环,所以它就是它。

答案 3 :(得分:0)

我的解决方案基于将累积分数(重量)与target_score相匹配。评分函数是哈希函数的非常简化版本。自从&#34;平衡&#34;是8字节长,该值应该能够位于64位长整数。

在python中编写,但它的方式与C类似。

def wfunc(s):
    ret = 0
    for x in s:
        ret <<= 8
        ret |= ord(x)
    return ret

def find_balanced(buf, index, score, target_score):
    end = len(buf) == index
    score_hit = score == target_score
    if end:
        return score_hit
    c = buf[index]
    enclosed = c == '[' or c == ']'
    if enclosed:
        if score_hit:
            return True
        else:
            # Reset accumulated value
            return find_balanced(buf, index+1, 0, target_score)
    score <<= 8
    score |= ord(c)
    return find_balanced(buf, index+1, score, target_score)


find_balanced('[Orama][Koma][[exmp][Balanced]', 0, 0, wfunc('Balanced')) # True
find_balanced('[Orama][Koma][[exmp][Balanceded]', 0, 0, wfunc('Balanced')) # False
find_balanced('[Orama][Koma][[exmp][Balance]', 0, 0, wfunc('Balanced')) # False