牛客网校招刷题
反转单链表
校招开始的第一个题就碰壁,不记得怎么做了。
key point:用三个指针!
提供单链表表头指针p1;
设置新指针p0指向null,设置新指针p2指向pHead->next;
重点是反复利用同一个操作迭代实现单链表转置;
首先识别单链表为空或者只有一个节点的情况,直接返回p1;
实现转置:
p1->next=p0;
p0=p1;
p1=p2;
p2=p1->next
重复操作的条件是直到当前表头是null
即while(p1!=null)
此处有一个易错即当表头是null时,p1->next无意义,又参考以上代码发现可以在判断p1是不是null之后再做p2=p1->next的操作,所以修改为:
while(p1!=null)
{
p2=p1->next;
p1->next=p0;
p0=p1;
p1=p2;
}
return p0;
全部代码如下:
ListNode* ReverseList(ListNode* pHead) {
ListNode *p0=NULL;
ListNode *p1=pHead;
ListNode *p2=p1;
if(p1==NULL||p1->next==NULL)
{
return p1;
}
while(p2!=NULL)
{
p2=p1->next;
p1->next=p0;
p0=p1;
p1=p2;
}
return p0;
}
c++ Vector
遇到一个用vector作为数组的。
学到了以下内容:
vector obj;
obj.size();//数组的长度
obj[i];//访问元素
obj.pushback(i);//把整数i加进vector中;
obj.popback();//去掉数组最后一个数据
我还发现c++排序直接用sort()函数就可以,需要加个头文件:
#include <algorithm>
斐波那切数列
斐波那切数列:0 1 1 2 3 5 8…
按下标从0开始,则第2项开始就可以重复加加数的操作,即定义a=0,b=1,f;
f=a+b;a=b;b=f;
代码如下:
int Fibonacci(int n) {
if(n==0||n==1)
return n;
else
{
int a=0,b=1,f;
while(n!=1)
{
f=a+b;
a=b;
b=f;
n--;
}
return f;
}
}
折半查找(二分查找) 返回最小下标
重要思想就是,定义low、high、mid。
与传统折半查找不同的是,在找到匹配的元素后,要往前找是否有与该元素相等的元素,(直到元素不等于该元素||下标<0)返回下标+1
代码如下:
int search(vector<int>& nums, int target) {
int mid;
int low=0,high=nums.size()-1;
int i;
while(low<=high)
{
mid=(low+high)/2;
if(nums[mid]<target)
{
low=mid+1;
}
else if(nums[mid]>target)
{
high=mid-1;
}
else{
i=mid-1;
while(i>=0&&nums[i]==target)
{
i--;
}
return i+1;
}
}
return -1;
}
快速排序
需要写两个函数,一个Partiton函数,用来返回分隔点
一个QuickSort函数,用来排序,其中QuickSort需要递归自己。
需要注意的问题:
Partiton函数:
控制一遍交换的是:while(low<high)
控制high左移:while(low<high&&a[high]>=temp]) high–;
控制low右移:while(low<high&&a[low]<=emp]) low++;
代码如下:
int Partition(vector<int> &arr,int low,int high)
{
int temp=arr[low];
while(low<high)
{
while(low<high&&arr[high]>=temp) high--;
arr[low]=arr[high];
while(low<high&&arr[low]<=temp) low++;
arr[high]=arr[low];
}
arr[low]=temp;
return low;
}
void QuickSort(vector<int> &arr,int low,int high)
{
if(low<high)
{
int Par=Partition(arr,low,high);
QuickSort(arr,low,Par-1);
QuickSort(arr,Par+1,high);
}
}
vector<int> MySort(vector<int>& arr) {
QuickSort(arr,0,arr.size()-1);
return arr;
}
判断链表是否有环
- 快慢指针法
慢指针走一步,快指针走两步,所以如果链表有环,则快慢指针总能相遇,如果没有环,则快指针先为null。
注意:当链表只有一个元素或为空时需特殊处理,因为空指针->next会报错。
代码如下:
bool hasCycle(ListNode *head) {
ListNode *p=head;
ListNode *q=head;
while(p!=NULL&&p->next!=NULL)
{
p=p->next->next;
q=q->next;
if(q==p)
return true;
}
return false;
}
c++输入格式问题以及容易犯的错误
-多组输入数据,仅按每组第一个输入的数字为while入口,括号内再设置该组其他的输入,其中数组可以以数组长度作为while控制。
- 设置的有意义的变量或者之后要用到的变量不要轻易改变值,最好也不要用嵌套函数,因为在传值时会发生问题。
优先权队列实现求哈夫曼树最小权值和
优先权队列定义:
#include
priority_queue<int ,vector,greater> q1;//greater是构建最小堆,less是最大堆
核心方法:
while(q1.size()>1)
{
int a=q1.top();
q1.pop();
int b=q1.top();
q1.pop();
sum+=a+b;
q1.push(a+b);
}
cout<<sum<<endl;
#include<iostream>
#include<queue>
using namespace std;
int main()
{
int num;
while(cin>>num)
{
int sum=0;
priority_queue<int,vector<int>,greater<int>> Queue;
for(int i=0;i<num;i++)
{
int a;
cin>>a;
Queue.push(a);
}
while(Queue.size()>1)
{
int a=Queue.top();
Queue.pop();
int b=Queue.top();
Queue.pop();
sum+=a+b;
Queue.push(a+b);
}
cout<<sum<<endl;
}
return 0;
}
sort函数和unique函数查找第k小元素
核心代码:
#include
sort(a,a+n);//排序
unique(a,a+n);
cout<<a[k-]<<endl;
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
unique(a,a+n);
int k;
cin>>k;
cout<<a[k-1]<<endl;
return 0;
}
字符串匹配&&结构数组
题目:
一个复数(x+iy)集合,两种操作作用在该集合上: 1、Pop 表示读出集合中复数模值最大的那个复数,如集合为空 输出 empty ,不为空就输出最大的那个复数并且从集合中删除那个复数,再输出集合的大小SIZE; 2 Insert a+ib 指令(a,b表示实部和虚部),将a+ib加入到集合中 ,输出集合的大小SIZE; 最开始要读入一个int n,表示接下来的n行每一行都是一条命令。
输入描述:
输入有多组数据。
每组输入一个n(1<=n<=1000),然后再输入n条指令。
输出描述:
根据指令输出结果。
模相等的输出b较小的复数。
a和b都是非负数。
示例1
输入
3
Pop
Insert 1+i2
Pop
输出
empty
SIZE = 1在这里插入代码片
1+i2
SIZE = 0
分解问题:
- 字符串比较——读入指令字符串,识别是何指令
- POP指令,遍历,输出模值最大,将最大与末位交换,个数减一
- insert 指令,从输入的字符串中提取数字,添加到数组中
代码:
- 构建结构体及结构体数组:
struct stringNum{
string s;
int a;
int b;
}SN[100];
- 输入POP 或者Insert
指令并做出相应的反应,所以需要c++的字符串匹配函数——string.compare(str),当string==str时,为0;当string不等于str时,返回-1
string s;
cin>>s;
if(s.compare("Pop")==0)
{
}else if(s.compare("Insert")==0)
{
}
- 针对输入的字符串提取数字:
for循环遍历字符串,判断字符的ASCII码是否是0-9之间,若是,则初始化s,继续读,并更新s,直到读入的不是数字,即可提取出a和b
string str;
int a,b,s[2]={0};
cin>>str;
for(int i=0,j=0;i<str.length();i++)
{
bool Isnum=false;
while(str[i]>='0'&&str[i]<='9'&&i<str.length())
{
s[j]=s[j]*10+(int)str[i]-(int)'0';
Isnum=true;
i++;
}
if(Isnum)
{
j++;
}
}
简便方法:
int a,b;
scanf("%d+i%d",&a,&b);
使用该简便方法时,需要利用俩整数构建字符串,即:
string s="";
s.append(to_string(a));
s.append("+i");
s.append(to_string(b));
总代码如下:
#include<iostream>
using namespace std;
int N=100;
int M=0;
typedef struct stringNum SNum;
struct stringNum{
string s;
int a;
int b;
}SN[100];
void POP()
{
int j=0;
for(int i=0;i<M;i++)
{
if(SN[i].a*SN[i].a+SN[i].b*SN[i].b>SN[j].a*SN[j].a+SN[j].b*SN[j].b)
j=i;
else if(SN[i].a*SN[i].a+SN[i].b*SN[i].b==SN[j].a*SN[j].a+SN[j].b*SN[j].b&&SN[i].b<SN[j].b)
{
j=i;
}
}
cout<<SN[j].s<<endl;
SNum S=SN[M-1];
SN[M-1]=SN[j];
SN[j]=S;
M--;
cout<<"SIZE = "<<M<<endl;
}
void Insert(int a,int b)
{
M++;
SN[M-1].a=a;
SN[M-1].b=b;
SN[M-1].s="";
SN[M-1].s.append(to_string(a));
SN[M-1].s.append("+i");
SN[M-1].s.append(to_string(b));
cout<<"SIZE = "<<M<<endl;
}
int main()
{
int n;
while(cin>>n)
{
while(n--)
{
string s;
cin>>s;
if(s.compare("Pop")==0)
{
if(M==0)
cout<<"empty"<<endl;
else
POP();
}else if(s.compare("Insert")==0)
{
int a,b;
scanf("%d+i%d",&a,&b);
Insert(a,b);
}
}
}
return 0;
}