目录
练习题1 链表分割
练习题2 链表的回文结构?
练习题3 链表相交?
练习题4 判断是否为环形链表?
快慢指针延伸问题?
?练习题5 找环形链表的节点
?练习题6 复制带随机指针的链表
练习题1 链表分割
点击跳转
?思路:
将链表一分为2,以x为界限,大于x的尾插到新链表1,小于x的尾插到新链表2
,之后再将新链表1,头插到新链表2,跟归并排序有点像
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
ListNode*Guard1=(ListNode*)malloc(sizeof(ListNode));
ListNode*Guard2=(ListNode*)malloc(sizeof(ListNode));
ListNode*tail1=Guard1;
ListNode*tail2=Guard2;
while(pHead)
{
if(pHead->val<x)
{
tail1->next=pHead;
tail1=tail1->next;
}
else
{
tail2->next=pHead;
tail2=tail2->next;
}
pHead=pHead->next;
}
tail1->next=Guard2->next;
tail2->next=NULL;
free(Guard2);
return Guard1->next;
}
};
练习题2 链表的回文结构?
思路:
1.先找到中间节点?
2.从中间节点一直到末尾节点内的节点进行逆置
3. 用俩个节点分别指向头和中间位置,然后挨个进行数字比较,若不想等,直接退出
?注:当奇数时候,第一个2,仍然指向3,因此判断相等
struct ListNode* middleNode(struct ListNode* head){
struct ListNode*fast,*slow;
fast=slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head){
struct ListNode*cur=head;
struct ListNode*prve=NULL;
while(cur)
{
struct ListNode*t=cur->next;
cur->next=prve;
prve=cur;
cur=t;
}
return prve;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
ListNode*mid=middleNode(A);
struct ListNode*rmid=reverseList(mid);
while(A&&rmid)
{
if(A->val!=rmid->val)
return false;
else
{
rmid=rmid->next;
A=A->next;
}
}
return true;
}
};
?方法二:临时拷贝一份,然后一个一个比较
练习题3 链表相交?
160. 相交链表 - 力扣(LeetCode)
?相交链表特点:最后一个节点的地址相等
?方法:1.求俩个出链表的长度,即让俩个链表都走到尾节点
? ? ? ? ? ? 2.求出他们的距离差d
? ? ? ? ? ? 3.较长的链表先走d步,然后俩个链表开始一起走,每次走一步
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *newhead1=headA;
struct ListNode *newhead2=headB;
int k=1;int z=1;int c=0;
while(newhead1->next)
{
newhead1=newhead1->next;
k++;
}
while(newhead2->next)
{
newhead2=newhead2->next;
z++;
}
if(newhead1!=newhead2)
return NULL;
c=abs(k-z);
while(c--)
{
if(k>z)
headA=headA->next;
else
headB=headB->next;
}
while(headA&&headB)
{
if(headA==headB)
return headA;
else
{
headA=headA->next;
headB=headB->next;
}
}
return NULL;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *newhead1=headA;
struct ListNode *newhead2=headB;
int k=1;int z=1;
while(newhead1->next)
{
newhead1=newhead1->next;
k++;
}
while(newhead2->next)
{
newhead2=newhead2->next;
z++;
}
if(newhead1!=newhead2)
return NULL;
int gap=abs(k-z);
struct ListNode *Longlist=headA;
struct ListNode *ShoreList=headB;
if(k<z)
{
Longlist=headB;
ShoreList=headA;
}
while(gap--)
{
Longlist=Longlist->next;
}
while(Longlist!=ShoreList)
{
Longlist=Longlist->next;
ShoreList=ShoreList->next;
}
return Longlist;
}
练习题4 判断是否为环形链表?
141. 环形链表 - 力扣(LeetCode)
?带环链表:1.不能遍历,会陷入死循环
利用快慢指针,快指针一次走俩步,慢指针走一步
?当slow走到中间位置时,fast进入环内
当慢指针进环时,快指针在环内已经走了一小会了,具体走到了哪里,无法知晓?(要根据环的大小决定),但是可以知道fast在环里走的路程,是slow从中间到进环路程的2倍
slow进入环后,看作是fast追赶slow
假设在红色位置fast追上了slow
bool hasCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
return true;
}
return false;
}
快慢指针延伸问题?
?
?证明:slow走一步,fast走俩步,fast能追上slow
假设:slow进环以后,fast和slow之间的差距是N,即追赶距离为N
?slow和fast每移动一次,他们的距离会缩小一格
因此距离由:N,N-1,N-2,N-3……0
所以,能追上
证明:slow走一步,fast走三部,能否追得上
假设:slow进环以后,fast和slow之间的差距是N,即追赶距离为N
一开始fast在3,slow进入圆环
?slow和fast每移动一次,他们的距离会缩小2格,他们的距离N=9
?
此时距离是-1,-1意味着,他们之间的距离变成了C-1(C是环的长度)
最终距离是0还是其他数字,由N决定
如果N是奇数,N=9
9,7,5,3,1,-1
-1意味着,他们之间的距离变成了C-1(C是环的长度)
如果C-1是偶数,即他们的距离是偶数每次-2,一定追得上,如果C-1是奇数,又得去判断下一次C-1是偶数还是奇数
因此,能否追的上如果距离是偶数,则追得上
? ? ? 如果距离是奇数,得看C-1是否为偶
?练习题5 找环形链表的节点
142. 环形链表 II - 力扣(LeetCode)
?方式1.公式证明
用快慢指针:fast走的距离=2*slow的距离
公式推导
假设进环前的长度L,假设环的长度C,入口点到相遇点距离x
?slow所走距离:L+X,慢指针所走的距离不可能超过一圈,因为N最大是C-1
fast所走距离:L+NC+X,N代表fast走过的圈数,N>=1
2(L+X)=L+X+NC
(L+X)=NC
L=NC-X
L=(N-1)*C+C-X
左边是A所走距离,右边是B所走距离
可证明:一个指针A从头开始走,另一个指针B从相遇点开始走,最终会在入口点相遇
struct ListNode* detectCycle(struct ListNode* head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
struct ListNode* meetnextl =NULL;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
{
meetnextl = fast;
while(head!=meetnextl)
{
meetnextl=meetnextl->next;
head=head->next;
}
return head;
}
}
return NULL;
}
方法2:转换成相交问题
fast旁白的黑色是相遇点,下面蓝色是相遇点的下一个点,A和B链表的交点,就是入口点?,
然后让长的先走,接着同时走,跟上面的题一样
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *newhead1=headA;
struct ListNode *newhead2=headB;
int k=1;int z=1;
while(newhead1->next)
{
newhead1=newhead1->next;
k++;
}
while(newhead2->next)
{
newhead2=newhead2->next;
z++;
}
if(newhead1!=newhead2)
return NULL;
int gap=abs(k-z);
struct ListNode *Longlist=headA;
struct ListNode *ShoreList=headB;
if(k<z)
{
Longlist=headB;
ShoreList=headA;
}
while(gap--)
{
Longlist=Longlist->next;
}
while(Longlist!=ShoreList)
{
Longlist=Longlist->next;
ShoreList=ShoreList->next;
}
return Longlist;
}
struct ListNode *hasCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
return slow;
}
return fast;
}
struct ListNode* detectCycle(struct ListNode* head) {
struct ListNode* guard1 = hasCycle(head);
if(guard1==NULL)
return NULL;
struct ListNode*fast=head;
struct ListNode*slow=head;
struct ListNode* meetnextl =NULL;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
{
meetnextl = fast->next;
fast->next=NULL;
struct ListNode* guard2 = getIntersectionNode(head, meetnextl);
return guard2;
}
}
return NULL;
}
?练习题6 复制带随机指针的链表
138. 复制带随机指针的链表 - 力扣(LeetCode)
?思路:
1.先拷贝各个节点,插到相对应的节点后面,然后将链表连接起来
?2.然后将cur的random所指指针赋值给copy的random
if(cur->random!=NULL)
copy->random=cur->random->next
3.将各节点拷贝下来进行链接,顺便链接原链表
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
struct Node* copyRandomList(struct Node* head) {
struct Node*cur=head;
struct Node* next=NULL;
struct Node*copy=NULL;
while(cur)
{
//1.拷贝一份插入链表内
copy=(struct Node*)malloc(sizeof( struct Node));
next=cur->next;
copy->val=cur->val;
cur->next=copy;
copy->next=next;
cur=next;
}
cur=head;
while(cur)
{ //2.链接random
copy=cur->next;
if(cur->random==NULL)
copy->random=NULL;
else
copy->random=cur->random->next;
cur=cur->next->next;
}
cur=head;
struct Node*newhead=NULL;
struct Node*tail=NULL;
while(cur)
{
copy=cur->next;
next=copy->next;
if(newhead==NULL)
newhead=tail=copy;
else
{
tail->next=copy;
tail=tail->next;
}
cur->next=next;
cur=next;
}
return newhead;
}
|