目录
链表中环的入口结点
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
数据范围: n≤10000n,1<=结点值<=10000
要求:空间复杂度 O(1),时间复杂度 O(n)
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:
可以看到环的入口结点的结点值为3,所以返回结点值为3的结点。
思路:a,b都从头结点开始,a每走一步,b走两步,当a和b相遇时,说明有环,否则若a或b为空则没有环。假设a和b在A点相遇(如下图),则a走了x+y步,b走了2(x+y)步,设环为r步,则2(x+y)=x+y+nr,可得x=nr-y,即b继续从A出发,a从头结点出发,会在B(环的入口)相遇。
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
if(!pHead) return NULL;
cout<<"phead"<<pHead->val<<endl;
ListNode* a=pHead;
ListNode* b=pHead;
a=a->next;
b=b->next->next;
if(!a||!b) return NULL;
while(b&&a&&a!=b){//a走一步,b走两步
a=a->next;
b=b->next->next;
}
if(!a||!b) return NULL;
a=pHead;//a从链表头开始
while(a!=b){//查找环的入口结点
a=a->next;
b=b->next;
}
return a;
}
};
链表中倒数最后第k个结点
输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。
如果该链表长度小于k,请返回一个长度为 0 的链表。
数据范围:0≤n≤10^5,0≤ai≤10^9,0≤k≤10^9
要求:空间复杂度 O(n),时间复杂度 O(n)
进阶:空间复杂度 O(1),时间复杂度 O(n)
例如输入{1,2,3,4,5},2时,对应的链表结构如下图所示:
其中蓝色部分为该链表的最后2个结点,所以返回倒数第2个结点(也即结点值为4的结点)即可,系统会打印后面所有的节点来比较。
思路:a为头结点,b从头结点向后移动到第k个结点,若b为空,则说明链表长小于k;从此时开始a和b同步向后移动相同结点,直到b为最后一个结点,此时a结点为倒数第k个结点。
class Solution {
public:
ListNode* FindKthToTail(ListNode* pHead, int k) {
if(!pHead||k<1) return NULL;
ListNode* a=pHead;
ListNode* b=pHead;
for(int i=1;i<k&&b;i++,b=b->next);
if(!b) return NULL;
while(b->next!=NULL){
a=a->next;
b=b->next;
}
return a;
}
};
复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。
思路:有两种方法,第一个是在遍历建立next链表的同时,利用哈希表保存random指针值,第二个是直接在原链表上将每个结点拷贝一个放在原结点后面,最后将链表一分为二,如下图。
第一种方法:
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead) {
if(!pHead) return NULL;
unordered_map<RandomListNode*, RandomListNode*> mp;
RandomListNode* p=new RandomListNode(0);
RandomListNode* pre=p,*cur=pHead;
while(cur){
RandomListNode* clone=new RandomListNode(cur->label);
pre->next=clone;
mp[cur]=clone;
pre=pre->next;
cur=cur->next;
}
for(auto&[key,value]:mp){
value->random=key->random==NULL?NULL:mp[key->random];
}
delete p;
return mp[pHead];
}
};
第二种方法:
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead) {
if(!pHead) return pHead; // 为空则返回
RandomListNode* cur = pHead;
while(cur){
RandomListNode* tmp = new RandomListNode(cur->label); // 拷贝节点
tmp->next = cur->next;
cur->next = tmp;
cur = tmp->next;
}
RandomListNode *old = pHead, *clone = pHead->next, *ret = pHead->next;
while(old){
clone->random = old->random == NULL ? NULL : old->random->next; // 处理拷贝节点的随机指针
if(old->next) old = old->next->next; // 注意特判空指针
if(clone->next) clone = clone->next->next;
}
old = pHead, clone = pHead->next;
while(old){ // 拆分链表
if(old->next) old->next = old->next->next;
if(clone->next) clone->next = clone->next->next;
old = old->next;
clone = clone->next;
}
return ret;
}
};