本篇文章涉及到前面文章的相关内容:
本文内容如下:
1.环形链表1
这道题如果我们正常去用指针遍历的话,就会进入死循环
这时如果我们创建两个指针
一个指针一次走两步,另一个指针一次走一步
快指针先进入循环
当慢指针进入循环时,快指针开始追及慢指针
如果相遇就是带环链表
如果有一个走到NULL就是不带环
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode* head) {
struct ListNode *fast = head, *slow = head;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (slow == fast) {
return true;
}
}
return false;
}
理解完思路代码就比较简单了
2.环形链表2
这次问的就点意思了,一共有两种解法:
解法一:数学思维
我们先标明长度关系:
C ————环的长度
L ————进入环前长度
N ————环内相遇到进环的长度
我们通过数学关系就能的到:
此时刚好进环前的距离和相遇后到进环的距离长度是一样的
那么这样创建两个指针,当他俩刚好相遇时就是进环的点
struct ListNode* detectCycle(struct ListNode* head) {
struct ListNode *fast = head, *slow = head, *meet;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (slow == fast) {
meet = fast;
slow = head;
while (slow != meet) {
slow = slow->next;
meet = meet->next;
}
return meet;
}
}
return false;
}
解法二:改为链表相交问题
我们可以在相交的位置将带环链表解开
然后转换为链表相交问题
链表相交问题的解法: C语言数据结构:链表相关题目补充1
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* getIntersectionNode(struct ListNode* headA,
struct ListNode* headB) {
struct ListNode* cur1 = headA;
struct ListNode* cur2 = headB;
int len1 = 1, len2 = 1;
while (cur1->next) {
cur1 = cur1->next;
++len1;
}
while (cur2->next) {
cur2 = cur2->next;
++len2;
}
if (cur1 != cur2) {
return NULL;
}
int a = abs(len1 - len2);
struct ListNode *longList = headA, *shortList = headB;
if (len2 > len1) {
shortList = headA;
longList = headB;
}
while (a--) {
longList = longList->next;
}
while (longList != shortList) {
longList = longList->next;
shortList = shortList->next;
}
return longList;
}
struct ListNode* detectCycle(struct ListNode* head)
{
struct ListNode *fast = head, *slow = head, *meet;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast)
{
meet = fast;
struct ListNode* newhead = meet->next;
meet->next = NULL;
return getIntersectionNode(head,newhead);
}
}
return false;
}
我们将其拆开,然后就是相交链表的计算了
2.随机链表的复制
给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点或空结点。
要求返回这个链表的深度拷贝。
这道题目前只有一个比较好的解法:
- 先将链表正常拷贝下来,无random节点
- 将其尾插在原链表后面
- 实现random的链接
- 将链表拆下来
1.拷贝原链表
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
while(cur)
{
struct Node* copy =(struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
copy->next = cur->next;
}
}
2.将拷贝链表各个节点尾插到原链表中
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
while (cur) {
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
copy->next = cur->next;
cur->next = copy;
cur = copy->next
}
}
3.让创建的链表random节点指向正确的位置
这里恰好复制的节点就是 原链表的random指向的节点的next
while (cur)
{
struct Node* copy = cur->next;
if (cur->random == NULL)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
cur = copy->next;
}
4.最后将节点链表拆下来就行了
struct Node*copyhead = NULL,*copytail=NULL;
cur=head;
while(cur)
{
struct Node *copy =cur->next;
struct Node* next = copy->next;
if(copytail == NULL)
{
copyhead = copytail =copy;
}
else{
copytail->next = copy;
copytail =copytail->next;
}
cur = next;
}
最后汇总到一起就行了:
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
while (cur) {
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
copy->next = cur->next;
cur->next = copy;
cur = copy->next;
}
cur = head;
while (cur)
{
struct Node* copy = cur->next;
if (cur->random == NULL)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
cur = copy->next;
}
struct Node*copyhead = NULL,*copytail=NULL;
cur=head;
while(cur)
{
struct Node *copy =cur->next;
struct Node* next = copy->next;
if(copytail == NULL)
{
copyhead = copytail =copy;
}
else{
copytail->next = copy;
copytail =copytail->next;
}
cur = next;
}
return copyhead;
}