题目

c9575d76c3e27ea9b57243ed8697640.png


题目分析

笔试的时候思考流程,我先是想把所有的城市当作节点,存到一个vector数组里面,然后 再对这个vector进行按节点里面的x进行排序,然后依次进行处理,想着维护一个最大城市开销,和一个最大开心值。最后没有在规定时间内写出来,比较遗憾~

提交的代码:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
typedef struct  Node
{
	int x; //表示去i城的花费
	int y;  //开心值
	bool operator <(struct Node n2)
	{
		return 
	}
}Node;

int main()
{
	int n,k;
	cin>>n>>k;
	//存下所有节点数据
	vector<Node> v(n);
	for(int i=1;i<n;i++)
	{
		int x,y;
		cin>>x>>y;
		v[i].x=x;
		v[i].y=y;
	}
	//先排序   降序
	sort(v.begin(),v.end());
//	for(auto val:v)
//	{
//		cout<<val.x<<" "<<val.y<<endl;
//	}
	
	//找x最大的
	int max_val=0;
	int max_x=v[0].x;   //维护一个最大的城市花销
	
	
	
	
	
	
	
	return 0;
}

结束之后写一个新的版本代码来解决这个问题,但是核心的思路还是没有找到

能过测试用例输出是6,核心的算法逻辑没问题 思路:我想着用map存储这个键值对,map插入的都是会有序嘛,可以减少排序的过程,然后一个个去从后往前遍历所有的点,如果和最大的花费差值>k,那么不考虑,如果小于k,就加到维护的max_val变量里面。最后输出max_val得到答案6,这么一初看没啥问题,但是没有考虑到第二大的花销为起点,之后是否有差值>k的。如果在测试环境肯定通过率为0,只能过一个测试用例而已。 如下就是过测试用例的代码

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;


int main()
{
	int n,k;
	cin>>n>>k;
	map<int,int> m1;
	while(n--)
	{
		int x,y;
		cin>>x>>y;
		m1.insert({x,y});
		
	}
	//
	vector<int> max_list(1);
	int i=0;
	//找到x最大值
	auto it = m1.rbegin();
	max_list[i]=it->first;
	int max_val=0;

	for(it=m1.rbegin();it!=m1.rend();it++)
	{
		int val=abs(it->first-max_list[i]);
		if(val<k)
		{
			max_val+=it->second;
			
		}
		
	}
	cout<<max_val<<endl;	
}

上述代码出现的问题: 最大开心值计算逻辑:试图通过遍历 std::map(按照花费降序)并检查当前城市与之前找到的某个城市之间的花费差值是否小于 k 来累加开心值。然而,这种方法未能正确处理题目要求的任意两个城市之间花费差值的绝对值小于 k 这一约束。您只检查了当前城市与单个先前城市之间的差值,而不是所有已选择城市之间的任意两两差值。

下面就是完整的code

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
	std::ios_base::sync_with_stdio(false);
	std::cin.tie(nullptr);
	
	// 读取城市数量和最大花费差值
	int n, k;
	std::cin >> n >> k;
	
	// 初始化一个vector来存储城市信息,使用pair表示每个城市的花费和开心值
	std::vector<std::pair<int, int>> cities(n);
	for (int i = 0; i < n; ++i) {
		std::cin >> cities[i].first >> cities[i].second;
	}
	
	// 按照城市花费对城市列表进行排序
	std::sort(cities.begin(), cities.end());
	
	// 初始化最大开心值和当前开心值
	int maxHappy = 0;
	int curHappy = 0;
	
	// 遍历排序后的城市列表
	for (int i = 0; i < n; i++) {
		int j = i + 1;  // 初始化滑动窗口右边界
		
		// 计算以当前城市(左边界)为中心的子序列开心值
		curHappy = cities[i].second;
		
		// 使用滑动窗口算法,维护一个满足花费差值条件的城市子序列
		while (j < n && cities[j].first - cities[i].first < k) {
			curHappy += cities[j].second;  // 累加右边界城市开心值
			j++;  // 移动滑动窗口右边界
		}
		
		// 更新最大开心值
		maxHappy = std::max(maxHappy, curHappy);
	}
	
	// 输出最大开心值
	std::cout << maxHappy << std::endl;
	
	return 0;
}

为什么要用滑动窗口算法呢,就是题目中能抽取出,相当于原型就是让一段子串保持子串内任意元素之间的差的绝对值小于k即可,那么滑动窗口正好适合,如果遇到的下一个城市不满足这个条件就出窗口,更新最大开心值,如果符合就去累加当前的开心值,并扩大窗口。

总结

大厂的笔试题,考察的算法难度还是相对比较大的,其次不是单纯的算法原型题,而是会带有一定的情景去考察,首先我觉得就是要能大概猜或则想出,这里能用什么算法去ac,或则有没有比较稳妥办法保证能ac,如果没法子了就想想算法能不能去优化。