第二节课:


题目一

在这里插入图片描述
方法一:将数组放入哈希表中;遍历哈希表,每遍历到一个数,在哈希表中查询比他大k的数在不在哈希表中
代码实现:

//方法一
vector<vector<int>> subValueEqualK01(vector<int>& arr, int k) {
	set<int>s;
	vector<vector<int>>res;
	for (int i = 0; i < arr.size(); i++) {
		s.insert(arr[i]);
	}
	//for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
	//	if (s.find(*it + k) != s.end()) {
	//		res.push_back(vector<int>({ *it,*it + k }));
	//	}
	//}

	for (int a : s) {
		if (s.find(a + k) != s.end()) {
			res.push_back(vector<int>({ a,a + k }));
		}
	}
	return res;
}

方法二:对数组进行排序;使用双指针l和r;首先让l和r都指向0位置;r有移动,比较l、r对应位置的差值,如果等于k–>l、r都向右移动,如果小于k–>r向右移动,如果大于k–>l向右移动;直到r在最右侧,并且当前l位置与r位置的差值小于k

代码实现:

//方法二
vector<vector<int>> subValueEqualK02(vector<int>& arr, int k) {
	vector<vector<int>>res;
	sort(arr.begin(), arr.end());
	int l = 0;
	int r = 0;
	while (r < arr.size() && l < arr.size()) {
		if (arr[r] - arr[l] == k) {
			res.push_back(vector<int>({ arr[l],arr[r] }));
			while (r < arr.size() && arr[r] - arr[l] == k) {
				r++;
			}
		}
		else if (arr[r] - arr[l] < k) {
			r++;
		}
		else {
			l++;
		}
	}
	return res;	
}


题目二

在这里插入图片描述
题目大致可以分为,以业务为主的题(笔试:55%;面试:30%):求解完全在于分析这个问题本身,虽然也会用一些技巧加速;以技巧为主的题(笔试45%;面试:70%):主要考察某一技巧/原型会不会,会的话,用一下就解决了。
本题是以以业务为主的题。分类讨论:1) 平均值相同
在这里插入图片描述
2) 平均值不同:只可能将大平均值的集合的数放入小平均值的集合,优先拿符合条件最小的数

在这里插入图片描述
代码实现:

//本题注意coding的技巧
int getSum(vector<int>& arr) {
	int sum = 0;
	for (int i = 0; i < arr.size(); i++) {
		sum += arr[i];
	}
	return sum;
}
double getAver(double sum, int size) {
	return sum / size;
}

int f(vector<int>& a, vector<int>& b) {
	double sumOfA = getSum(a);
	double sumOfB = getSum(b);
	
	if (getAver(sumOfA, a.size()) == getAver(sumOfB, b.size())) {
		return 0;
	}
	if (getAver(sumOfA, a.size()) < getAver(sumOfB, b.size())) {
		int sumOfT = sumOfA;
		sumOfA = sumOfB;
		sumOfB = sumOfT;
		vector<int>tempArr = a;
		a = b;
		b = tempArr;
	}
	sort(a.begin(), a.end());
	set<int>s;
	for (int num : b) {
		s.insert(num);
	}
	int sizeOfA = a.size();
	int sizeOfB = b.size();
	int res = 0;
	for (int i = 0; i < a.size(); i++) {
		double cur = a[i];
		if (cur<getAver(sumOfA, sizeOfA) && cur>getAver(sumOfB, sizeOfB) && s.find(cur) == s.end()) {
			sumOfA -= cur;
			sizeOfA--;
			sumOfB += cur;
			sizeOfB++;
			s.insert(cur);
			res++;
		}
	}

	return res;
}


题目三

在这里插入图片描述
借用上节课的思路:用一个变量count,遇到‘(’count++,遇到‘)’count–,count所能达到的最大值就是这题的解
代码实现:

int depth(string& s) {
	int count = 0;
	int res = 0;
	for (int i = 0; i < s.length(); i++) {
		if (s[i] == '(') {
			count++;
		}
		else {
			res = max(res, count);
			count--;
		}
	}
	return res;
}


题目四

给定一个由左括号和右括号组成的字符串,请找到最长的有效括号子串(连续)
看到子序列/子串/子数组的题目(连续):就求以每个位置结尾的情况下答案是多少,最优答案一定在其中。
动态规划:以左括号结尾不可能有效。假设当前位置i是右括号,求dp[i],看dp[i-1]之前的一个字符是否位左括号,1) 如果是左括号,这dp[i]的值至少为dp[i-1]+2,2) 否则为0.

在这里插入图片描述
在这里插入图片描述
对于1) 如果是左括号,这dp[i]的值至少为dp[i-1]+2,因为在这个左括号之前可能会再接一个有效的字符串,但在这个有效的字符串之前不可能再接一个有效的字符串了,这个有效字符串已经把之前能接的全部接上了

在这里插入图片描述
代码实现:

int f(string& s) {
	if (s.length() < 2) {
		return 0;
	}
	vector<int>dp(s.length());
	int pre = 0;
	int res = 0;
	for (int i = 1; i < s.length(); i++) {
		if (s[i] == '(') {
			dp[i] = 0;
		}
		else {
			pre = i - 1 - dp[i - 1];
			if (pre >= 0) {
				if (s[pre] == ')') {
					dp[i] = 0;
				}
				else {
					dp[i] = dp[i - 1] + 2 + (pre - 1 >= 0 ? dp[pre - 1] : 0);

				}
			}
		}
		res = max(res, dp[i]);
	}
	return res;

}

题目五

