链表究极分析总结大作战
来源:互联网 发布:tp主人网络与访客网络 编辑:程序博客网 时间:2024/04/28 06:16
1 打印俩个有序链表公共部分
思路
这道题很简单,核心思路就是,如果当L1的值小于L2当前的值,L1一直往后走,直到找到大于等于L2的值,等于输出,大于的话,L2就开始遍历做跟L1一样的事情。
代码
#include<iostream>using namespace std;struct Node{ int _data; Node * next;}void Print(Node * head1 , Node * head2){ assert(head1&&head2); while(head!=NULL&&head2!=NULL) { int temp = head2->_data; while(head&&head2&&head->_data<temp) head = head->next; if(head2&&head&&temp==head->_data) { cout<<temp<<" "; head = head->next; } if(head) temp=head->_data; while(head&&head2&&head2->_data<temp) head2 = head2->next; if(head&&head2&&temp==head2->_data) { cout<<temp<<" "; head2 = head2->next; } }}实现方法2void printf2(Node * head1 , Node *head2){ assert(head1&&head2); while(head1&&head2) { if(head1->_data<head2->_data) head1 = head1->next; else if(head1->_data < head2->_data) head2 = head2->next; else { cout<<head1->_data; head1 = head1->next; head2 = head2->next; } }}
2在单链表中总有N个节点让你删除倒数第K个节点
方法1
删除倒数第K个节点就是让你找到第N-K个节点,仔细想下,让你删除倒数第一个节点,你得找到第N-1个节点,因为第N个节点是最后一个节点,你得找到它前面的那个节点。
找到第N-K个节点的方法,遍历一次链表直到NULL,每次迭代的时候,K值减一。从第一个节点到NULL这个位置,刚好走迭代N次,因为一开始是从第一个节点走的,那么到第N个节点,一共走了N-1步,再走到NULL的时候,刚好迭代了N次。
此时,k的值为k-N , 那么我们现在开始再次遍历链表,每走一次让k+1,直到走到值为0的节点,那个节点就是N-K个节点。因为 (N-K) + (K-N) = 0 , 所以当K走到0的时候,就一共走了N-K步,那么就找到了第N-K个节点。
方法2
先找到倒数第K个节点,然后从头开始走判断下一个节点是否等于它,等于它跳出循环。
找到倒数第K个节点的方法,先让一个快指针走K步,然后慢指针开始走,当fast走到最后一个节点了,那么此时慢指针指向的节点就是倒数第K个节点。
细节总结
如果是第一个方法,K=0就代表被删除节点为头节点。但是对于第二个方法得自己把这个情况先过滤一遍。
Node * DeletelastK(Node*head,int k){ assert(head); if (k < 1) return NULL; Node * pCur = head; Node * del = nullptr; while (pCur) { --k; pCur = pCur->next; } if (k>0) return pCur; else if (k == 0) { del = pCur = head; pCur = head->next; } else { /// 现在 k == K-N , 因为 共走了 N步, 每走一步 K减1 此时 K 的值等于 K - N // 我们 可以让 K加到0 ,然后 让它走 N-K步。找到 第 N-K个节点 ,它就是倒数第K个节点的前一个节点 pCur = head; while (++k < 0) // ++k 是因为直接从1号节点进入,2号节点,所以得先把1号节点那 { //份值减掉 pCur = pCur->next; } del = pCur ->next; pCur = del->next; } delete del; return pCur;}Node *DeletelastK(Node * head, int K){ assert(head != NULL&&K >= 1); Node * fast = head; Node * last = head; while (fast&&--K) { fast = fast->next; } if (K > 0) return NULL; while (fast->next) { fast = fast->next; last = last->next; } /*先找到第K个节点*/ Node * del = head; if (last == head) { del = head; head = head->next; } else { while (del->next != last) { del = del->next; } del->next = last->next; del = last; } delete del; return head;}
删除链表的中间节点和a/b处的节点
思路
方法一先把链表遍历一边,得到链表的长度,然后找到待删节点位置的前一个节点即可。
方法二,慢节点走一步,快节点走俩步,当快节点,走到最后一个位置的时候,慢节点找到待删节点的前一个位置。(最后一个位置可能是最后一个节点,也可能是倒数第二个节点)
题目描述
1->2 删除1 , 1->2->3 删除2 , 1->2->3->4 删除2,这里有个规律就是,如果是偶数就待删除的中间节点就是,N/2处的节点,如果是奇数,待删除节点就是N/2+1的节点。
第二道题待删除节点是这样找的,(N*a)/b 就是待删除位置,这个位置如果小于0就是非法return 即可,否则删除掉。
Node* deleteMid(Node*head){ int Length = 0; Node * pCur =head; while(pCur) { ++Length; pCur = pCur->next; } if(Length==1) { delete head; return NULL; } Length = (Length%2>0)?((Length>>1)+1):Length>>1; Length-=1; Node * del = head; // 下面递归结束 del 就是被删除的前一个节点 while(Length>0&&--Length) { del = del->next; } // -- Length是因为 直接从1号节点出发 所以得先减再判断 if(del == head) { head = head->next; delete del; return head; } del->next = del->next->next; delete del->next; return del;}Node * DeleteMid(Node * head){ if(head==NULL||head->next==NULL) return head; Node * del = NULL; if(head->next->next==NULL) { del = head->next; delete del; } Node * last = head; del = head->next->next; while(del->next&&del->next->next) { last = last ->next; del = del->next->next; } last->next = last->next->next; delete last->next; return last;}/*删除 第 a/b个节点*/Node*removeRatio(Node*head,int a, int b){ if(a/b>1||head==NULL) return head; int N = 0; Node * pCur = head; while(pCur) { N++; pCur=pCur->next; } N = (a*N)/b; pCur = head; if(N==1) { head = head->next; delete pCur; } if(N>1) { while(--N!=1) { pCur=pCur->next; } pCur->next = pCur->next->next; delete pCur->next; } return head;}
反转链表/反转部分链表
思路
定义一个新节点,头插法即刻解决。
第二道题,就是找到部分区间的前一个节点与后一个节点,反转部分节点后,将其再拼接即可。主要细节就是,可能从第一个节点开始反转,则可能更换头节点,所以做个条件过滤即可。
/*反转单链表*/Node * reserve(Node*head){ if(head==NULL) return NULL; Node * NewHead = NULL; Node * pCur =head; Node * pNext = NULL; while(pCur) { pNext = pCur->next; pCur->next = NewHead; NewHead = pCur; pCur = pNext; } return NewHead;}Node* reversepart(Node*head,int from ,int to){ Node * fpre = NULL; Node * Nto = head; int length = 0; Node * pCur = head; int temp=0; while(pCur) { ++length; pCur = pCur->next; } if(from>to||to>N||from<1) return head; temp = from; if(temp != 1) { fpre = head; while(--temp!=1) { fpre = fpre->next; } } temp = to; while(--temp!=-1) { Nto = Nto->next; } Node * pNext = NULL; Node * Newhead = Nto; if(fpre!=NULL) pCur = fpre; else pCur = head; while(pCur!=Nto) { pNext = pCur->next; pCur->next = NewHead; NewHead = pCur; pCur = pNext; } if(fpre) { fpre->next=NewHead; NewHead = head; } return NewHead;}
复杂链表的赋值
方法1
用unordered_map , 保存每一个节点得到指针和新构造出来的节点指针。然后遍历链表的时候,用operator[] 返回对应key的复制出来节点的指针,然后如果这个当前节点next/random有值的话,可以快速从unordered_map中查找到,对应的value就是复制出来的节点,原理很绕口,代码很简单。
方法2
上面的空间复杂度O(n),那么可以不用 unordered_map, 就直接定义临时变量,然后把新复制的节点,放到原节点的后面,设置下一个位置的时候,复制节点的下一个位置就是它的下一个位置的下一个位置,random就是原节点的random的下一个位置。因为它们串插在链表中,所以复制节点的下一个节点是原节点的下一个节点,那么原节点的下一个节点就是复制节点的下一个节点,看代码即可。
方法1:Node* CopyRandList(Node*head){ unordered_map<Node*,Node*> hash; Node * pCur = head; while(pCur) { hash.insert(pair<Node*,Node*>(pCur,new Node(*pCur))); pCur = pCur->next; } pCur = head; while(pCur) { hash[pCur]->next =(pCur->next)?hash[pCur->next]:NULL; hash[pCur]->rand =(pCur->rand)?hash[pCur->rand]:NULL; pCur = pCur->next; } return hash[head];}方法 2 : RandomListNode *copyRandomList(RandomListNode *head) { if(head==NULL) return NULL; Node * Copy =NULL; Node * pCur = head; Node * pNext =NULL; /*复制*/ while(pCur) { Copy = new Node(*pCur); pNext = pCur->next; Copy->next = pNext; pCur->next = Copy; pCur = pNext; } /*设置随机指针*/ pCur = head; while(pCur) { Copy = pCur->next; Copy->random = (pCur->random)?(pCur->random->next):(NULL); pCur = pCur->next->next; } /*拆分*/ pCur = head; pNext = pCur->next;//保存新链表的第一个节点 Copy =pCur->next; while(pCur) { pCur->next = Copy->next; if(Copy->next) { Copy->next = Copy->next->next; Copy = Copy->next; } else { Copy->next = NULL; Copy = NULL; } pCur = pCur->next; } return pNext;}
返回俩个可能带环链表的交点
分析
先判断俩个链表是否带环,如果都带环/都不带环可能有交点否则无交点。
第二步,如果都不带环,进入不带环返回交点的函数。
第三部,都带环,有俩个模型:
模型1与模型2是俩个带环相交的可能情况,模型三是俩个带环不相交的情况。
Node * LoopNode(Node * head){ if(head == NULL) return NULL; Node * fast = head; Node * low = head; while(fast&&fast->next) { fast = fast->next->next; low = low->next; if(low==fast) break; } if(fast==NULL||fast->next==NULL) return NULL; fast = head; while(fast!=low) { fast = fast->next; low = low->next; } return fast;}Node * Associate(Node * head1, Node* head2)//返回俩个不带环链表的交点{ if(head1==NULL||head2==NULL) return NULL; int Length1 = 0; int Length2 = 0; Node * pCur = head1; Node * pCur2 = head2; while(pCur->next) { ++Length1; pCur = pCur->next; } while(pCur2->next) { ++Length2; pCur2 = pCur2->next; } if(pCur!=pCur2) return NULL; Length1+=1; Length2+=2; pCur = (Length1>Length2)? head1 : head2; pCur2 = (Length1<Length2)? head1 : head2; Length1 = (Length1>Length2)?Length1-Length2:Length2-Length1; while(Length1--) { pCur = pCur->next; } while(pCur!=pCur2) { pCur=pCur->next; pCur2 = pCur2->next; } return pCur;}Node * LoopAssociate(Node * head1, Node * head2)//返回俩个可能带环链表的交点{ Node * Loop1 = LoopNode(head1); Node * Loop2 = LoopNode(head2); if(Loop1==NULL&&Loop2==NULL) return Associate(head1,head2); if(Loop1&&Loop2) { if(Loop1==Loop2) // 环入口点相同,说明是俩个带环相交的模型1 return Loop1; Node * pCur = Loop1->next; while(pCur!=Loop1&&pCur!=Loop2)//这里得判断下,俩个带换不一定就 { //相交,如果相交的话,就为模型2,从Loop1转 pCur = pCur->next;//一圈肯定内遇见Loop2,一圈没遇见说明没交点 } if(pCur == Loop2) return Loop2; else return NULL; } return NULL;}
- 链表究极分析总结大作战
- 说说夏日大作战
- make大作战
- 求职大作战1
- 爱情风水大作战
- 选课大作战
- 消除BUG大作战
- 选课大作战
- C 眼力大作战
- 筷子大作战
- 得分大作战
- 贪吃蛇大作战
- OJ_1160.存钱大作战
- 贪吃蛇大作战
- 《跑跑大作战》FLASH完工
- 二维数组折腾大作战
- 博弈论大作战之 PART1
- 博弈论大作战之 PART2
- 串匹配问题经典解法
- 哈尔滨银行拿下这么多行业第一 当然离不开IT系统的创新
- mysqldump: Got error: 1049: Unknown database 'base_name' when selecting the...linux mysql数据库备份的时候报错
- mysql 备份/还原数据库 mysqldump
- gradle+springBoot
- 链表究极分析总结大作战
- 多线程【临界区-临界资源的理解】
- Python必会的单元测试框架 —— unittest
- Mybatis高级映射结果集---xml配置---(一对多,多对一)
- 171124之Oracle的简单语句
- VS2010下编译DSOframer
- 如何在"设置->关于手机"界面添加Logo
- Pt-table-checksum原理浅析
- 自定义圆环进度条,可改变外层圆环颜色,重置与开始