1. 力扣21: 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
解题:
方法一
用归并的方式给链表排序
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
//如果一个空的,返回另一个数组
if(NULL == l1) return l2;
if(NULL == l2) return l1;
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
struct ListNode* p = l1;
struct ListNode* q = l2;
//如果两个数组都没空,则排序
while(NULL != p && NULL !=q){
if(p->val < q->val){
//考虑第一个数据插入的情况
if(NULL == head){
head = p;
}else{
tail->next = p;
}
tail = p;
p = p->next;
}else{
if(NULL == head){
head = q;
}else{
tail->next = q;
}
tail = q;
q = q->next;
}
}
//如果哪个数组没空,就把这个数组剩下的全放进来
if(NULL != p) tail->next = p;
if(NULL != q) tail->next = q;
return head;
}
方法二
为了不考虑头指针为空的情况,我们直接加一个头节点
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if(NULL == l1) return l2;
if(NULL == l2) return l1;
struct ListNode dump = {0,NULL};
struct ListNode* tail = &dump;
struct ListNode* p = l1;
struct ListNode* q = l2;
while(NULL != p && NULL !=q){
if(p->val < q->val){
tail->next = p;
tail = p;
p = p->next;
}else{
tail->next = q;
tail = q;
q = q->next;
}
}
if(NULL != p) tail->next = p;
if(NULL != q) tail->next = q;
return dump.next; //返回的是一个指针
}
方法三
可以不用 p 和 q ,直接使用 l1 和 l2 ,删掉重复的判断,减少代码量
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
struct ListNode dump = {0,NULL};
struct ListNode* tail = &dump;
while(NULL != l1 && NULL != l2){
struct ListNode* cur = l1->val < l2->val ? l1:l2;
tail->next = cur;
tail = cur;
if(l1->val < l2->val){
l1 = l1->next;
}else{
l2 = l2->next;
}
}
if(NULL != l1) tail->next = l1;
if(NULL != l2) tail->next = l2;
return dump.next;
}
方法四
换个思路,用递归的方式,返回的都是地址
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if (NULL == l1) return l2;
if (NULL == l2) return l1;
if(l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}else{
l2->next = mergeTwoLists(l1,l2->next);
return l2;
}
}
2. 力扣237: 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为要被删除的节点
解题:
我们不知道要删除的前一个节点,而是当前节点,并且这个节点不是尾节点
我们可以把该结点后面结点的数据移过来,再删除后面的结点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
void deleteNode(struct ListNode* node) {
if(NULL == node || NULL == node->next) return;
struct ListNode* next = node->next; //定义一个指针next,指向当前结点的下一个结点
node->val = next->val; //把下一个结点的值赋给当前结点
node->next = next->next; //把当前结点的指针域指向下下结点的地址
free(next); //释放下一个结点
}
3. 力扣24:两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
解题:
递归写法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* swapPairs(struct ListNode* head){
if(NULL == head) return NULL;
if(NULL == head->next) return head;
struct ListNode* p = head;
struct ListNode* q = head->next;
p->next = swapPairs(q->next);
q->next = p;
return q;
}
4. 力扣19:删除链表的倒数第N个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
解题:
方法一
用传统的方法,找到要删除对象的前一个数
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(NULL == head || n<0) return head;
int size = 0;
struct ListNode* p =head;
while(NULL != p){
++size;
p = p->next;
}
//如果删除的是头结点
if(n == size){
p = head->next;
free(head);
return p;
}
int index = size - n;
p = head;
for(int i=0;i<index-1;++i){ //找到要删除结点的前一个结点
p = p->next;
}
struct ListNode* del = p->next;
p->next = del->next;
free(del);
return head;
}
方法二
再前面增加一个空结点,可以不考虑删除头结点的情况
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(NULL == head || n<0) return head;
int size = 0;
struct ListNode dump = {0,head};
struct ListNode* p = head;
while(NULL != p){
++size;
p = p->next;
}
int index = size - n;
p = &dump;
for(int i=0;i<index;++i){ //找到要删除结点的前一个结点
p = p->next;
}
struct ListNode* del = p->next;
p->next = del->next;
free(del);
return dump.next;
}
方法三
另一种思维:
定义p和q都在链表头,p先跑n,再p和q一起跑,p到最后时,q所在位置就是要删除位置的前一个位置
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(NULL == head || n<0) return head;
struct ListNode dump = {0,head};
struct ListNode* p = &dump;
for(int i=0;i<n;++i){
p = p->next;
}
struct ListNode* q = &dump;
while(NULL != p->next){
p = p->next;
q = q->next;
}
struct ListNode* del = q->next;
q->next = del->next;
free(del);
return dump.next;
}
方法四
使用递归的方式,在归的时候删除
需要新建一个函数用于递归
int NthFromEnd(struct ListNode* head,int n){ //返回是倒数第几个数
if(NULL == head) return 0;
if(NULL == head->next) return 1;
int nextNth = NthFromEnd(head->next,n);
if(nextNth == n){
struct ListNode* del = head->next; //head是要找的前一个结点
head->next = del->next;
free(del);
}
return nextNth+1;
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(NULL == head || n<0) return head;
struct ListNode dump = {0,head};
NthFromEnd(&dump,n);
return dump.next;
}
方法五
用栈的方法来删除会更简单,第n个出栈的删除就可以完成
typedef struct ListNode* Element;
typedef struct Node{
Element e;
struct Node* next;
}Node;
typedef struct Stack{
Node* header;
size_t size;
}Stack;
//创建
Stack* Create(){
Stack* s = malloc(sizeof(Stack));
s->header = NULL;
s->size = 0;
return s;
}
//销毁
void Destory(Stack** s){
if(NULL == s) return;
if(NULL == *s) return;
Node* p = (*s)->header;
while(NULL!=p){
Node* del = p;
p = p->next;
free(del);
}
free(*s);
*s = NULL;
}
//栈长度
size_t GetSize(Stack* s){
return s->size;
}
//入栈
bool Push(Stack* s,Element e){
if(NULL == s) return false;
Node* p = malloc(sizeof(Node));
p->e = e;
p->next = s->header;
s->header = p;
s->size++;
return true;
}
//出栈
bool Pop(Stack* s){
if(NULL == s) return false;
if(NULL == s->header) return false;
s->size--;
Node* del = s->header;
s->header = del->next;
free(del);
return true;
}
//头指针
Element* Top(Stack* s){
if(NULL == s) return NULL;
if(NULL == s->header) return NULL;
return &(s->header->e);
}
int NthFromEnd(struct ListNode* head,int n){ //返回是倒数第几个数
if(NULL == head) return 0;
if(NULL == head->next) return 1;
int nextNth = NthFromEnd(head->next,n);
if(nextNth == n){
struct ListNode* del = head->next; //head是要找的前一个结点
head->next = del->next;
free(del);
}
return nextNth+1;
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(NULL == head || n<0) return head;
struct ListNode dump = {0,head};
// NthFromEnd(&dump,n);
Stack* s = Create();
struct ListNode* p = &dump;
while(NULL != p){
Push(s,p);
p = p->next;
}
for(int i=0;i<n;++i){
Pop(s);
}
p = *Top(s);
struct ListNode* del = p->next;
p->next = del->next;
free(del);
Destory(&s);
return dump.next;
}