array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 PAT 1129 C++版 - 爱码网

PAT 1129 C++版【updating…】

1.题意

实现一个简单的推荐系统。这里的推荐规则如下:

  • 给出一个总的可推荐的数目n
  • 给出一串访问序列,针对该访问序列得到的访问当前商品时的推荐商品。

那么如何生成这个推荐商品序列呢?主要有两点:

  • 已经访问过的商品的最高频商品
  • 如果频率相同,则优先输出较小下标的商品

2.分析

处理这道题,有直接暴力的思想:

  • 直接将所有的已访问商品放到一个结构体数组中,然后每次输入的时候,进行一个排序,然后输出前k个。
    上面的思想虽然简单,但是容易出现测试用例超时的结果。所以这个时候就需要使用换另外的方法。还有更好的方法么?

我们需要思考的是:上面这个思想的代码实现主要的耗时在哪里?通过思想可以知道,主要的耗时操作是在执行sort()。因为如果有N个输入,那么其时间复杂度就是N^2。所以就会导致超时。

3.代码

#include<cstdio>
#include<algorithm>
#include<iostream>

using namespace std;
struct item{
	int index = -1;//表示当前的这个商品的索引 
	int accNum = 0 ;//每种商品的访问量
	int order ;//访问的顺序 
	int isVisit =0;//表示是否访问过 
};

int cmp(item i1,item i2){
	if(i1.accNum == i2.accNum) return i1.index < i2.index ;
	return i1.accNum > i2.accNum;
}

int main(){
	int num,limit;	 
	scanf("%d %d",&num,&limit);
	item it[num];
	int i,j;
	int accItem;
	int k;
	for(i = 0;i< num;i++){//这里的i只是用作控制输入,不作下标用 
		scanf("%d",&accItem);				
		if(i != 0){
			k = min(limit,i);
			sort(it,it+i,cmp);
			printf("%d: ",accItem);
			for(j = 0;j< k;j++){
				if(j != k - 1) 	{									
					printf("%d ",it[j].index);
				}
				else{
					printf("%d",it[j].index);
				}
 			}printf("\n");			
		}
		
		for(j = 0;j< i;j++){
			if(it[j].index == accItem){				
				it[j].accNum++;
				it[j].order = i;//重置order的值 
				break;
			}
		}
		if(j == i){
			it[i].accNum++;
			it[i].index = accItem;//表示这个结构体中访问的就是accItem这一项
			it[i].order = i;				
		}		
	}	
}

4.测试用例

12 3
3 5 7 5 5 3 2 1 8 3 8 12

5.执行结果

PAT 1129 C++版

6.代码优化

6.1 优化1

针对上面的输出,我认为上述的下面这个for()循环去找一个合适的index时出现了问题。

#include<cstdio>
#include<algorithm>
#include<iostream>

using namespace std;
struct item{
	int index = -1;//表示当前的这个商品的索引 
	int accNum = 0 ;//每种商品的访问量
};

int cmp(item i1,item i2){
	if(i1.accNum == i2.accNum) return i1.index < i2.index ;
	return i1.accNum > i2.accNum;
}

int cmp_index(item i1,item i2){
	return i1.index < i2.index ;	
}

int main(){
	int num,limit;	 
	scanf("%d %d",&num,&limit);
	item it[num];
	int i,j;
	int accItem;
	int k;
	
	//使用二分法寻找合适的数字 
	int high ,low ,mid ;
	for(i = 0;i< num;i++){//这里的i只是用作控制输入,不作下标用 
		scanf("%d",&accItem);				
		if(i != 0){
			k = min(limit,i);
			sort(it,it+i,cmp);
			printf("%d: ",accItem);
			for(j = 0;j< k;j++){
				if(j != k - 1) 	{									
					printf("%d ",it[j].index);
				}
				else{
					printf("%d",it[j].index);
				}
 			}printf("\n");			
		}
		
		//将如下的代码修改成使用2分法 
		//但是存在的问题是:如果使用二分法,那么前提得是:it[i].index 呈一个有序的状态,
		//如果这个非有序序列,那么就无法使用二分法 
		sort(it,it+i,cmp_index);
		high = i-1;
		low = 0;		
		while(low <= high){
			mid = (high + low)/2; //求出mid的值
			//printf("mid = %d\n",mid);
			if(it[mid].index < accItem){
				low = mid + 1; 				
			}
			else if(it[mid].index > accItem){
				high = mid - 1;	
			}
			else break;
		}
		
		if(it[mid].index == accItem){//如果当前输入的值已经存在了			
				it[mid].accNum++;			
		}
		else{
			it[i].accNum++;
			it[i].index = accItem;//表示这个结构体中访问的就是accItem这一项							
		}		
	}	
}

