💕人面只今何处去,桃花依旧笑春风💕
作者:Mylvzi
文章主要内容:详解链表OJ题
题目一:环形链表(判断链表是否带环)
题目描述:
画图分析:
代码实现:
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head,*fast = head;//定义快慢指针
// 进入链表
while(fast && fast->next)//为空,就不含有环
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)//相等,环存在
return true;
}
return false;
}
题目二:相交链表(判断两个链表是否相交)
题目描述:
画图分析:
代码实现:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA = headA,* curB = headB;
int lenA = 1;
int lenB = 1;
//根据尾结点判断是否相交
// 判断尾结点是否相同
while(curA->next)
{
curA = curA->next;
lenA++;
}
while(curB->next)
{
curB = curB->next;
lenB++;
}
if(curA != curB)//不等于,不相交
{
return NULL;
}
//相同,返回公共结点
int gap = abs(lenA - lenB);//得到链表长度差值
struct ListNode*longlist = headA,*shortlist = headB;
if(lenA < lenB)
{
longlist = headB;
shortlist = headA;
}
//先让长的链表走gap步
while(gap--)
{
longlist = longlist->next;
}
while(longlist != shortlist)
{
longlist = longlist->next;
shortlist = shortlist->next;
}
//出循环-->走到公共结点
return longlist;
}
题目三:链表分割(哨兵位使用)
题目描述:
画图分析:
代码实现:
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
//创建哨兵位和两个链表
struct ListNode* lhead,* ltail;//存放比x小的
struct ListNode* ghead,* gtail;//存放比x大的
lhead = ltail =(struct ListNode*)malloc(sizeof(struct ListNode));
ghead = gtail =(struct ListNode*)malloc(sizeof(struct ListNode));
//循环遍历尾插
struct ListNode* cur = pHead;
while(cur)
{
if(cur->val < x)
{
ltail->next = cur;
ltail = cur;
}
else
{
gtail->next = cur;
gtail = cur;
}
cur = cur->next;
}
//不置空,有可能呈环,导致死循环
gtail->next = NULL;
ltail->next = ghead->next;//链接两个链表
struct ListNode* head = lhead->next;
free(lhead);
free(ghead);
lhead = NULL;
ghead = NULL;
return head;
}
};
哨兵位总结:
“哨兵位”是一种特殊的结点,放在链表头结点之前,可以理解为工具人,就告诉你我是结点,不是NULL,但其本身不存储任何数据,为了方便对链表的链接而设置的!
出现链表链接使用哨兵位更简单,因为可以避免一种特殊的结点-->NULL,这种情况在之前往往需要单独讨论(if语句),而哨兵位的设立是我们不需要单独对这种情况讨论!
题目四:链表的回文结构(判断是否时回文链表)
题目要求:
画图分析:
代码实现:
class PalindromeList {
public:
//第二种写法-->头插
struct ListNode* reverseList(struct ListNode* head){
//设置新的头结点,进行头插
struct ListNode* newhead = NULL;
struct ListNode* cur = head;
//头插
while(cur)
{
struct ListNode* next = cur->next;
cur->next = newhead;
newhead = cur;
cur = next;
}
return newhead;
}
struct ListNode* middleNode(struct ListNode* head){
struct ListNode*slow = head,*fast = head;
//开始移动
while(fast && fast->next)
{
fast = fast->next->next;//一次移动两步
slow = slow->next;
}
return slow;
}
bool chkPalindrome(ListNode* head) {
struct ListNode* mid = middleNode(head);//得到中间结点
struct ListNode* rmid = reverseList(head);// 逆置中间结点之后的链表
while(rmid && head)
{
//不等于-->不是回文链表
if(rmid->val != head->val)
return false;
rmid = rmid->next;
head = head->next;
}
return true;
}
};
题目五:环形链表II
题目要求:
画图分析:
思路一:
思路二:
代码实现:
struct ListNode *detectCycle(struct ListNode *head) {
//解法1:分析结论法 L = n*C - X;
struct ListNode* slow,*fast;
slow = fast =head;//刚开始都是从头走
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//带环
if(fast == slow)//相遇
{
struct ListNode* meet = slow;//相遇点
//一个从头走,一个从相遇点走,最后一定会在入口点相遇
while(head != meet)
{
head = head->next;
meet = meet->next;
}
return meet;
}
}
//不带环
return NULL;
}
struct ListNode *detectCycle(struct ListNode *head){
struct ListNode* slow,*fast;
slow = fast =head;//刚开始都是从头走
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)//相遇
{
//两个相交链表,返回其交点
struct ListNode* meet = slow;
struct ListNode* newhead = meet->next;
meet->next = NULL;
//这个地方不能free(meet),因为你接下来算长度还会经过meet
int len1 = 1;
int len2 = 1;
struct ListNode* head1 = head;
struct ListNode* head2 = newhead;
while(head1->next)
{
head1 = head1->next;
len1++;
}
while(head2->next)
{
head2 = head2->next;
len2++;
}
//找出长链表
struct ListNode* longlist = head,*shortlist =newhead;
if(len1 < len2)
{
longlist = newhead;
shortlist = head;
}
int gap = abs(len1 - len2);
//让长的先走gap步
while(gap--)
{
longlist = longlist->next;
}
while(longlist != shortlist)
{
longlist = longlist->next;
shortlist = shortlist->next;
}
return longlist;
}
}
return NULL;
}
题目六:随机链表的深拷贝
题目要求:
画图分析:
代码实现:
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
struct Node* copyRandomList(struct Node* head) {
//1.拷贝
struct Node* cur = head;
while(cur)
{
struct Node* next = cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
//赋值
copy->val = cur->val;
copy->next = next;
cur->next = copy;
//向后走
cur = next;
}
cur = head;//从头来
//2.置 copy random
while(cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if(cur->random == NULL)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
//向后移动
cur = next;
}
//3.解离
struct Node* copyhead = NULL;
struct Node* 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 = next;
//向后走
cur = next;
}
return copyhead;
}