leetcode 301. Remove Invalid Parentheses

news/2025/2/24 17:03:17

题目要求

Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

Note: The input string may contain letters other than the parentheses ( and ).

Examples:
"()())()" -> ["()()()", "(())()"]
"(a)())()" -> ["(a)()()", "(a())()"]
")(" -> [""]

现在有一个字符串包含一些左右括号以及字母。一个合法的字符串是指左括号和右括号必定成对出现。要求得出用最少次数的删除可以得到的所有的合法字符串。

思路和代码

这道题目的思路源自于评论区。刚开始会有点难以理解,现在试图理清这个思路。

先从题目中给的例子入手:()())()
当遍历到第五个括号时,我们发现这个括号的存在非法。因此我们会从当前的三个右括号(下标分别为1, 3, 4)中选择一个删去。那么选择哪个呢?其实选择任意一个右括号都可以使当前的的子字符串合法,并依次生成如下三个结果(())()()()()。最后两个结果重复,因此只保留(())()()两个结果。最终生成的合法字符串为[()()(), (())()]

这里说明了一种情况,即右括号的数量多于左括号的数量。那么如何处理左括号的数量多于右括号数量的场景呢?如()(()
其实,我们只需要将其倒置为)(()(,并且将)(视为一组合法的括号即可。这时我们会看见下标2上的左括号不合法,对之进行处理即可。方法相同于上一种情况。

还要考虑一个问题,即出现重复的结果集的问题,就像例子中重复生成的的()()。我们如何才能避免使用Set来过滤掉重复的结果呢?

还是举一个例子:()())())
按照之前的处理,当我们遍历到下标4上的右括号时,我们有三个删除选择。而且我们发现当出现连续的右括号时,删除该连续括号中的任意一个产生的结果都相同。所以默认情况下,我们删除第一个括号。这时处理后的字符串为()()())以及(())())

再对()()())处理,同样的,当我们遇到最后一个右括号时,只需要删除任意一个右括号就可以使数组成为合法数组,那么我们先根据第一个原则,删除连续右括号的第一个括号,可以产生没有重复的结果为(()()),()(())()()()

同理(())())可以处理出结果(()())(())()。其中(()())出现了两次。我们如何避免这样的重复呢?这时我们需要记录一下最后一次删除所在的下标。在该下标前的删除将会产生重复的结果。这里我们看到最后一次删除的下标为3。对下标3之前的删除将会带来重复的结果(()())

public List<String> removeInvalidParentheses(String s) {
        List<String> result = new ArrayList<String>();
        removeInvalidParentheses(s, result, 0, 0, new char[]{'(', ')'});
        return result;
    } 
    
    
    
    public void removeInvalidParentheses(String s, List<String> result, int lastRemoveIndex, int lastCheckedIndex, char[] pattern){
        for(int stack = 0, i = lastCheckedIndex ; i<s.length() ; i++){
            int cur = s.charAt(i);
            if(cur == pattern[0]) stack++;
            if(cur == pattern[1]) stack--;
            if(stack>=0) continue;
            for(int j = lastRemoveIndex ; j <= i ; j++){
                if(s.charAt(j)==pattern[1] && (j == lastRemoveIndex || s.charAt(j-1)!=pattern[1])){
                    removeInvalidParentheses(s.substring(0, j) + s.substring(j+1), result, j, i, pattern);
                }
            }
            return;
        }
        String reversed = new StringBuilder(s).reverse().toString();
        if(pattern[0] == '('){
            removeInvalidParentheses(reversed, result, 0, 0, new char[]{')', '('});
        }else{
            result.add(reversed);
        }
    }

clipboard.png
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~


http://www.niftyadmin.cn/n/3369337.html

相关文章

C语言程序员不会告诉你的14个工具和插件 | 收藏 ...

关注我并收藏这篇文章&#xff0c;可以私信我领取这篇文章内所有的工具和插件&#xff01;koz.ross 维护的一个 C 语言资源列表&#xff0c;包括了&#xff1a;构建系统、编译器、数据库、加密、初中高的教程/指南、书籍、库等等。 1.构建系统 下面是一些 C 项目的自动化构建和…

初学者第04节之数据类型(上)

1.Java是一种强类型语言&#xff0c;每个变量都必须声明其类型。 Java的数据类型分为两大类&#xff1a;基本类型&#xff08;primitive type&#xff09;和引用类型 &#xff08;reference type&#xff09; Java中定义了3类8种基本数据类型,今天主要讲讲基本数据类型。如…

require.context() 用于获取一个特定上下文的,webpack的一个api

参考链接&#xff1a; 1、https://www.jianshu.com/p/c894ea00dfec 2、https://www.jianshu.com/p/c894ea00dfec require.context() 1、可以使用require.context()函数创建自己的上下文。它允许您传入一个&#xff0c;目录进行搜索&#xff0c;一个标志指示是否应该搜索子目录&…

修改文件默认代码方式

转载于:https://www.cnblogs.com/minconding/p/10440676.html

Vue中如何在线预览pdf文件

某次项目的需求中要实现pdf文件的在线预览&#xff0c;百度了很多个实现pdf在线预览的功能&#xff0c;感觉看起来都是比较费劲&#xff0c;可能自己比较菜吧&#xff0c;但是总结了一下可以实现这种结果的是pdf.js 可以去pdf.js的官网下载文件&#xff1a; mozilla.github.io/…

外部排序——大文件排序

外部排序 外部排序指的是大文件排序&#xff0c;即待排序的记录存储在外存储器上&#xff0c;待排序的文件无法一次装入内存&#xff0c;需要在内存和外部存储器之间进行多次数据交换&#xff0c;以达到排序整个文件的目的。 一般来说外排序分为两个步骤&#xff1a;预处理和…

IList, ICollection ,IEnumerable AND IEnumerator in C#

IList, ICollection ,IEnumerable 很显然&#xff0c;这些都是集合接口的定义&#xff0c;先看看定义&#xff1a; 1 // 摘要:2 // 表示可按照索引单独访问的对象的非泛型集合。3 [ComVisible(true)]4 public interface IList : ICollection, IEnumerable5 …

Java中的回溯算法

回溯算法 定义&#xff1a; 回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜素尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#xff0c;尝试别的路径。回溯法是一种选优搜索法&#xff0c;按选优条件向前搜索&a…