LeetCode 301. 删除无效的括号
思路
本题有两点需要解决,如果确定括号的最少删除数量以及删除哪些括号
求出最少删除数量
思路见 LeetCode 22. 括号生成
已知删除数量,删除哪些括号?
直接爆搜,枚举每个括号是否删除
- 如果当前是左括号,枚举是否删除 (删除 0 还是 1 个)
- 如果当前是左括号,枚举是否删除 (删除 0 还是 1 个)
- 如果不是括号,不能删除,直接递归下一步
假设输入为 ()))))
,爆搜出来的答案会重复,耗时。为此,遇到连续多个括号时,不应该枚举哪个括号应该删除,而应该枚举的数量,我们人为规定删除顺序从左到右,这是第一处剪枝
直接枚举括号是否删除,那么如何保证括号序列合法呢?
- 方法 1:加入答案之前,使用
check
函数判断是否合法,合法再加入,可以过,但时间复杂度增加
bool check(string s)
{
int cnt = 0,n = s.length();
for(int i = 0 ; i < n ; i ++)
{
if(s[i] =='(') cnt ++;
else if(s[i] == ')') cnt --;
if(cnt < 0) return false;
}
return cnt == 0;
}
- 本题用的方法 2:枚举过程中,时刻保证左括号数量>右括号数量,为此需要维护一个
cnt
变量,记录左括号和右括号数量的差值- 刚进入递归时,
path
是满足cnt>0
的 - 如果当前字符不是括号,加入
path
,继续递归 - 如果当前字符是括号,倒序枚举删除多少括号 (删除所有括号~删除 0 个括号),反过来理解就是,正序枚举
path
添加多少括号 path
添加左括号后一定满足条件,而添加右括号后可能非法了,因此需要保证cnt>0
的情况下,添加右括号进入下一步递归,这是第二处剪枝
- 刚进入递归时,
时间复杂度
最坏情况下每个位置有两种选择,去掉和不去掉,最后需要 O (n)的时间拷贝答案,故时间复杂度为 O ($n2^{n}$)
方法1代码
class Solution {
public:
vector<string> ans;
vector<string> removeInvalidParentheses(string s) {
//lr分别记录要删除的左右括号数量
int l=0,r=0;
for(auto c:s)
if(c=='(') l++;
else if(c==')')
{
if(l==0) r++;
else l--;
}
dfs(s,"",0,l,r);
return ans;
}
bool check(string s)
{
int cnt = 0,n = s.length();
for(int i = 0 ; i < n ; i ++)
{
if(s[i] =='(') cnt ++;
else if(s[i] == ')') cnt --;
if(cnt < 0) return false;
}
return cnt == 0;
}
void dfs(string s,string path,int u,int l,int r)//枚举删除哪些括号
{
int n=s.size();
if(u>=n)
{
if(check(path))
ans.push_back(path);
return;
}
if(s[u]=='(')
{
//找出连续括号数量
int t=u;
while(t<n&&s[t]=='(') t++;
//倒序枚举删除的数量
l-=t-u;
for(int i=t-u;i>=0;i--)
{
if(l>=0)
dfs(s,path,t,l,r);
path=path+'(';
l++;
}
}
else if(s[u]==')')
{
//找出连续括号数量
int t=u;
while(t<n&&s[t]==')') t++;
//倒序枚举删除的数量
r-=t-u;
for(int i=t-u;i>=0;i--)
{
if(r>=0)
dfs(s,path,t,l,r);
path=path+')';
r++;
}
}
else//当前不是括号,直接递归下一步
dfs(s,path+s[u],u+1,l,r);
}
};
方法2代码
class Solution {
public:
vector<string> ans;
vector<string> removeInvalidParentheses(string s) {
//lr分别记录要删除的左右括号数量
int l=0,r=0;
for(auto c:s)
if(c=='(') l++;
else if(c==')')
{
if(l==0) r++;
else l--;
}
dfs(s,"",0,l,r,0);
return ans;
}
void dfs(string s,string path,int u,int l,int r,int cnt)//枚举删除哪些括号
{
int n=s.size();
if(u>=n)
{
if(!cnt)
ans.push_back(path);
return;
}
if(s[u]=='(')
{
//找出连续括号数量
int t=u;
while(t<n&&s[t]=='(') t++;
//倒序枚举删除的数量
l-=t-u;
for(int i=t-u;i>=0;i--)
{
if(l>=0)
dfs(s,path,t,l,r,cnt);
path=path+'(';
l++;cnt++;
}
}
else if(s[u]==')')
{
//找出连续括号数量
int t=u;
while(t<n&&s[t]==')') t++;
//倒序枚举删除的数量
r-=t-u;
for(int i=t-u;i>=0;i--)
{
if(r>=0&&cnt>=0)
dfs(s,path,t,l,r,cnt);
path=path+')';
r++;cnt--;
}
}
else//当前不是括号,直接递归下一步
dfs(s,path+s[u],u+1,l,r,cnt);
}
};
有帮助的话可以点个赞,我会很开心的~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2022-07-18 css设置样式常用参数