猿辅导校招(第二批笔试预计8.24,具体以通知为准)
一、校招Q&A
-
提前批 or 秋招 ?
答:前面我不太确定,前几天看到公司的宣传,对,是提前批。 -
提前批影响校招吗?
答:我了解到的,除了华为的提前批会影响,其他的还没听过,部分公司如果走系统确实没过后面没法投,但是像那种组内直招,明确说不走系统的,可以多试试,马上八月了,后面要慢慢进入正式批了,有机会的赶紧试试,毕竟秋招只有一次机会。
关于我司,我不敢明确给你打包票说影响还是不影响,因为我没看到任何相关方面的说明。但是,以我的经验而言,去年八月末我就拿到辅导的offer了,但在我后面,公司九月又组织过一次面试,当时是可以直接发简历给hr的。 -
投递为什么一直不成功?怎么办?
答:有可能前面投过实习等挂过,还处于保护期。这种情况可以尝试把简历发给hr,找不到hr的找到内部员工帮忙转交给hr。 -
提前批先不报,想走秋招?
答:至少我司我是不建议你们这样,毕竟公司研发规模不能跟大公司比,先拿offer就先占坑,前面招的比较理想,后面就更不容易了,反正我不信什么海量hc。去年vivo提前批和内推批招了很多人,发了不少sp,但秋招时,留下的岗位就不多了,拿sp也难了。 -
猿辅导实习真的是日薪800吗?
答: 刚听到这样的说法时,就有人不相信,有人开始酸。我只能说,我实习过,网上那些说法确实是真的。零食饮料、下午茶、年度体检、旅游、每月120的团建费、朝10晚7双休、每月1天的带薪病假、加班免费企业滴滴、餐补等,这些都是真的。 -
内推可以免笔试吗?
答: 简历足够优秀才能直接面试,几乎都需要笔试考察。 -
非985、211有希望吗?
答: 具体这个我不太清楚,我的看法是,校招时比较看重这些硬性指标,这也是公司快速筛选简历的一种方式,正因为这一点也经常被人酸吧,我觉得这一点无可厚非个,毕竟给的钱多,拿到offer的同学也不可能差到哪里去。但之前在脉脉上看到公司是存在非985、211的研发的,更多的是社招吧(个人猜测)。如果是这种情况的同学,但是简历比较漂亮(比如大厂实习、发表论文、做过比较高大上的项目的),也可以投递的试试。 -
笔试、面试难度如何?
答:笔试还好吧,去年笔试在牛客上做的,总时长好像就45分钟(忘了,这里不确定),感觉还好,可以自己搜的看看。面试基础其实问的不是很难,也不算多,但是一定会有手写代码,这是公司选人的一种方式吧,算法题难度我下面会列举我去年的,仅供参考。 -
公司真的不加班吗?
答:公司的上班时间确实是10:00 -- 19:00,双休。到点即可走,没人会强求你留下,但是到8点左右的时候就走的差不多了,部分留下的,一般是在自己充电学习或者有任务急需解决。公司采用敏捷开发,开发效率挺高的,每周都会制定一周每个人需要做的事,任务很明确,比较忙一般是个人任务前松后紧,或者其他业务上的需求。 -
公司技术氛围怎么样?实力如何?
答:技术氛围确实很好,很自由,同事之间关系比较平等,有定期的阅读分享会,开发流程也比较规范。实力如何,这个我不好回答,之前一直在学校,没去过其他公司实习,学习方向也是C++,没有做过JAVA项目,所有无从说起。个人觉得还不错。 -
公司小姐姐多吗?
答:还挺多的,服务端会少点,其他岗位挺多。 - 笔面试时间安排?
二、18猿辅导个人面试算法题(把上一篇帖子的再搬过来)
一面
- 给定一个链表,一个值key,将链表中大于key的值移到链表的后面,保证相对顺序不变,不另开辟空间存储这些大于key的节点。
- 一颗二叉树,转换成按中序遍历的方式连起来看,不能采用记录当前节点的pre节点的方式。
二面
马走日,给定一个数组标识棋盘,给定一个起点,给定一个目标点,如何采用最少的步数走到目标点。如果能,返回最小步数,否则返回-1。
三、校招岗位
方向 | 工作内容 | 岗位要求 | 地点 |
数据开发工程师 |
|
| 北京 |
深度学习研发工程师 |
|
| 北京 |
客户端开发工程师 |
|
| 北京 |
服务端研发工程师 |
| | 北京 |
前端开发工程师 |
| | 北京 |
四、校招内推方式
笔试马上就要开始了,剩下的时间不多了,还没有投的同学快抓紧时间投递啊,不要错过机会了。简历状态工作日更新很快,投递的同学最好留下你的:姓名,不方便留下个人完整信息的,留下姓名的部分即可,状态更新后我会在下面回复。
五、社招及实习内推(应届生或不需要找实习的同学请忽略)
六、贡献点C++常见手写代码
1.赋值操作符(2种写法) CMyString CMyString::operator=(const CMyString &str) { if(this==&str) return *this; delete []m_pData; m_pData=NULL; m_pData=new char[strlen(str.m_pData)+1]; strcpy(m_pData,str.m_pData); return *this; } CMyString& CMyString::operator=(const CMyString &str) { if(this!=&str) { CMyString strTemp(str); Char* pTemp=strTemp.m_pData; strTemp.m_pData=m_pData; m_pData=pTemp; } return *this; } 2.智能指针 shared_ptr实现: template<typename T> class SmartPtr { public: SmartPtr(T *p=0):pointee(p),count(new size_t(t)) {} SmartPtr(const SmartPtr& rhs):pointee(rhs.pointee),count(rhs.count) {++*count;} ~SmartPtr() {decr_count();} SmartPtr& operator=(const SmartPtr& rhs) { ++*rhs.count; decr_count(); pointee=rhs.count; return *this; } T* operator->() {return pointee;} const T* operator->() const {return pointee;} T& operator*() {return *pointee;} const T& operator*() {return *pointee;} size_t get_refCount() {return *count;} private: T* pointee; size_t *count; void decr_count() { if(--*count==0) { delete pointee; delete count; } } }; auto_ptr实现: template<class T> class auto_ptr { public: explicit auto_ptr(T *p = 0): pointee(p) {} auto_ptr(auto_ptr<T>& rhs): pointee(rhs.release()) {} ~auto_ptr() { delete pointee; } auto_ptr<T>& operator=(auto_ptr<T>& rhs) { if (this != &rhs) reset(rhs.release()); return *this; } T& operator*() const { return *pointee; } T* operator->() const { return pointee; } T* get() const { return pointee; } T* release() { T *oldPointee = pointee; pointee = 0; return oldPointee; } void reset(T *p = 0) { if(pointee != p) { delete pointee; pointee = p; } } private: T *pointee; }; 3.strcpy/memmove/memcpy void *memmove(void* dis,const void* src,size_t n) { assert(dst!=NULL&&src!=NULL); char* p=(char*) dst; const char* s=(const char*) src; if(p>=s&&p<=s+n) { p=p+n-1; s=s+n-1; while(n--) *p--=*s--; } else { while(n--) *p++=*s++; } return dst; } void* memcpy(void* dst,const void* src,size_t n); //不处理内存折叠 4.strcat char* strcat(char* dst, const char* src) { char* ret = dst; while(*dst != '\0') ++dst; while((*dst++ = *src++) != '\0'); return ret; } 5.strcmp int strcmp(const char* str1, const char* str2) { while(*str1 == *str2 && *str1 != '\0') { ++str1; ++str2; } return *str1 - *str2; } 6.单例模式 class singleton { public: static singleton* getInstance(); private: singleton() {} static singleton* instance; }; singleton* singleton::instance=new singleton; singleton* singleton::getInstance() { return instance; } 7.堆排序 void heapAdjust(int R[],int l,int h) { int i=l; int j=2*i; int temp=R[i]; while(j<=h) { if(j<h&&R[j]<R[j+1]) j++; if(temp<R[j]) { R[i]=R[j]; i=j; j=2*i; } else break; } R[i]=temp; } void heapSort(int R[],int n) { for(int i=n/2-1;i>=0;i--) heapAdjust(R,i,n-1); //初始建堆 for(int j=n-1;j>=1;j--) { swap(R[1],R[j]); heapAdjust(R,0,j-1) } } 8.快排 int partition(int R[],int l,int r) { int tmp=R[l]; int i,j; i=l,j=r; while(i<j) { While(R[j]>tmp&&j>i) j--; R[i]=R[j]; While(R[i]<tmp&&i<j) i++; R[j]=R[i]; } R[i]=tmp; return i; } 递归: void quickSort(int R[],int l,int r) { if(l<r) { int mid=partition(R,l,r); quickSort(R,l,mid-1); quickSort(R,mid+1,r); } } 非递归: void quickSort(int R[],int l,int r) { stack<int> st; if(l<r) { int mid=partition(R,l,r); if(mid-1>l) { st.push(l); st.push(mid-1); } if(mid+1<r) { st.push(mid+1); st.push(r); } while(!st.empty()) { int end=st.top();st.pop(); int start=st.top();st.pop(); int kmid=partition(R,start,end); if(kmid-1>start) { st.push(start); st.push(kmid-1); } if(kmid+1<end) { s.push(kmid+1); s.push(end); } } } } 9.Top K void findk(int R[],int l,int h,int k) { int p=partition(R,l,h); if(p==k-1) { for(int i=0;i<k;i++) cout<<R[i]<<" "; } else if(p>k-1) findk(R,l,p-1,k); else findk(R,p+1,h,k); } 10.二路归并 void merge(vector<int>&nums,int l1,int r1,int l2,int r2) { int i=l1; int j=l2; int n=(r1-l1+1)+(r2-l2+1); vector<int> temp(n); int k=0; while(i<=r1&&j<=r2) { if(nums[i]<=nums[j]) temp[k++]=nums[i++]; else temp[k++]=nums[j++]; } while(i<=r1) temp[k++]=nums[i++]; while(j<=r2) temp[k++]=nums[j++]; for(int i=0;i<n;i++) nums[l1+i]=temp[i]; } void mergeSort(vector<int>&nums,int start,int end) { if(start<end) { int mid=(start+end)>>1; mergeSort(nums,start,mid); mergeSort(nums,mid+1,end); merge(nums,start,mid,mid+1,end); } } 11.冒泡 void BubbleSort(int R[],int n) { bool flag; for(int i=0;i<n-1;i++) { flag=false; for(int j=0;j<n-i-1;j++) { if(R[j]>R[j+1]) { swap(R[j],R[j+1]); flag=true; } } if(!flag) return; } } 12.直接选择 void SelectSort(int R[],int n) { int k; for(int i=0;i<n;i++) { k=i; for(int j=i+1;j<n;j++) { if(R[k]>R[j]) k=j; } } swap(R[i],R[k]); } 13.有序链表合并 非递归: Node* mergeList(Node* p1,Node* p2) { Node* p=new Node(0); Node* ret=p; while(p1&&p2) { if(p1->val<=p2->val) { p->next=p1; p1=p1->next; } else { p->next=p2; p2=p2->next; } p=p->next; } if(p1) p->next=p1; if(p2) p->next=p2; return ret->next; } 递归: Node* mergeList(Node* p1,Node* p2) { if(p1==NULL) return p2; else if(p2==NULL) return p1; Node* pMergeHead=NULL; if(p1->val<p2->val) { pMergeHead=p1; pMergeHead->next=mergeList(p1->next,p2); } else { pMergeHead=p2; pMergeHead->next=mergeList(p1,p2->next); } return pMergeHead; } 14.二叉树先序遍历(非递归版) 方法1: vector<int> preorder(TreeNode *root) { if(!root) return vector<int>(); stack<TreeNode*> st; st.push(root); vector<int> ret; while(st.size()) { TreeNode* p=st.top(); ret.push_back(p->val); st.pop(); if(p->right) st.push(p->right); if(p->left) st.push(p->left); } return ret; } 方法2: void preorder(TreeNode *root) { stack<TreeNode*> s; TreeNode *p=root; while(p!=NULL||!s.empty()) { while(p!=NULL) { cout<<p->data<<" "; s.push(p); p=p->left; } if(!s.empty()) { p=s.top(); s.pop(); p=p->right; } } } 15.二叉树中序遍历(非递归) vector<int> inorder(TreeNode* root) { if (!root) return vector<int>(); vector<int> ans; stack<TreeNode*> st; TreeNode* cur = root; while (cur || !st.empty()) { while (cur) { st.push(cur); cur = cur->left; } if (!st.empty()) { cur = st.top(); ans.push_back(cur->val); st.pop(); cur = cur->right; } } return ans; } 16.二叉树后序(非递归) vector<int> postorder(TreeNode *root) { if(!root) return vector<int>(); vector<int> ret; stack<TreeNode*> st; st.push(root); while(!st.empty()) { TreeNode* tmp=st.top(); st.pop(); ret.push_back(tmp->val); if(tmp->left) st.push(tmp->left); if(tmp->right) st.push(tmp->right); } reverse(ret.begin(),ret.end()); return ret; } 17.二叉树层次遍历 vector<vector<int>> printLevel(TreeNode* root) { if(!root) return vector<vector<int>>(); vector<vector<int>> ans; queue<TreeNode*> que; que.push(root); while(!que.empty()) { vector<int> tmp; int qsize=que.size(); for(int i=0;i<qsize;i++) { TreeNode* p=que.front(); tmp.push_back(p->val); que.pop(); if(p->left) que.push_back(p->left); if(p->right) que.push_back(p->right); } ans.push_back(tmp); } return ans; } 18.判读是否为同一棵树 bool isEqual(TreeNode* p1,TreeNode* p2) { if(p1==NULL&&p2==NULL) return true; if(p1==NULL||p2==NULL) return false; return (p1->val==p2->val&&isEqual(p1->left,p2->left) &&isEqual(p1->right,p2->right)); } 19.平衡二叉树的判断 方法1: int getDepth(TreeNode* root) { if(!root) return 0; return max(getDepth(root->left),getDepth(root->right))+1; } bool isBlancedTree(TreeNode* root) { if(!root) return true; int left=getDepth(root->left); int right=getDepth(root->right); if(abs(left-right)>1) return false; return isBlancedTree(root->left)&&isBlancedTree(root->right); } 方法2: bool isBlancedTree(TreeNode* root,int &depth) { if(!root) { depth=0; return true; } int left=0,right=0; if(isBlancedTree(root->left,left)&&isBlancedTree(root->right,right)) { if(abs(left-right)<=1) { depth=1+max(left,right); return true; } } return false; } 20.树的子结构判断 bool isSubTree(TreeNode* root1,TreeNode* root2) { if(!root2) return true; if(!root1) return false; if(root1->val!=root2->val) return false; return isSubTree(root1->left,root2->left) && isSubTree(root1->right,root2->right); } bool hasSubTree(TreeNode* root1,TreeNode* root2) { if(!root1 || !root2) return false; bool flag=false; if(root1->val==root2->val) flag=isSubTree(root1,root2); if(flag) return flag; return hasSubTree(root1->left,root2) || hasSubTree(root1->right,root2); } 21.左旋字符串 abcdefg->cdefgab 2位 void reverseStr(string &str,int l,int h) { for(int i=l,j=h;i<=l+(h-l)/2;++i,j--) swap(str[i],str[j]); } string leftRotateString(string str,int n) { int len=str.size(); if(len<=0) return ""; if(n==0) return str; reverse(str,0,n-1); reverse(str,n,len-1); reverse(str,0,len-1); } 22.字符串逆序(递归) void reverse(string &s,int l,int r) { if(l>=r) return; swap(s[l],s[r]); reverse(s,l+1,r-1); } 字符串逆序打印 void reversePrint(string s,int i) { if(s[i]!='\0') { reversePrint(s,i+1); cout<<s[i]; } } 23.二叉树中和为某一值的路径 vector<vector<int>> ans; void findPathStack(TreeNode* root,int expectNumber,int sum,vector<int> vec) { sum+=root->val; vec.push_back(root->val); if(!root->left&&!root->right) { if(sum==expectNumber) ans.push_back(vec); } if(root->left) findPathStack(root->left,expectNumber,sum,vec); if(root->right) findPathStack(root->right,expectNumber,sum,vec); } vector<vector<int>> findPath(TreeNode* root,int expectNumber) { if(!root) return ans; vector<int> vec; findPathStack(root,expectNumber,0,vec); return ans; } 24.二叉搜索树与双向链表 void convertNode(TreeNode* root,TreeNode*& pre) { if(!root) return; if(root->left) convertNode(root->left); root->left=pre; if(pre) pre->right=root; if(root->right) convertNode(root->right); } TreeNode* convert(TreeNode* root) { TreeNode* pre=NULL; convert(root,pre); while(pre&&pre->left) pre=pre->left; return pre; } 25.KMP O(m+n) 0 1 2 3 4 5 6 7 8 str: A B A B A B A B B substr: A B A B A B B next: -1 0 0 1 2 3 4 i=6处不匹配,str、substr的0-5处相同,此时 j=next[j]=4意思指:0-5之间str的2-5与substr的0-3匹配,下一步只需将j=4以后元素与i依次比较 int kmp(string str,string substr,int next[]) { int i=0,j=0; while(i<str.size()&&j<substr.size()) { if(str[i]==substr[j]) { ++i; ++j; } else { j=next[j]; if(j==-1) { j=0; ++i; } } } if(j==substr.size()) return i-substr.size(); } void getNext(string subStr,int next[]) { int i=0,j=-1; next[0]=-1; while(i<subStr.size()) { if(j==-1||subStr[i]==subStr[j]) { ++i; ++j; next[i]=j; } else j=next[j]; } } 26.字符串的全排列 void permutation(string s,int l,int h) { if(l==h) { cout<<s<<endl; return; } for(int i=l;i<=h;i++) { swap(s[i],s[l]); permutation(s,l+1,h); swap(s,l+1,h); } } 用dfs: void perm_dfs(string s,int i,vector<char> &path,vector<int> vis) { if(i==s.size()) { for(auto c:path) cout<<c<<" "; cout<<endl; return; } for(int k=0;k<s.size();k++) { if(vis[k]==0) { path.push_back(s[k]); vis[k]=1; perm_dfs(s,i+1,path,vis); vis[k]=0; path.pop_back(); } } } 27.组合 void combination(char* str,int num,vector<char> &ret) { if(num==0) { for(auto c:ret) cout<<c; cout<<endl; return; } if(*str=='\0') return; ret.push_back(*str); combination(str+1,num-1,ret); //把当前字符放到组合中,从剩下的n-1个字符中选取m-1个字符 ret.pop_back(); combination(str+1,num,ret); //不放入该字符,从剩下的n个字符中选取m-1个字符 } void combination(char* str) { if(str==NULL) return; int len=strlen(str); vector<char> ret; for(int i=1;i<=len;i++) combination(str,i,ret); } 28.二叉树的镜像 递归版: void Mirror(TreeNode* root) { if(!root) return; if(!root->left&&!root->right) return; TreeNode* ptemp=root->left; root->left=root->right; root->right=ptemp; if(root->left) Mirror(root->left); if(root->right) Mirror(root->right); } 非递归版: void Mirror(TreeNode* root) { if(root==NULL) return; stack<TreeNode*> st; st.push(root); while(st.size()) { TreeNode* tree=st.top(); st.pop(); if(tree->left||tree->right) { TreeNode* ptmep=tree->left; tree->left=tree->right; tree->right=ptemp; } if(tree->left) st.push(tree->left); if(tree->right) st.push(tree->right); } } 29.字典树 (大致框架) struct TrieNode { TrieNode* next[26]; bool exist; }; TrieNode* createTrieNode() { TrieNode* node=new TrieNode(); memeset(node->next,0,sizeof(node->next)); node->exist=false; return node; } void TrieInsert(TrieNode* root,string word) { TrieNode* p=root; for(auto c:word) { int id=c-'a'; if(p->next[id]==NULL) p->next[id]=createTrieNode(); p=p->next[id]; } p=p->exist=true; } int TrieSearch(TrieNode* root,string word) { int ans=0; TrieNode* p=root; for(auto c:word) { int id=c-'a'; p=p->next[id]; if(p==NULL) break; if(p->exist) ans++; } return ans; } 31.并查集 关于连通图的例子示意,有多个城市,有些城市之间有道路连接,问至少还需要几条路使得任意城市之间都可以到达 int find(int x) { int r=x; while(r!=pre[r]) r=pre[r]; int i=x,j; while(pre[i]!=r) //路径压缩 { j=pre[i]; pre[i]=r; i=j; } return r; } void mix(int x,int y) { int fx=find(x); int fy=find(y); if(fx!=fy) pre[fy]=fx; } int main() { int n,m,a,b,i,j,ans; //n为城市个数,m为路的条数 while(scanf("%d%d",&n,&m)&&n) { for(i=1;i<=N;i++) pre[i]=i; for(i=1;i<=M;i++) { scanf("%d%d",&a,&b); mix(a,b); } memset(t,0,sizeof(t)); for(i=1;i<N;i++) t[find(i)]=1; for(ans=0,i=1;i<=N;i++) if(t[i]) ans++; printf("%d\n",ans); } } 32.sqrt(n) 牛顿迭代法 double sqrt(double a) { double x=a,y=0; while(fabs(x-y)>0.00001) { y=x; x=0.5*(x+a/x); } return x; } 二分法: int mySqrt(int x) { if(x<=1) return x; long long h=x/2; long long l=2; long long mid=(h+l)>>1; while(l<mid) { if(mid*mid>x) h=mid; else if(mid*mid<x) l=mid; else return mid; mid=(h+l)>>1; } return mid; } 33.洗牌算法 void shuffle(int *a,int n) { for(int i=n-1;i>0;i--) { srand((unsigned)time(NULL)); swap(a[i],a[rand()%(i+1)]); } } 34.单链表快排 ListNode* getpartions(ListNode* pbeg,ListNode* pend) { int k=pbeg->val; ListNode* p=pbeg; ListNode* q=p->next; while(q!=pend) { if(q->val<k) { p=p->next; swap(p->val,q->val); } q=q->next; } swap(p->val,pbeg->val); return p; } void quickSort(ListNode* pbeg,ListNode* pend) { if(pbeg!=pend) { ListNode* partitions=getpartions(pbeg,pend); quickSort(pbeg,partition); quickSort(partition->next,pend); } } quickSort(head,NULL); 35.反转链表 ListNode* reverseList(ListNode* pHead) { if(!pHead||!pHead->next) return pHead; ListNode* p=pHead->next,*pre=pHead; while(p) { pre->next=p->next; p->next=pHead; pHead=p; p=p->next; } return pHead; } 递归版 ListNode* reverseList(ListNode* pHead) { if(!pHead||!pHead->next) return pHead; ListNode* pReverseNode=reverseList(pHead->next); pHead->next->next=pHead; pHead->next=NULL; return pReverseNode; } 36.数据流中的中位数 将数据平均分配到最小堆、最大堆中 维持大顶堆中的数<=小顶堆中的数,且两者的个数相等或差1 priorty_queue<int,vector<int>,less<int>> maxHeap; priorty_queue<int,vector<int>,greater<int>> minHeap; int cnt=0; void insert(int num) { if(cnt%2==0) { if(maxHeap.size()>0&&num<maxHeap.top()) { maxHeap.push(num); num=maxHeap.top(); maxHeap.pop(); } minHeap.push(num); } else { if(minHeap.size()>0&&minHeap.top()<num) { minHeap.push(num); num=minHeap.top(); minHeap.pop(); } maxHeap.push(num); } cnt++; } int getMedian() { if(cnt%2==0) return (minHeap.top()+maxHeap.top())/2; return minHeap.top(); } 37.和为s的连续正数序列 vector<vector<int>> findContinuousSeq(int sum) { vector<vector<int>> ret; int l=1,h=2; while(l<h) { int cur=(h+l)*(h-l+1)/2; if(cur<sum) h++; if(cur==sum) { vector<int> tmp; for(int i=l;i<=h;i++) tmp.push_back(i); ret.push_back(tmp); l++; } if(cur>sum) l++; } return ret; } 38.正则表达式匹配 例:aaa与a.a和ab*ac*a匹配,与aa.a及ab*a不匹配 bool match(char* str,char* pattern) { if(pattern[0]==0&&str[0]==0) return true; if(pattern[0]!=0&&pattern[1]=='*') { if(match(str,pattern+2)) return true; } if((pattern[0]=='.'&&str[0])||str[0]==pattern[0]) { if(match(str+1,pattern+1)) return true; if(pattern[1]=='*'&&match(str+1,pattern)) return true; } return false; } 39.链表中环的入口节点 ListNode *meetingNode(ListNode* head) { if(!head) return NULL; ListNode* pSlow=head->next; if(!pSlow) return NULL; ListNode* pFast=pSlow->next; while(pFast&&pSlow) { if(pFast==pSlow) return pFast; pSlow=pSlow->next; pFast=pFast->next; if(pFast) pFast=pFast->next; } return NULL; } ListNode* entryNodeOfLoop(ListNode* head) { ListNode* meetingNode=meetingNode(head); if(!meetingNode) return NULL; int circle=1; ListNode* p1=meetingNode; while(p1->next!=meetingNode) { p1=p1->next; circle++; } p1=head; for(int i=0;i<circle;i++) p1=p1->next; ListNode* p2=head; while(p1!=p2) { p1=p1->next; p2=p2->next; } return p1; } 40.和为s的两个数字 递增排序的数组 vector<int> twoSum(vector<int> arr,int sum) { vector<int> result; int length=arr.size(); int start=0; int end=length-1; while(start<end) { if(arr[start]+arr[end]==sum) { result.push_back(arr[start]); result.push_back(arr[end]); } else if(arr[start]+arr[end]<sum) start++; else end--; } return result; } 41.N皇后 bool isvalid(int R[],int i,int j) { for(int k=0;k<i;k++) { if(j==R[k]||abs(k-i)==abs(R[k]-j)) return false; } return true; } int process(int R[],int i,int n) { if(i==n) return 1; int res=0; for(int j=0;j<n;j++) { if(isValid(R,i,j)) { R[i]=j; res+=process(R,i+1,n); } } return res; } 42.序列化和反序列化二叉树 char* serialize(TreeNode* root) { if(!root) return "#"; string s=to_string(root->left); s+=","; char* left=serialize(root->left); char* right=serialize(root->right); char* ans=new char[strlen(left)+strlen(right)+s.size()]; strcpy(ans,s.c_str()); strcat(ans,left); strcat(ans,right); return ans; } char* rstr; TreeNode* Deserialize(char* str) { rstr=str; if(*rstr=='#') { rstr++; return NULL; } int val=0; while(*rstr!=',') { val=val*10+*rstr-'0'; rstr++; } rstr++; TreeNode* root=new TreeNode(val); root->left=Deserialize(rstr); root->right=Deserialize(rstr); return root; } 43.未排序正数数组中累加和为给定值的最长子数组长度 arr:1,2,1,1,1 k=3 返回:3 int getMaxLength(int arr[],int n,int k) { if(n<=0||k<=0) return 0; int l=0,r=0; int sum=arr[0]; int len=0; while(r<n) { if(sum==k) { len=max(len,r-l+1); sum-=arr[l++]; } else if(sum<k) { r++; if(r==n) break; sum+=arr[r]; } else sum-=arr[l++]; } } 44.未排序数组中累加和为给定值的最长子数组系列问题 a.无序数组arr,元素可正、可负、可0,给定一个整数k int maxLength(int arr[],int n,int k) { if(n==0) return 0; unordered_map<int,int> map; map[0]=-1; int len=0; int sum=0; for(int i=0;i<n;i++) { sum+=arr[i]; if(map.find(sum-k)!=map.end()) len=max(len,i-map[sum-k]); if(map.find(sum)==map.end()) map.put(sum,i); } return len; } b.求arr所有子数组中正数与负数个数相等的最长子数组长度 方法:整数全部变成1,负数全部变成-1,0不变,然后求累加和为0的最长子数组长度即可 c.求arr中所有的子数组中0和1个数相等的最长子数组长度 方法:0变成-1,1不变,求累加和为0的最长子数组长度即可 45.动态规划相关 背包问题系列 最长递增子序列 最长公共子序列 最长公共子串