1.力扣208:移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
分析: 1.考虑链表为空的情况 2.考虑头结点等于val的情况
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* newhand = malloc(sizeof(struct ListNode));
newhand->next=head;
struct ListNode*cur=newhand;
if(head==NULL){
return NULL;
}
while(cur->next){
if(cur->next->val!=val){
cur=cur->next;
}
else{
cur->next=cur->next->next;
}
}
return newhand->next;
}
2.力扣206:反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
分析:相当于头删接头插,注意先后顺序即可
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL){
return NULL;
}
struct ListNode* cur=head;
struct ListNode* newhead=NULL;
while(cur){
struct ListNode* fist=cur->next;
cur->next=newhead;
newhead=cur;
cur=fist;
}
return newhead;
}
3.力扣867:链表的中间结点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
分析:经典的快慢指针问题, 快指针=2倍慢指针 1.奇数个结点,当快指针到最后一个结点时慢指针到中间位置 2.偶数个结点,当快指针到NULL时慢指针到两个中间结点的第二个结点 思考:当为偶数个结点,如何返回两个中间结点的第一个结点
struct ListNode* middleNode(struct ListNode* head){
struct ListNode*prev=head,*cur=head;
while(cur&&cur->next){
prev=prev->next;
cur=cur->next->next;
}
return prev;
}
4.剑指offer:链表的倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点。
分析:可以让一个指针从头先走k步,再让另一个指针开始从头走,当快指针到NULL时慢指针到达倒数第K个结点。 1.注意k的范围 0<k<总结点个数 2.如果k大于总结点个数,fist在先走的过程中会到达NULL
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
struct ListNode* fist=pListHead;
struct ListNode* slow=pListHead;
if(k<=0||pListHead==NULL) return NULL;
for(int i=0;i<k;++i){
if(fist==NULL){
return NULL;
}
fist=fist->next;
}
while(fist){
fist=fist->next;
slow=slow->next;
}
return slow;
}
5.力扣21:合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
分析: 1.有一个链表为空可直接返回另一个链表 2.因为要修改头结点,可malloc出一个新结点当头 3.遍历比较两个链表的值,将小的值的结点接到新头后面,知道有一个链表为空,将另一个链表拼接上即可
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
struct ListNode* newhead=malloc(sizeof(struct ListNode));
newhead->next=NULL;
struct ListNode*cur=newhead;
if(l1==NULL) return l2;
if(l2==NULL) return l1;
while(l1&&l2){
if(l1->val>=l2->val){
cur->next=l2;
cur=l2;
l2=l2->next;
}
else{
cur->next=l1;
cur=l1;
l1=l1->next;
}
}
if(l1==NULL) cur->next=l2;
if(l2==NULL) cur->next=l1;
return newhead->next;
}
6.牛客CM11:链表分割
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
分析: 1.可以建立两个头,一个用来链接小值,一个用来链接大值 2.保存两个链表的尾,方便尾插 3.将大值链表链接到小值链表之后
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
struct ListNode* newhead1=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* newhead2=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* cur=pHead;
struct ListNode* tail1=newhead1;
struct ListNode* tail2=newhead2;
while(cur){
if(cur->val<x){
tail1->next=cur;
tail1=tail1->next;
}
else{
tail2->next=cur;
tail2=tail2->next;
}
cur=cur->next;
}
tail2->next=NULL;
tail1->next=newhead2->next;
return newhead1->next;
}
};
7.牛客OR36:链表的回文结构
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。 给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。 测试样例: 1->2->2->1 返回:true
分析: 1.空链表或者链表长度为1一定是回文结构 2.回文结构一定是中心对称的,可以找到链表的中间结点。 3.将中间结点后的链表逆置形成新链表 4.将原链表与逆置的新链表进行比较如果新链表到空即为回文 注意:在进行比较的时候原链表长度>=新链表,所有循环条件为新链表不为空
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
if(A==NULL||A->next==NULL){
return true;
}
struct ListNode *fist=A;
struct ListNode *slow=A;
while(fist&&fist->next){
slow=slow->next;
fist=fist->next->next;
}
struct ListNode *newhead=NULL;
struct ListNode *cur=slow;
while(cur){
struct ListNode* save=cur->next;
cur->next=newhead;
newhead=cur;
cur=save;
}
while(newhead){
if(A->val!=newhead->val){
return false;
}
A=A->next;
newhead=newhead->next;
}
return true;
}
};
|