在这里插入图片描述
假设原始栈为A,辅助栈为B。想让栈中元素升序排列,则需要在辅助栈中降序排列。从A栈中弹出元素,用一个辅助变量temp存储,如果符合辅助栈的排序规则,则直接压入栈中;否则将栈B中的元素不断弹出并压入栈A中,直到temp可以进入栈B;重复上述操作,直到栈A为空;最后再将栈B中的元素压回栈A。
在这里插入图片描述
代码实现:

void f(stack<int>& a) {
	stack<int>b;
	while (!a.empty()) {
		int temp = a.top();
		a.pop();
		if (b.empty()) {
			b.push(temp);
		}
		else {
			while (!b.empty()&&temp > b.top()) {
				a.push(b.top());
				b.pop();
			}
			b.push(temp);
		}
	}
	while (!b.empty()) {
		a.push(b.top());
		b.pop();
	}
}

题目六

在这里插入图片描述
从左往右的尝试模型:i位置及之后有多少转化方法,所求即为f(0)。怎么做决定?1) s[0]==0,则返回0;2) s[i]!=0,则f(i+1)总有效;3) [i][i+1]<=26,则f(i+2)

在这里插入图片描述
代码实现:

//暴力递归
int p(string& s, int i) {//s[i..]有多少种转法
	if (i == s.length()) {
		return 1;
	}
	if (i > s.length()) {
		return 0;
	}
	if ((s[i]) == '0') {
		return 0;
	}
	int res = 0;
	if (s[i] == '1') {
		res = p(s, i + 1) + p(s, i + 2);
	}
	else if (s[i] == '2') {
		res = p(s, i + 1);
		if (i + 1 < s.length() && s[i + 1] <= '6') {
			res += p(s, i + 2);
		}
	}
	else {
		res = p(s, i + 1);
	}
	return res;
}
int f(string& s) {
	return p(s, 0);
}


//改动态规划
int f2(string& s) {
	vector<int>dp(s.length() + 1);
	dp[s.length()] = 1;
	dp[s.length() - 1] = s[s.length() - 1] == '0' ? 0 : 1;
	for (int i = s.length() - 2; i >= 0; i--) {
		if (s[i] == '0') {
			dp[i] = 0;
		}
		else if (s[i] == '1') {
			dp[i] = dp[i + 1] + dp[i + 2];
		}
		else if (s[i] == '2') {
			dp[i] = dp[i + 1];
			if (s[i + 1] <= '6') {
				dp[i] += dp[i + 2];
			}
		}
		else {
			dp[i] = dp[i + 1];
		}
	}

	return dp[0];
}

题目七

在这里插入图片描述
方法一:先序遍历
代码实现:

class Node {
public:
	int val;
	Node* left;
	Node* right;
	Node(int val) {
		this->val = val;
		this->left = nullptr;
		this->right = nullptr;
	}
};
//方法一:先序遍历
//sum:从根节点到当前节点的路径和
void process(Node* head, int& res, int sum) {
	if (head->left == nullptr && head->right == nullptr) {
		res = max(res, sum + head->val);
		return;
	}
	sum += head->val;
	if (head->left != nullptr) {
		process(head->left, res, sum);
	}
	if (head->right != nullptr) {
		process(head->right, res, sum);
	}
}
int maxWeight(Node* head) {
	if (head == nullptr) {
		return 0;
	}
	int res = INT_MIN;
	process(head, res, 0);
	return res;
}

方法二:二叉树的递归套路
代码实现:

//方法二:套路解
//返回以当前节点为头的最大路径和
int process02(Node* head) {
	if (head->left == nullptr && head->right == nullptr) {
		return head->val;
	}
	int next = INT_MIN;
	if (head->left != nullptr) {
		next = process02(head->left);
	}
	if (head->right != nullptr) {
		next = max(next, process02(head->right));
	}
	return next + head->val;
}


题目八

在这里插入图片描述
有点二分的思想:根据题意,左上角最小,右下角最大,从偏向中间值的右上角开始找,如果当前值比aim大–>aim不可能在当前位置所在行的左边,所以当前位置向下移动;如果当前值比aim小–>aim不可能在当前位置所在列的下边,当前位置向左移动;直到达到左边界或者下边界。时间复杂度:O(M+N)。
在这里插入图片描述

bool f(vector<vector<int>>& arr, int aim) {
	if (arr.size() == 0 || arr[0].size() == 0) {
		return false;
	}
	int M = arr.size();
	int N = arr[0].size();
	int i = 0;
	int j = N - 1;
	while (i < M && j >= 0) {
		if (arr[i][j] == aim) {
			return true;
		}
		if (arr[i][j] < aim) {
			i++;
		}
		else {
			j--;
		}
	}
	return false;
}

题目九

给定一个只包含0和1的矩阵,如果一行即存在0,又存在1,则所有的1在0的右边,返回1数量最多的行。
也是从右上角开始,如果左边有1,则一直向左;不能向左时,向下

在这里插入图片描述

vector<int> f(vector<vector<int>>& arr) {
	if (arr.size() == 0 || arr[0].size() == 0) {
		return vector<int>(1, -1);
	}
	int M = arr.size();
	int N = arr[0].size();
	int i = 0;
	int j = N - 1;
	vector<int>res;
	int cur = 0;//当前找到的最大连续1
	while (i < M && j >= 0) {
		if (j == 0) {
			if (arr[i][j] == 1) {
				res.push_back(i);
			}
			i++;
		}
		else if (arr[i][j] == 1 && arr[i][j - 1] == 1) {
			j--;
		}
		else {
			if (arr[i][j] == 1 && arr[i][j - 1] != 1) {
				if (res.size() == 0 || N - j >= cur) {
					if (N - j > cur) {
						res.clear();
						cur = N - j;
					}
					res.push_back(i);
				}
			}
			i++;
		}
	}
	return res;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值