王道机试指南刷题记录

P16 2.4
https://www.nowcoder.com/practice/97fd3a67eff4455ea3f4d179d6467de9?tpId=40&tqId=21389&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking
1.这里有一个比较严重的问题,scanf("%d",&d);后面有一个换行符。我们需要getchar();
scanf("%d",&number);
getchar();
在进行这道题的编写的过程中因为这个导致出现了较为严重的错位。
下面是一个demo来处理这样的问题。
首先我们可以使用cin.getline(char * ,int);的方式读入一行中指定位数的字符串。前面一个char *只能使用字符数组。
其次是getchar();消除换行符。

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
	int n=1,size=0;
	while(n)
	{
		cin>>n;		
		if(n==0)
			break; 
		getchar();
		char a[6][6];
		//vector<string> a(6);
		for(int i=0;i<n;i++)
		{
			cin.getline(a[i],6);
			//当然如果非要使用string类,我们可以使用getline方法
			//getline(cin, a[i]);
			//前面固定式cin,后面固定是想输入的字符串
			cout<<"*******"<<endl;
		}
		cin>>size;
		getchar();
		for(int i=0;i<n;i++)
			cout<<a[i]<<endl;
	}
	return 0;
}

2.这里有第二个问题,在模拟的过程中我总是企图递归扩大当前的数据结构的大小,在题目中已经给出确定大小的情况下,我们可以直接开足够大的数组,避免不必要的重复空间开创。
3.同时这里有与上面相关的问题。同样适用开一个二维数组大小的空间,int all[i][j]就是空间比vector<vector > all(i,vector (j) )要小,如果使用后面一种方式会导致内存超限。

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
int all[3003][3003];
void dfs(int now,vector<string> a,int i,int j,int n)
{
	//cout<<"now: "<<now<<" i: "<<i<<" j: "<<j<<endl;
	if(now==1)
	{
		for(int g=0;g<a.size();g++)
		{
			for(int h=0;h<a[g].length();h++)
			{
				if(a[g][h]!=' ')
					all[g+i][h+j]=1;
			}
		}
		return;
	}
	for(int k=0;k<n;k++)
	{
		for(int l=0;l<n;l++)
		{
			int base=pow(n,now-1);
			if(a[k][l]!=' ')
				dfs(now-1,a,i+base*k,j+base*l,n);
		}
	}
}
int main()
{
	int n=1,size=0;
	while(n)
	{
		cin>>n;		
		if(n==0)
			break; 
		getchar();
		vector<string> a(n);
		for(int i=0;i<n;i++)
		{
			getline(cin, a[i]);
			//cout<<a[i].length()<<endl;
		}
		char c;
		for(int i=0;i<n;i++)
		{
			if(a[0][i]!=' ')
				c=a[0][i];
		}
		cin>>size;
		getchar();
		dfs(size,a,0,0,n);
		/*for(int i=0;i<n;i++)
			cout<<a[i]<<endl;*/
		for(int i=0;i<pow(n,size);i++)
		{
			for(int j=0;j<pow(n,size);j++)
			{
				if(all[i][j]==1)
				{
					cout<<c;
					//cout<<all[i][j]<<" ";
					all[i][j]=0;
				}
				else
				{
					//cout<<all[i][j]<<" ";
					cout<<" ";
				}
			}
			cout<<endl;
		}
	}
	return 0;
}

P26
https://www.nowcoder.com/practice/75c189249d6145cfa33cd53edae6afc8?tpId=63&tqId=29579&tPage=1&ru=/kaoyan/retest/9001&qru=/ta/zju-kaoyan/question-ranking
题目本身没有什么好讲的,还是输入的问题。

#include <iostream>
using namespace std;
int main()
{
	int number=-1;
	while(true)
	{
		cin>>number;
		getchar();
		if(number==0)
			break;
		int count=0;
		//cout<<"******************"<<endl;
		while(number!=1)
		{
			//cout<<number<<endl;
			if(number%2==0)
				number/=2;
			else
				number=(3*number+1)/2 ;
			count++;
		}
		cout<<count<<endl;
		//cout<<"******************"<<endl;
	}
	return 0;
}

这个版本的代码本身没有问题,问题在于输入的时候,没有处理好对输入情况的判断。
下面的版本就能解决问题。

#include <iostream>
using namespace std;
int main()
{
	int number=-1;
	while(cin>>number)
	{
		if(number==0)
			break;
		int count=0;
		//cout<<"******************"<<endl;
		while(number!=1)
		{
			//cout<<number<<endl;
			if(number%2==0)
				number/=2;
			else
				number=(3*number+1)/2 ;
			count++;
		}
		cout<<count<<endl;
        //cin>>number;
		//cout<<"******************"<<endl;
	}
	return 0;
}

P28

链接:https://www.nowcoder.com/questionTerminal/fdd6698014c340178a8b1f28ea5fadf8?f=discussion
来源:牛客网

/*本题最重要的逻辑是蚂蚁的相对位置永远不变!!这个逻辑直接推导出了本题的解法之一
 有参考 http://www.cnblogs.com/liangrx06/p/5083868.html
  不过因为没有注解,所以自己写了一点
首先,我们来确定怎么判断蚂蚁不会坠落,有两种情况————
   第一种:静止的蚂蚁两边的蚂蚁都不会碰到这只蚂蚁,也就是说,左边的往左走,右边的往右走
   第二种:蚂蚁的右边有向左走的,左边有向右走的,按照一般的理解一开始静止的蚂蚁一定
   是会掉下去的,但是注意一开始提到的那个逻辑,蚂蚁的相对位置不变,并且移动方向也不变!
   什么意思呢,比如整个树枝上向左走有n个,向右走有m个。那么在任何时间向左走和向右走的
   数量都是n和m,这时候结合蚂蚁的相对位置,在无限的时刻,向左走的n只蚂蚁都掉下了树枝,
   这n只不一定都是原来初始状态向左走的,但一定是一开始左边的n只蚂蚁,因为相对位置不变。
   同理,右边m只也都掉出去了,那么如果n==m,并且静止的蚂蚁左右都有n(m)只。那么,在某个时刻,
   左边n只无论之前是向哪里走的,一定都下去了。
   所以,我们把结论推广,只要静止的蚂蚁左边的蚂蚁数量,等于所有蚂蚁中往左走的数量,
   亦或者右边的等于向右走的那么它就不会掉下去。
     
那么,怎么判断蚂蚁什么时候下去呢
   这时候肯定能确定这只蚂蚁左右数量不等了。接下来就是很巧妙的思想了,如果该蚂蚁
   左边的蚂蚁数量小于向左走的蚂蚁数量,那么它总会加入向左走的大军最后掉落。这时候
   我们宏观的去看,我们定位所有在向左走的蚂蚁,并且定位静止的那只蚂蚁的位置,并且
   标记为k(第k个蚂蚁),这时开始移动,我们看不到蚂蚁之间交换速度,我们只知道他们
   像是穿过对方继续往下走。让蚂蚁继续走,直到某一刻我们观察到第k只向左走的蚂蚁
   掉下去了,暂停。现在考虑所有蚂蚁的相对位置不变!如果是第k个向左走的蚂蚁下去了
   那么他之前的向左走的蚂蚁都下去了,反映到相对位置上来说,就是树枝上左边k-1只都下去了,
   那么这一瞬间掉下去的想必就是相对位置在第k的蚂蚁了————也就是原来静止的那只。
   也就是说一开始所有向左走的蚂蚁中,第k个蚂蚁要走多远,就是最终答案!!
   同样,如果反过来,右边的少于向右走的,也一样,
*/
 
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
 
struct Ant
{
    int position;
    int direct;    //方向
    bool operator < (const Ant &a) const
    {
        return position<a.position;
    }
};
 
int main()
{
    int n;
    while(scanf("%d",&n) != EOF)
    {
        vector<Ant> ant(n);
        for(int i = 0; i<n; i++)
            scanf("%d %d",&ant[i].position,&ant[i].direct);
        sort(ant.begin(),ant.end());
        //接下来要做的就是找到静止的那只的位置,为此我们要先排序
        //这样找到的静止的蚂蚁左边有几只就出来了
        int target,toLeft = 0;    //这里选用向左走的为基准来做
        for(int i = 0; i<n; i++)    //遍历所有蚂蚁
        {
            if(ant[i].direct == 0)
                target = i;
            if(ant[i].direct == -1)
                toLeft++;
        }//现在的target就是静止的蚂蚁左边的数量了
        bool flag = false;
        int ans;
        if(toLeft == target)
            flag = true;
        else if (toLeft > target)//这样的话我们要找的就是所有向左走的蚂蚁中,第target蚂蚁
        {
            int cnt = 0;//计数器
            for(int i = 0; i<n; i++)
            {
                if(ant[i].direct == -1 && cnt == target)
                {
                    ans = ant[i].position;
                    break;
                }
                else if(ant[i].direct == -1)
                    cnt++;
            }
        }
        else    //向左走的蚂蚁少,那么目标蚂蚁会向右落下
        {
            int cnt = 0;
            for(int i = n - 1; i>=0; i--)
            {
                if(ant[i].direct == 1 && cnt == n - target - 1)//相应的变化,cnt要变成静止蚂蚁右边的蚂蚁数量
                {
                    ans = 100 - ant[i].position;
                    break;
                }
                else if(ant[i].direct == 1)
                    cnt++;
            }
        }
        if(flag)
            printf("Cannot fall!\n");
        else
            printf("%d\n",ans);
    }//while
    return 0;
}//main

KMP算法必须要记忆熟练
记录半途吃的亏

#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<int> next;
//vector<int> all;
这里对于目标串并不需要记录。
string a,b;
void countnext()
{
	int j=0;
	next[j]=-1;
	这里的初始化要将对应小指针的置为-1,因为后面要无条件的加一。
	同时要将next[0]的值设为-1,否则无法i=next[i];
	这里j要等于0.因为要匹配的是下一个,而不是当前的,这里i与j指向同一个字符串。
	int i=-1;
	while(j<next.size())
	{
		if(i==-1||a[i]==a[j])
		{
			i++;
			j++;
			next[j]=i;
			记录小坐标的位置
		}
		else
		{
			i=next[i];
		}
	}
	for(int i=0;i<next.size();i++)
	{
		cout<<next[i]<<" ";
	}
	cout<<endl;
	return;
}
int test()
{
	int j=-1,i=-1;
	这里需要注意,后面都有无条件加一,所以这里都要记为-1,以保证比较的方向一致。
	cout<<i<<" "<<j<<endl;
	cout<<a.size()<<" "<<b.size() <<endl;
	int m=a.size();
	int n=b.size();
	while( i<m && j<n )
	{
		cout<<i<<" "<<j<<endl;
		if(i==-1 || a[i]==b[j])
		{
			i++;j++;//all[j]=i;
		}
		else
		{
			i=next[i];
		}
	}
	if(i==m)
	{
		return j-i+1;
	}
	else
		return -100;
}
//as
//asasas

int main()
{
	
	cin>>a>>b;
	//cout<<a<<endl;
	//cout<<b<<endl;
	next=vector<int> (a.length(),-1);
	//all=vector<int>(b.length(),-1);
	countnext();
	cout<<test();
	return 0;
} 

栈的应用:计算器
简单方便的方法:
1.如果是数字,将数字全部输入数字栈。
2.如果是符号,判断当前符号和栈顶符号的优先级,如果比栈顶的大,则压入,否则弹出计算。
注意点:
1.使用while循环,在2的弹出计算的时候不需要index后移,一直判断。
2.在符号栈的栈底压入#,在字符串的末尾加上$.字符串末尾的符号的优先级<栈底符号的优先级<+ -<* /
3.用vector代替栈,这样可以访问每一个元素,队的访问可以用queue这样输出一个push回去一个。

王道机试指南:
最大公约数gcd(a,b)=gcd(b,a%b) 这里要求a>b;
当int t1=b;int t2=a%b;t1%t2==0时,t2为最大公约数。
或者b=0时,return a;
最小公倍数为a*b/gcd(a,b)

小心vector<vector< int > >内存超限。
例如https://www.nowcoder.com/practice/31e539ab08f949a8bece2a7503e9319a?tpId=67&tqId=29638&tPage=1&ru=/kaoyan/retest/1005&qru=/ta/bupt-kaoyan/question-ranking
最好用二维数组代替。

贪心:
https://www.nowcoder.com/questionTerminal/f7eba38f7cd24c45982831e0f38518f9
首先将加油站按照距离升序排列,将重点设置为一个距离为D,油价为0的加油站,如果没有距离为0的加油站,直接输出最大距离为0;
设置当前加油站为now,寻找在最大距离范围内第一个比当前加油站油价低的加油站,加够刚好到达该加油站的油,没有价格更低的则寻找价格最低的,并在当前加油站把油加满;
若最大距离范围内没有能够到达的加油站,那么输出当前加油站距离加上加满油后行驶的最大距离;

#include<iostream>
#include<algorithm>
using namespace std;
 
const int maxn=510;
const int INF=1e9;
 
struct Station{
    double price;
    double dis;
}station[maxn];
 
bool cmp(Station a,Station b){
    return a.dis<b.dis;
}
 
