本文介绍几道典型算法题的思路
移除链表元素、反转链表、链表的中间结点、合并两个有序链表、链表分割、链表的回文结构、相交链表以及两种环形链表
思路:以空间换时间,将值不为val的结点拿下来尾插到newhead
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
// 创建新链表
ListNode *newhead = NULL, *newtail = NULL;
ListNode* pcur = head;
while (pcur) {
// 把值不为val的结点插到新的链表中去
if (pcur->val != val) {
// 尾插
// 链表为空
if (newhead == NULL) {
newhead = newtail = pcur;
} else
{
newtail->next = pcur;
newtail = newtail->next;
}
}
pcur = pcur->next;
}
//pcur为空
if(newtail)
newtail->next = NULL;
return newhead;
}
思路:三指针法转向,n1转向,n2,n3后移;
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
if(head == NULL)
{
return head;
}
ListNode*n1,*n2,*n3;
n1 = NULL;
n2 = head;
n3 = n2->next;
while(n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if(n3)
{
n3 = n3->next;
}
}
return n1;
}
思路:快慢指针,慢指针走一步,快指针走两步
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head)
{
ListNode* show = head;
ListNode* fast = head;
while(fast&&fast->next)
{
show = show->next;
fast = fast->next->next;
}
return show;
}
思路:建立新的链表,比较小的尾插进去,遍历结束后,如果哪个不为空,将剩余的全部尾插进去
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if(list1 == NULL)
return list2;
if(list2 == NULL)
{
return list1;
}
ListNode* newhead ,*newtail;
//创建非空链表
newhead = newtail = (ListNode*)malloc(sizeof(ListNode));
ListNode *l1 = list1;
ListNode *l2 = list2;
while(l1 && l2)
{
if(l1->val<l2->val)
{
newtail->next = l1;
newtail = newtail->next;
l1 = l1->next;
}
else{
newtail->next = l2;
newtail = newtail->next;
l2 = l2->next;
}
}
if(l1)
{
newtail->next = l1;
}
if(l2)
{
newtail ->next = l2;
}
ListNode*rehead = newhead->next;
free(newhead);
newhead = NULL;
return rehead;
}
思路:
创建两个子链表:less链表:存储所有值小于x的节点。
great链表:存储所有值大于等于x的节点。 ,避免处理头节点为空的情况。
遍历原链表: 逐个检查每个节点,根据节点值将其添加到对应的子链表末尾。 连接子链表:
将less链表的末尾连接到great链表的头部。 确保great链表的末尾节点的next指针置为NULL,防止成环。
释放虚拟头节点并返回结果: 合并后的链表头为less虚拟头节点的下一个节点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* phead, int x) {
// write code here
ListNode* greathead ,*greattail ;
greathead = greattail= (ListNode*)malloc(sizeof(ListNode));
ListNode* lesshead,*lesstail;
lesshead =lesstail = (ListNode*)malloc(sizeof(ListNode));
ListNode*pcur = phead;
while(pcur)
{
if(pcur->val<x)
{
lesstail->next = pcur;
lesstail = lesstail->next;
}
else {
greattail->next = pcur;
greattail = greattail->next;
}
pcur = pcur->next;
}
greattail->next = NULL;
lesstail->next = greathead->next;
ListNode* ret = lesshead->next;
free(greathead);
free(lesshead);
return ret;
}
};
思路
找到中间结点
反转后半段
遍历链表,将前半段与后半段比较,若相同则为回文结构
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
ListNode* middle(ListNode*A)
{
ListNode* show,*fast;
show = fast = A;
while(fast&&fast->next)
{
show = show->next;
fast = fast->next->next;
}
return show;
}
ListNode* reveselist(ListNode*A)
{
if(A==NULL)
return A;
ListNode* n1,*n2,*n3;
n1 = NULL;
n2 = A;
n3 = A->next;
while(n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if(n3)
{
n3 = n3->next;
}
}
return n1;
}
bool chkPalindrome(ListNode* A) {
// write code here
//找中间结点
ListNode * mid = middle(A);
//反转后半段
ListNode* right = reveselist(mid);
//head与mid比较
ListNode* left = A;
while(right)
{
if(left->val != right->val)
{
return false;
}
left = left->next;
right = right->next;
}
return true;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
//计算两个链表的长度
ListNode* pa = headA;
ListNode* pb = headB;
int sizea = 0;
int sizeb = 0;
while(pa)
{
sizea++;
pa = pa->next;
}
while(pb)
{
sizeb++;
pb = pb->next;
}
//计算差值
int gap = abs(sizea-sizeb);
ListNode* longlist = headA;
ListNode* shortlist = headB;
if(sizea<sizeb)
{
longlist = headB;
shortlist = headA;
}
//让长的一个先走gap步
while(gap--)
{
longlist = longlist->next;
}
//同时遍历,若长的和短的相等,则相交
while(shortlist)
{
if(longlist == shortlist)
{
return shortlist;
}
longlist = longlist->next;
shortlist = shortlist->next;
}
return NULL;
}
思路:快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
ListNode* fast = head;
ListNode* show = head;
while(fast&&fast->next)
{
show = show->next;
fast = fast->next->next;
if(fast == show)
return true;
}
return false;
}
思路:让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
//定义快慢指针
ListNode* show = head;
ListNode* fast = head;
//遍历链表
while(fast&&fast->next)
{
show = show->next;
fast = fast->next->next;
if(show == fast)
{
//找到相遇点
//相遇点和头节点到入环第一个结点的距离相等
ListNode* pcur = head;
//此时fast和slow重合,下面哪个都可以
while(pcur!=fast)
{
fast = fast->next;
pcur = pcur->next;
}
//pcur == fast
return pcur;
}
}
return NULL;
}