所以我决定使用二分法去解决寻找。修改的代码如下:

sort(it,it+i,cmp_index);
		high = i-1;
		low = 0;		
		while(low <= high){
			mid = (high + low)/2; //求出mid的值
			//printf("mid = %d\n",mid);
			if(it[mid].index < accItem){
				low = mid + 1; 				
			}
			else if(it[mid].index > accItem){
				high = mid - 1;	
			}
			else break;
		}

但是得到的结果仍然是运行超时

6.2 优化2

针对上面的运行超时问题,可以大致猜到修改查找index的值不是时间的关键,时间的关键是:sort()。所以转换另外一种思路。使用set + 运算符重载 + 自定义类型 解决这个问题。

  • 代码如下:
#include<cstdio>
#include<set>
#include<iostream>
#include<cstring>

using namespace std;

struct node{
	int cnt;
	int value;
	
	bool operator<(const node &n)const{
		if(n.cnt == cnt) return n.value > value;
		return n.cnt < cnt; 
	}
};

int rate[50005];

int main(){
	int num,limit;	 
	scanf("%d %d",&num,&limit);
	set<node> s;//用于存放浏览记录的 set 
	int i,j;
	int accItem;
	int k;
	node n;//定义一个临时的node 变量 	 
	memset(rate,0,sizeof(rate));//初始化rate数组
	 
	for(i = 0;i< num;i++){//这里的i只是用作控制输入,不作下标用 
		scanf("%d",&accItem);
		
		//遍历这个it,然后得到其中的值 
		k = min(limit,i);//求出输出的项数 
		int size = s.size();
		//cout << "s.size() = "<<s.size()<<endl	; 
		k = min(k,size);
		if(i > 0){
			//cout << "k = "<<k<<endl;
			cout<<accItem<<": ";	
			set<node>::iterator it;
			for(it = s.begin(),j = 0;it !=s.end() && j<k; it++,j++){			
				if(j!=k-1)	cout << it->value<<" ";//输出值 
				else cout<< it->value<<endl;
			}	
		}
				
		n.value = accItem;		
		n.cnt = rate[accItem];
		rate[accItem]++;//现在访问过这个商品了,需要将其访问次数加一
		 
		if(s.find(n) != s.end()){//说明该商品已经浏览过 
			s.erase(n);//删除这个商品 
			//cout<<"找到了这个商品"<<endl;
			//然后再将这个商品添加到set中 					
		}
		n.cnt = rate[accItem];
		s.insert(n);				
	}
}
  • 测试用例
12 10
3 5 7 5 5 3 2 1 8 3 8 12
  • 关键问题
    但是现在的问题是,如果使用find()函数,那么这个set查找的是什么元素呢?(是value还是cnt呢?)答案是:既非cnt,也不是value。而是一个node 变量。所以需要定义 一个临时的node变量 n。然后判断 n 是否 存在于set中。
    同时需要注意输出的格式问题。这里虽然说是输出的格式问题,但是实际上是因为代码考虑不周导致的错误发生。如下图所示,使用该测试用例得到的结果是:
    PAT 1129 C++版
    很明显的可以看到这个输出是有误的,为什么呢?错误的代码如下:
k = min(limit,i);//求出输出的项数 

我这里只考虑了limit,i两者的大小关系,而没有考虑到set本身的大小。所以导致输出格式错误。修改代码如下:

		int size = s.size(); 
		k = min(limit,size);//求出输出的项数 

因为s.size <= i恒成立,所以应该取set 的size和 limit之间的最小值。

  • 执行结果
    PAT 1129 C++版

相关文章: