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;
}