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中重复的选择 比如
Leetcode 301 删除无效的括号  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;
	}
};

我的视频题解空间

上一篇:函数防抖、节流


下一篇:现代操作系统:原理与实现配套实验ChCore-lab02