力扣-5868+5867+678

题目一

在这里插入图片描述

解题思路

1、栈

1、很经典很固定的思路,这种左右匹配的问题都可以尝试栈方法。
2、因为*有三个意思,所以在存储的时候,“(“单独一个栈, *单独一个栈
3、扫描的时候,优先匹配含义明确的,就是扫到“(“入栈,扫到 * 入栈,扫到“)“,优先匹配含义明确的“(“,等“(“都没了,再把匹配另一个栈,两个栈都空了,则肯定出错,因为右括号多了。
4、最难的问题来了,现在串扫描完了,如果左括号栈空了,则刚刚好,星号栈不用管,剩下的全当成是空串,返回true。当二者都不空时候,这里就要注意了,不是所有的星号都可以转化右括号将左括号栈里的元素抵消,二者有固定的相对位置要求,即左括号必须在右括号右面。所以我们需要存贮吗,每个字符的位置,栈里面如果存字符本身没用的,所以不存字符了,存位置,这样就知道相对位置信息了。(位置序号严格递增的)
5、最后目标就是用星号干掉剩下的左括号,比较之前看一下位置信息,不符合的话(即左括号位置大于所有星号位置),那么肯定不合法

2、区间DP

玩DP,先确定为什么是DP,再就是老四样,先找好几个状态,赋初始值,找转移,最后找答案。

确定算法

1、最简单的确定DP问题的方法就是找大小问题并且看二者有无转化方程式。
2、(( * ))对于这么一个玩意,大问题很显然,就是 (( * ))是否合法。字符串合不合法,要看左右括号能否匹配,所以小问题就是左右同时干掉一个即(*) ,所以当小问题合法,且大问题最左最右的符号匹配了,那么大问题也成立了,所以满足小问题推大问题,可以确定算法。

定状态

我们就是看当前区间的端点,以及区间内部小区间,所以仅用i j表示区间端点即可

找初始值(空串或者左一个右一个的字符)

括号匹配,要左边右边共同定,所以初始的时候,空串和 “*” 是固定的,以及 “()” ,"( * " , “ * )”,“**”是合法的,其余的都不合法,这就是初始值。

找转移

1、如果区间端点是相互匹配的,具体匹配看上一条列出的四种,那么大区间的结果完全和小区间一致
即dp[i][j] = dp[i + 1][j - 1];
2、当中间的部分不是合法的,但是因为*的存在所以当添加上两边的新点后,就有可能让整个串合法化,因为区间DP所以这个大串合不合法就要看被划分成的两个小串合法情况(这里这么想:是区间DP,小区间转化成为大区间,所以看大区间状态就只需要枚举小区间)
即dp[i][j] = dp[i][k] && dp[k + 1][j];

找答案

最终结果就是,看整个串的情况时候,他的结果,即dp[0][n - 1]

代码

1:栈

class Solution {
    
    
public:
	stack<int> stack_char_one;//存储(
	stack<int> stack_char_two;//存储*
	bool checkValidString(string s) {
    
    
		int num_s = s.size();
		for (int i = 0; i < num_s; i++) {
    
    //右括号固定对应左括号,*变化多,所以后处理
			switch (s[i]) {
    
    
			case '(':
				stack_char_one.push(i);
				break;
			case '*':
				stack_char_two.push(i);
				break;
			case ')':
				if (stack_char_one.empty() && stack_char_two.empty()) {
    
    
					return false;
				}
				else if (!stack_char_one.empty()) {
    
    
					stack_char_one.pop();
				}
				else if (stack_char_one.empty() && !stack_char_two.empty()) {
    
    
					stack_char_two.pop();
				}
			}
		}
		while (!stack_char_one.empty() && !stack_char_two.empty()) {
    
    
			int one = stack_char_one.top();//取出左括号位置
			stack_char_one.pop();
			int two = stack_char_two.top();//取出右括号位置
			stack_char_two.pop();
			if (one >= two) {
    
    //因为两个栈中的位置序号都是递增的,一旦栈头处左括号序号大,则星号的位置序号都会小于它,所以不合法了
				return false;
			}
		}
		if (!stack_char_one.empty()) {
    
    
			return false;
		}
		return true;
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):
在这里插入图片描述
时间复杂度:O(N)
空间复杂度:O(N)

2:区间DP

注:
1、表示上述四种匹配情况语句:

(s[i] == '(' || s[i] == '*') && (s[i + 1] == ')' || s[i + 1] == '*')

2、
在这里插入图片描述
循环条件控制中,!dp[i][j],这里就是看dp[i][j]有无可能是true。一旦发现立即停止即可

class Solution {
    
    
public:
	bool checkValidString(string s) {
    
    
		int n = s.size();
		if (s.empty()) {
    
    
			return true;
		}
		bool dp[105][105] = {
    
     false };//初始化
		for (int i = 0; i < n; i++) {
    
    //初始化
			if (s[i] == '*') {
    
    
				dp[i][i] = true;
			}
		}
		for (int i = 0; i + 1 < n; i++) {
    
    //初始化
			dp[i][i + 1] = (s[i] == '(' || s[i] == '*') && (s[i + 1] == ')' || s[i + 1] == '*');
		}
		for (int l = 2; l < n; l++) {
    
    
			for (int i = 0, j; i + l < n; i++) {
    
    
				j = i + l;
				if ((s[i] == '(' || s[i] == '*') && (s[j] == ')' || s[j] == '*')) {
    
    
					dp[i][j] = dp[i + 1][j - 1];
				}
				for (int k = i; k < j && !dp[i][j]; k++) {
    
    //区间DP,小区间转化成为大区间,所以看大区间状态就只需要枚举小区间
					dp[i][j] = dp[i][k] && dp[k + 1][j];
				}
			}
		}
		return dp[0][n - 1];
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):
在这里插入图片描述

时间复杂度:O(N^3)
空间复杂度:O(N^2)

题目二:

在这里插入图片描述

解题思路

直接模拟题目要求

代码

class Solution {
    
    
public:
	string reversePrefix(string word, char ch) {
    
    
		int i = 0;
		string ans = "";
		for (; i < word.size(); i++) {
    
    //寻找目标位置
			if (word[i] == ch) {
    
    
				break;
			}
		}
		if (i == word.size()) {
    
    
			return word;//没找到
		}
		for (int j = i; j >= 0; j--) {
    
    //做新串
			ans += word[j];
		}
		for (int j = i + 1; j < word.size(); j++) {
    
    
			ans += word[j];
		}
		return ans;
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

时间复杂度:O(N)

题目三

在这里插入图片描述

思路:

1、按照要求,求出比值序列
2、一定注意,一个组数,一旦很混乱,则难以找规律,所以先排序,把一样的数放在一块
3、然后动态的找数字相同的有多少个,在用公式计算有多少种匹配方式即可。

代码:

注:
1、一定注意,题目中数据规模很大,并且他给的接口返回值long long,就知道他这里肯定数据量极大,所以全部int换成long long

class Solution {
    
    
public:
	long long factorial(long long  n) {
    
    //匹配数目计算函数
		return ((1 + n)*n) / 2;
	}

	long long interchangeableRectangles(vector<vector<int>>& rectangles) {
    
    
		long long ans = 0;
		long long  n = rectangles.size();
		vector<double> item;
		for (long long i = 0; i < n; i++) {
    
    
			item.push_back((rectangles[i][0] * 1.0) / rectangles[i][1]);//按照要求求
		}
		sort(item.begin(), item.end());//数据整理
		long long cnt = 1;
		double tmp = item[0];
		for (long long i = 1; i < item.size(); i++) {
    
    //动态查找
			if (item[i] == tmp) {
    
    
				cnt++;
			}
			else {
    
    
				if (cnt <= 1) {
    
    //点出现次数少于1,不会产生匹配
					cnt = 1;
					tmp = item[i];
				}
				else {
    
    
					tmp = item[i];
					ans += factorial(cnt - 1);
					cnt = 1;
				}
			}
		}
		ans += factorial(cnt - 1);
		return ans;
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):
在这里插入图片描述

时间复杂度:O(N)

猜你喜欢

转载自blog.csdn.net/qq_45678698/article/details/120252657
678
今日推荐