目录
移除链表元素
解题思路:
遍历链表,如果节点值等于val就删除,删除时要先保存好prev前一个指针和next下一个指针。
其中最要注意的是头节点的保存:如果头节点等于要删除的节点,头节点要改变。
prev指针:若在该节点删除,则不用后移,若没删除,则后移,这里我才用flag来显示有没有删除。
struct ListNode* removeElements(struct ListNode* head, int val){
if(head==NULL)
{
return NULL;
}
struct ListNode*newhead=head;
struct ListNode* cur=head;
struct ListNode*prev=NULL;
int flag=1;
while(cur)
{ flag=1;
struct ListNode*next=cur->next;
if(cur->val==val)
{
if(cur==newhead)
{
free(cur);
newhead=next;
flag=0;
}
else
{
free(cur);
prev->next=next;
flag=0;
}
}
if(flag)
{
prev=cur;
}
cur=next;
}
return newhead;
}
反转链表
解题思路:
三指针法:prev保存前一个节点,cur保存当前节点,next保存下一个节点。
每两个节点反转一次,cur的next指针指向prev,然后把cur的值赋给prev,next的值赋给cur。
当cur=null时结束。
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL)
{
return NULL;
}
struct ListNode*prev=NULL;
struct ListNode*cur=head;
struct ListNode* next=NULL;
while(cur)
{
next=cur->next;
cur->next=prev;
prev=cur;
cur=next;
}
return prev;
}
链表的中间结点
解题思路:
数组保存地址:
遍历一遍链表,将链表中节点地址保存到数组中,最后返回数组中值,也就是中间节点。
快慢指针:
慢指针slow一次走一步,快指针一次走两步,当fast走完,slow的位置就是中间节点。
注意奇偶:奇数结束条件:fast->next=null;偶数结束条件fast=null。
struct ListNode* middleNode(struct ListNode* head){
if(head==NULL)
{
return NULL;
}
//用数组保存地址
// struct ListNode*a[100]={0};
// struct ListNode*cur=head;
// int i=0;
// while(cur)
// {
// a[i++]=cur;
// cur=cur->next;
// }
// return a[(i/2)];
//不创建空间
//快慢指针
struct ListNode*slow=head;
struct ListNode*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
链表中倒数第k个节点
解题思路:
快慢指针:
fast指针先走k步,然后slow指针再开始走,当fast走到空为止。
路程差为n-k,所以slow的位置就是倒数第k个节点。
注意:fast如果先走k步就走到空,就说明k>n,直接返回空!
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
struct ListNode*fast=pListHead;
struct ListNode*low=pListHead;
while(k--)
{
if(fast==NULL)
{
return NULL;
}
fast=fast->next;
}
while(fast)
{
fast=fast->next;
low=low->next;
}
return low;
}
合并两个有序链表
解题思路:
创建一条新链表,设置头尾节点,利用尾节点进行尾插。
采用归并思想,list1和list2的val进行比较,谁小就尾插谁。
当list1和list2中有一个为空时,结束遍历,将不为空的链表链接到尾。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* newlist=NULL;
struct ListNode *tail=NULL;
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
//先比一次把头节点设置好
if(list1->val<list2->val)
{
newlist=tail=list1;
list1=list1->next;
}
else{
newlist=tail=list2;
list2=list2->next;
}
//采用归并思想,谁小连接谁
while(list1!=NULL&&list2!=NULL)
{
if(list1->val<list2->val)
{
tail->next=list1;
tail=list1;
list1=list1->next;
}
else
{
tail->next=list2;
tail=list2;
list2=list2->next;
}
}
//链接尾:尾连接上不为空的那条链表
if(list1==NULL)
{
tail->next=list2;
}
if(list2==NULL)
{
tail->next=list1;
}
return newlist;
}
链表分割
解题思路:
建立两条链表,一条保存val<x,另一条保存val>x,最后将两条链表连接起来。
注意:val>x那条链表的尾一定要置空!否则可能造成死循环。
class Partition
{
public:
ListNode* partition(ListNode* pHead, int x)
{
ListNode*newlist1,*newlist1tail,*newlist2,*newlist2tail;
//设置哨兵节点
newlist1tail=newlist1=(struct ListNode*)malloc(sizeof(ListNode));//val<x
newlist2tail=newlist2=(struct ListNode*)malloc(sizeof(ListNode));//val>x
struct ListNode*cur=pHead;
//创建两条链表
while(cur)
{
if(cur->val<x)
{
newlist1tail->next=cur;
newlist1tail=cur;
}
else{
newlist2tail->next=cur;
newlist2tail=cur;
}
cur=cur->next;
}
newlist2tail->next=NULL;//注意这里,val>x那条链表为要置空,不然造成循环
newlist1tail->next=newlist2->next;
struct ListNode* returnhead=newlist1->next;
free(newlist1);
free(newlist2);
return returnhead;
}
};
链表的回文结构
解题思路:
综合前面几题:
1.先找到中间节点。
2.将中间节点后半部分逆序,使之成为两条链表。
注意:只要逆序中间节点及后半部分,前半部分不要动!
例:
只要两链表有一个为空就结束。
3.对这两条链表遍历比较。
class PalindromeList {
public:
bool chkPalindrome(ListNode* A)
{
// write code here、
ListNode*slow=A;
ListNode*fast=A;
//快指针走两步,满指针走一步,找到中间节点
//若有两个中间节点,则返回后一个!
while(fast)
{
slow=slow->next;
if(fast->next)
{
fast=fast->next->next;
}
else
{
break;
}
}
//反转后半部分
ListNode*next=NULL;
ListNode*prev=NULL;
ListNode*cur=slow->next;
while(cur)
{
next=cur->next;
cur->next=prev;
prev=cur;
cur=next;
}
while(prev&&A)
{
if(A->val!=prev->val)
{
return false;
}
prev=prev->next;
A=A->next;
}
return true;
}
};