• Leetcode 301 删除无效的括号 DFS+剪枝


    地址 https://leetcode-cn.com/problems/remove-invalid-parentheses/

    给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
    返回所有可能的结果。答案可以按 任意顺序 返回。
    
    示例 1:
    输入:s = "()())()"
    输出:["(())()","()()()"]
    
    示例 2:
    输入:s = "(a)())()"
    输出:["(a())()","(a)()()"]
    
    示例 3:
    输入:s = ")("
    输出:[""]
     
    
    提示:
    1 <= s.length <= 25
    s 由小写英文字母以及括号 '(' 和 ')' 组成
    s 中至多含 20 个括号
    

    解法
    dfs 剪枝 但是包括太多细节需要注意
    写了四版代码,前两版都TLE 超时了.
    第一版超时代码

    
    class Solution {
    public:
    	vector<string> ans;
    	int visitedLeft = 0;
    	map<int, set<string>> mm;
    	void dfs(string s, int idx, string& t) {
    		if (idx == s.size()) {
    			if (0 == visitedLeft) {
    				mm[t.size()].insert(t);
    			}
    			return;
    		}
    
    		if (s[idx] == '(') {
    			//选择删除
    			dfs(s,idx+1,t);
    
    			//选择保留
    			t.push_back('(');
    			visitedLeft++;
    			dfs(s, idx + 1, t);
    			visitedLeft--;
    			t.pop_back();
    		}
    		else if(s[idx] == ')') {
    			//选择删除
    			dfs(s, idx + 1, t);
    
    			//如果之前有记录左括号才可能保留右括号
    			if (visitedLeft != 0) {
    				t.push_back(')');
    				visitedLeft--;
    				dfs(s, idx + 1, t);
    				visitedLeft++;
    				t.pop_back();
    			}
    		}
    		else {
    			//非括号的字符 直接存入
    			t.push_back(s[idx]);
    			dfs(s, idx + 1, t);
    			t.pop_back();
    		}
    
    	}
    
    	vector<string> removeInvalidParentheses(string s) {
    		string t;
    		dfs(s,0,t);
    
    		auto tt = mm.rbegin();
    		for (auto & e : tt->second) {
    			ans.push_back(e);
    		}
    
    		return ans;
    	}
    };
    
    

    第二版超时代码

    class Solution {
    public:
    	vector<string> ans;
    	int visitedLeft = 0;
    	int deleteCount = 0;
    	int minDeleteCount = 999999;
    	map<int, set<string>> mm;
    	void dfs(string s, int idx, string& t) {
    		if (idx == s.size()) {
    			if (0 == visitedLeft && minDeleteCount>= deleteCount) {
    				minDeleteCount = deleteCount;
    				mm[t.size()].insert(t);
    			}
    			return;
    		}
    
    		if (deleteCount > minDeleteCount) {
    			//删除过多 不考虑此分支
    			return;
    		}
    
    		if (s[idx] == '(') {
    			//选择删除
    			deleteCount++;
    			dfs(s, idx + 1, t);
    			deleteCount--;
    
    
    			//选择保留
    			t.push_back('(');
    			visitedLeft++;
    			dfs(s, idx + 1, t);
    			visitedLeft--;
    			t.pop_back();
    		}
    		else if (s[idx] == ')') {
    			//选择删除
    			deleteCount++;
    			dfs(s, idx + 1, t);
    			deleteCount--;
    
    			//如果之前有记录左括号才可能保留右括号
    			if (visitedLeft != 0) {
    				t.push_back(')');
    				visitedLeft--;
    				dfs(s, idx + 1, t);
    				visitedLeft++;
    				t.pop_back();
    			}
    		}
    		else {
    			//非括号的字符 直接存入
    			t.push_back(s[idx]);
    			dfs(s, idx + 1, t);
    			t.pop_back();
    		}
    
    	}
    
    	vector<string> removeInvalidParentheses(string s) {
    		string t;
    		dfs(s, 0, t);
    
    		auto tt = mm.rbegin();
    		for (auto & e : tt->second) {
    			ans.push_back(e);
    		}
    
    		return ans;
    	}
    };
    

    然后优化了下dfs中重复的选择 比如

    class Solution {
    public:
    	vector<string> ans;
    	int visitedLeft = 0;
    	map<int, set<string>> mm;
    	void dfs(const string& s, int idx, string& t) {
    		if (idx == s.size()) {
    			if (0 == visitedLeft) {
    				mm[t.size()].insert(t);
    			}
    			return;
    		}
    
    		if (s[idx] != '(' && s[idx] != ')') {
    			//不是括号则保留 并且继续下一位尝试
    			t.push_back(s[idx]);
    			dfs(s,idx+1,t);
    			t.pop_back();
    			return;
    		}
    
    		int k = 0;
    		for (int i = idx; i < s.size(); i++) {
    			if (s[idx] == s[i]) { k++; }
    			else { break; }
    		}
    
    		if (s[idx] == '(') {
    			// (符号
    			//根据有相同k个括号 决定 留几个删除几个
    			for (int i = 0; i <= k; i++) {
    				visitedLeft += i;
    				for(int j = 0;j<i;j++){ t.push_back('('); }
    				dfs(s, idx + k,t);
    				for (int j = 0; j < i; j++) { t.pop_back(); }
    				visitedLeft -= i;
    			}
    		}
    		else {
    			// )符号
    			//根据有相同k个括号 决定 留几个删除几个
    			for (int i = 0; i <= k; i++) {
    				if (i <= visitedLeft) {
    					visitedLeft -= i;
    					for (int j = 0; j < i; j++) { t.push_back(')'); }
    					dfs(s, idx + k, t);
    					for (int j = 0; j < i; j++) { t.pop_back(); }
    					visitedLeft += i;
    				}
    			}
    		}
    	}
    
    	vector<string> removeInvalidParentheses(string s) {
    		string t;
    		dfs(s, 0, t);
    
    		const auto& tmp = mm.rbegin();
    		for (auto& e : tmp->second) {
    			ans.push_back(e);
    		}
    		
    		return ans;
    	}
    };
    

    然后在尝试添加一些优化 在某些DFS路径中,如果删除的次数已经比当前得到的尝试结果删除次数过,那么就不必继续尝试了,不可能得到更少次数的结果的,优化剪枝

    class Solution {
    public:
    	vector<string> ans;
    	int visitedLeft = 0;
    	map<int, set<string>> mm;
    
    	int minDelC = 999999;
    	int delCount = 0;
    	void dfs(const string& s, int idx, string& t) {
    		if (idx == s.size()) {
    			if (0 == visitedLeft && delCount<=minDelC) {
    				minDelC = delCount;
    				mm[t.size()].insert(t);
    			}
    			return;
    		}
    
    		if (delCount > minDelC) { return; }
    
    
    		if (s[idx] != '(' && s[idx] != ')') {
    			//不是括号则保留 并且继续下一位尝试
    			t.push_back(s[idx]);
    			dfs(s,idx+1,t);
    			t.pop_back();
    			return;
    		}
    
    		int k = 0;
    		for (int i = idx; i < s.size(); i++) {
    			if (s[idx] == s[i]) { k++; }
    			else { break; }
    		}
    
    		if (s[idx] == '(') {
    			// (符号
    			//根据有相同k个括号 决定 留几个删除几个
    			for (int i = 0; i <= k; i++) {
    				visitedLeft += i;
    				delCount += (k - i);
    				for(int j = 0;j<i;j++){ t.push_back('('); }
    				dfs(s, idx + k,t);
    				for (int j = 0; j < i; j++) { t.pop_back(); }
    				delCount -= (k - i);
    				visitedLeft -= i;
    			}
    		}
    		else {
    			// )符号
    			//根据有相同k个括号 决定 留几个删除几个
    			for (int i = 0; i <= k; i++) {
    				if (i <= visitedLeft) {
    					visitedLeft -= i;
    					delCount += (k - i);
    					for (int j = 0; j < i; j++) { t.push_back(')'); }
    					dfs(s, idx + k, t);
    					for (int j = 0; j < i; j++) { t.pop_back(); }
    					delCount -= (k - i);
    					visitedLeft += i;
    				}
    			}
    		}
    	}
    
    	vector<string> removeInvalidParentheses(string s) {
    		string t;
    		dfs(s, 0, t);
    
    		const auto& tmp = mm.rbegin();
    		for (auto& e : tmp->second) {
    			ans.push_back(e);
    		}
    		
    		return ans;
    	}
    };
    

    我的视频题解空间

    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    从清月高中物理动学课件制作工具说【FarseerPhysics引擎之WheelJoint】及【PropetryGrid之动态下拉列表】
    一种从纹理图片提取多边形的方法
    蒸汽世界满手尘土生命、水、光照锁定修改器
    【五子棋AI循序渐进】——整合完成
    洛谷-07敦刻尔克大撤退-[再也不坑]【二战2】二战系列2:狼烟四起
    洛谷-火柴棒等式-NOIP2008提高组复赛
    洛谷-笨小猴-NOIP2008提高组复赛
    NOIP2013-普及组复赛-第一题-计数问题
    NOIP2010-普及组复赛-第四题-三国游戏
    NOIP2012-普及组复赛-第二题-寻宝
  • 原文地址:https://www.cnblogs.com/itdef/p/15352285.html
Copyright © 2020-2023  润新知