检查是否可以通过将括号向两端移动最多 K 次来获得平衡括号

data structurec++server side programmingprogramming

在这个问题中,我们需要检查是否可以通过将字符串的末尾最多移动 K 个字符来获得括号的有效平衡子序列。

为了解决这个问题,我们可以使用堆栈数据结构。解决问题的逻辑是,如果我们在'('(开括号)之前找到超过 K 个')'(闭括号),我们就不能将字符串变成有效的子序列。

问题陈述– 我们给出了包含'('和')'括号序列的字符串 str。字符串的长度为 N。此外,我们给出了一个正整数 K。我们需要检查是否可以通过在字符串末尾移动字符串的最多 K 个字符来将给定的字符串变成有效的括号子序列。根据我们是否可以生成有效的子序列打印'是'或'否'。

示例

输入– str = ")()()(", k = 1

输出– '是'

解释– 在将第一个字符移动到末尾后字符串末尾,我们可以得到'()()()',这是一个有效的括号子序列

输入– str = "))())()(((", k = 2

输出– 否,

解释– 我们最多可以在字符串末尾移动 2 个字符。因此,在移动字符串末尾的前 2 个字符后,我们可以得到'())()((())',这不是有效的括号子序列。

输入– str = '()(', k = 10

输出– 否

解释– 字符串不包含相同数量的开括号和闭括号,因此无法创建有效的括号子序列。

方法1

我们将使用堆栈数据结构来按此方法解决问题。

算法

  • 如果 n 为奇数,则返回 false,因为如果字符串长度为奇数,则我们无法获得匹配括号的子序列。

  • 定义"open"和"close"变量并用零初始化。

  • 使用循环遍历字符串。如果当前字符是'(',则将 open 的值增加 1。否则,将')'的值增加 1。

  • 如果 open 和 closed 不相等,则返回 false,因为如果左括号和右括号的总数不相等,我们就无法获得平衡子序列。

  • 用零初始化'res'变量并定义一个空堆栈。

  • 再次开始遍历字符串。

  • 如果当前字符是'(',则将其推送到堆栈。

  • 如果当前字符是')',并且堆栈不为空,则从堆栈中删除顶部元素。否则,将'res'的值增加 1,因为我们需要移动末尾的字符。

  • 最后,检查'res'的值是否小于 K。如果是,则返回 true。否则,返回 false。

示例

#include <bits/stdc++.h>
using namespace std;
// 函数检查是否可以根据给定条件使字符串平衡
bool getMinMoves(string s, int n, int k) {
    // 如果字符串的长度为奇数,则无法使字符串平衡
    if(n % 2 != 0) {
        return false;
    }
    // 计算左括号和右括号的总数
    int open = 0, close = 0;
    // 遍历字符串
    for (int i = 0; i < n; i++) {
        // 如果当前字符是左括号,则增加 open。否则增加 close
        if (s[i] == '(') {
            open++;
        } else {
            close++;
        }
    }
    // 如果左括号的数量不等于右括号的数量,则无法使字符串平衡
    if (open != close) {
        return false;
    }
    // 存储使字符串平衡所需的移动
    int res = 0;
    // 定义堆栈
    stack<char> st;
    // 遍历字符串
    for (int i = 0; i < n; ++i) {
      // 如果当前字符是打开括号,则将其推送到堆栈
      if (s[i] == '(') {
          st.push(s[i]);
      } else {
          if(!st.empty()) {
            st.pop();
            } else {
                // 增加res
                ++res;
            }
       }
   }
   // 如果 res 小于或等于 k,则返回 true。否则返回 false
   if (res <= k) {
      return true;
   } else {
      return false;
   }
}
int main() {
    string str = "))())()(((";
    int K = 2;
    if (getMinMoves(str, str.length(), K)) {
        cout << "是的,通过将字符移动到任一端最多 K 次,可以生成有效的括号";
    } else {
        cout << "否,通过将字符移动到任一端最多 K 次,无法生成有效的括号";
    }
    return 0;
}

输出

否,通过将字符移动到任一端最多 K 次,无法生成有效的括号

时间复杂度 – O(N),因为我们遍历字符串。

空间复杂度 – O(N),因为我们使用堆栈。

方法2

在这种方法中,我们将编写优化的代码,而不使用堆栈来提高代码的空间复杂度。

算法

  • 如果字符串长度为奇数,则返回 false。

  • 使用 count() 方法计算'('和')'字符的总数。如果两者的计数不相等,则返回 false。

  • 定义'res'和'count'变量并用零初始化。

  • 开始遍历字符串

  • 如果当前字符为'(',则将计数的值增加 1。否则,将计数的值减少 1。

  • 如果'count'的值小于零,则将'res'的值增加 1,并将计数更新为零。

  • 循环迭代完成后,返回"res <= k"值。

示例

#include <bits/stdc++.h>
using namespace std;
bool getMinMoves(string s, int n, int k) {
    // 如果字符串的长度为奇数,则无法使字符串平衡
    if(n % 2 != 0) {
        return false;
    }
    int open = 0, close = 0;
    // 计算左括号和右括号的数量
    open = count(s.begin(), s.end(), '(');
    close = count(s.begin(), s.end(), ')');
    // 如果左括号的数量不等于右括号的数量,则无法使字符串平衡
    if (open != close) {
        return false;
    }
    // 存储使字符串平衡所需的移动次数
    int res = 0;
    int count = 0;
    // 遍历字符串
    for (int i = 0; i < n; ++i) {
      // 如果当前字符是左括号,则计数加 1
      if (s[i] == '(') {
          ++count;
      } else {
        // 将 count 减 1
        --count;
        // 如果 count 变为负数,则将 count 更新为 0,并将 res 增加 1。
        if (count < 0) {
            // 更新 count
            count = 0;
            // 增加 res
            ++res;
        }
      }
   }
   return (res <= k);
}
int main() {
    string str = ")()()(";
    int K = 1;
    if (getMinMoves(str, str.length(), K)) {
        cout << "是的,最多将字符移动到任一端 K 次即可生成有效的括号";
    } else {
        cout << "否,最多将字符移动到任一端 K 次即可生成有效的括号";
    }
    return 0;
}

输出

是的,最多将字符移动到任一端 K 次即可生成有效的括号

时间复杂度 – O(N),因为我们遍历字符串。

空间复杂度 – O(1),因为我们不使用动态空间。


相关文章