实习生笔试

第一题:题目是一个长为n的数组(非负数),元素i左边找到比i大的最大值left_max,右边找到比i小的最大值right_max,如果left_max是right_max整数倍,则i是有价值的数,输出数组一共多少有价值的数?

刚开始我只想到暴力法(只通过了系统部分测试用例,时间复杂度太高了,没有AC):

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{

	int n;
	cin >> n;
	vector<int>a(n);
	for (int i = 0; i<n; i++)
		cin >> a[i];
	vector<int>left(n, -1);//left[i]记录a[i]左侧大于a[i]的最大数
	vector<int>right(n, -1);//right[i]记录a[i]右侧小于a[i]的最大数
	for (int i = 1; i<n; i++)
	{
		for (int j = 0; j<i; j++)
		{
			if (a[i]<a[j])
			{
				left[i] = max(left[i], a[j]);
			}
		}
	}
	for (int i = 0; i<n - 1; i++)
	{
		for (int j = i + 1; j<n; j++)
		{
			if (a[i]>a[j])
			{
				right[i] = max(right[i], a[j]);
			}
		}
	}
	int res = 0;
	for (int i = 1; i<n - 1; i++)
	{
		if (left[i] != -1 && right[i] != -1)
			if (left[i] % right[i] == 0)
			{
				res++;
			}
	}
	cout << res << endl;

	system("pause");
	return 0;

}

后来交了卷马上就想到了改进方法,好气啊,为什么偏偏交卷了以后马上就想到了!!!,其实这题可以在暴力法的基础上加上一点动态规划的思路,就可以把算法时间复杂度从O(n2)降到O(n)。
自己改进后的代码如下:

int main()
{

	int n;
	cin >> n;
	vector<int>a(n);
	for (int i = 0; i < n; i++)
		cin >> a[i];
	vector<int>left(n, -1);//left[i]记录a[i]左侧大于a[i]的最大数
	vector<int>right(n, -1);//right[i]记录a[i]右侧小于a[i]的最大数

	//初始化
	if (a[1] < a[0])left[1] = a[0];
	if (a[n - 1] < a[n - 2])right[n - 2] = a[n - 1];

	for (int i = 2; i < n; i++)
	{
		if (a[i] < a[i - 1])
		{
			left[i] = max(left[i - 1], a[i - 1]);
		}

	}
	for (int i = n-2; i >=0; i--)
	{

		if (a[i] > a[i+1])
		{
			right[i] = max(right[i+1], a[i + 1]);
		}
	}
	int res = 0;
	for (int i = 1; i < n - 1; i++)
	{
		if (left[i] != -1 && right[i] != -1)
			if (left[i] % right[i] == 0)
			{
				res++;
			}
	}
	cout << res << endl;

	system("pause");
	return 0;

}

第二题
在这里插入图片描述
例如:
输入:
3 4
9 9 1 1
9 1 1 9
1 1 9 9
输出
4

我的思路是想用dp+回溯,但是感觉这题的难点在于起点和终点都是不确定的,我模型没建出来。只写了一部分代码。
后来我又想到思路了!!好气啊,就是简单的递归!!!

#include<iostream>
#include<vector>
using namespace std;
const int INFINITE = 65536;
void DFS(const vector<vector<int>>&array, vector<vector<int>>&dp, int i, int j, int current_sum, int &res)
{
	//递归结束的条件
	if (i < 0 || j < 0 || j >= array[0].size())
	{
		return;
	}
	//递归结束的条件
	if (i<array.size() && array[i][j] + current_sum > dp[i][j])//如果此时同一个值已经被遍历过并且取值更小,则没必要再对它遍历
	{
		return;
	}
	//递归结束的条件
	if (i == array.size())
	{
		res = min(res, current_sum);
		return;
	}

	//表示当前格子是可以进入的
	//更新dp
	dp[i][j] = current_sum + array[i][j];

	//开启新的子递归
	DFS(array, dp, i + 1, j, current_sum + array[i][j], res);
	DFS(array, dp, i - 1, j, current_sum + array[i][j], res);
	DFS(array, dp, i, j + 1, current_sum + array[i][j], res);
	DFS(array, dp, i, j - 1, current_sum + array[i][j], res);

}
int main()
{
	int res = INFINITE;
	int n, m;
	cin >> n >> m;
	vector<vector<int>>dp(n, vector<int>(m, INFINITE));//dp[i][j]表示从某个起点出发走到(i,j)消耗的体力最小值
	vector<vector<int>>array(n, vector<int>(m, 0));


	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			cin >> array[i][j];
		}
	for (int j = 0; j < m; j++)//m个起点
	{
		DFS(array, dp, 0, j, 0, res);
	}


	cout << res << endl;
	system("pause");
	return 0;
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值