牛客网校招刷题笔记(即时更新)

牛客网校招刷题

反转单链表

校招开始的第一个题就碰壁,不记得怎么做了。
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 指令,从输入的字符串中提取数字,添加到数组中

代码:

  1. 构建结构体及结构体数组:
struct stringNum{
    string s;
    int a;
    int b;
}SN[100];
  1. 输入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)
	{
	}
  1. 针对输入的字符串提取数字:
    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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值