int main(){
    double Cmax,D,Davg;
    int N;
    while(scanf("%lf %lf %lf %d",&Cmax,&D,&Davg,&N)!=EOF){
        for(int i=0;i<N;i++){
            scanf("%lf %lf",&station[i].price,&station[i].dis);
        }
        sort(station,station+N,cmp);
        if(station[0].dis!=0.0){
            printf("The maximum travel distance = 0.00\n");
            continue;
        }
        station[N].dis=D;
        station[N].price=0;
        int now=0;
        double ans=0,nowTank=0,Max=Cmax*Davg; //nowTank为当前剩余油量,Max为行驶最大距离
        while(now<N){
            int k=-1;  //下一个加油站编号
            double minPrice=INF;
            for(int i=now+1;i<=N&&station[i].dis-station[now].dis<=Max;i++){
                if(station[i].price<minPrice){
                    k=i;
                    minPrice=station[i].price;
                    if(station[i].price<station[now].price){
                        break;
                    }
                }
            }
            if(k==-1){  //不存在直接跳出循环
                break;
            }
            double need=(station[k].dis-station[now].dis)/Davg; //当前加油站到达下一个加油站所需油量
            if(minPrice<station[now].price){  //若存在价格更低的加油站,加刚好到达的油
                if(nowTank<need){
                    ans+=(need-nowTank)*station[now].price;
                    nowTank=0;
                }else{   //剩余油量足够到达下一个加油站,那么不用在此站加油
                    nowTank-=need;
                }
            }else{ //没有价格更低的,加满油
                ans+=(Cmax-nowTank)*station[now].price;
                nowTank=Cmax-need;
            }
            now=k;
        }
        if(now==N){
            printf("%.2f\n",ans);
        }else{
            printf("The maximum travel distance = %.2f\n",station[now].dis+Max);
        }
    }
    return 0;
}

P155
二叉树遍历,这道题的二叉树遍历与其他的不同,这里的空树被用#表示出来了,我们可以不需要其他条件直接按照先序遍历的方式进行树的创建。这样当进行到左子树的末尾的时候,因为都是#所以递归被打断,转换到右子树。

#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct node
{
	char value;
	struct node * left;
	struct node * right;
};
string str;
node* build(int &position)
{
	cout<<str[position]<<" "<<position<<endl;
	if(str[position]=='#')
	{
		//position++;
		return NULL;
	}
	node *root=new node;
	root->value=str[position];
	if(position+1<str.length())
		root->left=build(++position);
	if(position+1<str.length())
		root->right=build(++position);
	return root;
}
vector<char> record;
void mid(node *root)
{
	if(root==NULL)
	{
		return ;
	}
	cout<<root->value<<endl;
	mid(root->left);
	record.push_back(root->value);
	mid(root->right);
	return;
}
int main()
{
	node *root=NULL;
	cin>>str;
	cout<<str<<endl;
	int a=0;
	root=build(a);
	mid(root);
	cout<<endl;
	for(int i=0;i<record.size();i++)
	{
		cout<<record[i]<<" ";
	}
	cout<<endl;
	return 0;
}

有一些算法会有一点遗忘,比如迪杰斯特拉+DFS,以及最小生成树,通过前序中序建树。
在建树的过程中我们只有四个参数,前序的开始与终结位置,后续的开始与终结位置。我们需要明白直接使用的数据只有前序的开始的那一个,其他的只是计算出来确定什么时候结束迭代的。

#include <iostream>
#include <vector> 
#include <string>
using namespace std;
string pre,mid;
struct node
{
	char value;
	struct node *left;
	struct node *right;
};
node *build(int prebegin,int preend,int midbegin,int midend)
{
	cout<<prebegin<<" "<<preend<<" "<<midbegin<<" "<<midend<<endl;
	if(prebegin>preend)
		return NULL;
	node * t=new node;
	t->value=pre[prebegin];
	int i=0;
	for(i=midbegin;i<=midend;i++)
	{
		if(mid[i]==pre[prebegin])
		{
			break;
		}
	}
	int number=i-midbegin;
	t->left=build(prebegin+1,prebegin+number,midbegin,i-1);
	t->right=build(prebegin+number+1,preend,i+1,midend);
	return t;
}
vector<char> all;
void inner(node * root)
{
	if(root==NULL)
		return;
	inner(root->left);
	inner(root->right);
	all.push_back(root->value);
	return;
}
int main()
{
	while(cin>>pre)
	{
		cin>>mid;
		node *root=NULL;int i=0;
		root=build(0,pre.size()-1,0,mid.size()-1);
		inner(root);
		for(int i=0;i<all.size();i++)
		{
			cout<<all[i]<<" ";
		}
		cout<<endl;
		all.clear();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值