代码随想录算法训练营22期--Day 3

代码随想录算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表

1. 数据结构–链表

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针)。链表在内存中不是连续分布的,而是通过指针域的指针链接在内存中各个节点。链表的增添和删除的时间复杂度为 O(1),查找的时间复杂度为 O(n)。

2. 203.移除链表元素

Leetcode题目链接

题目:删除链表中等于给定值 val 的所有节点。

思路:重点在于删除头节点和删除其他节点的方式不一样,因此有两种方法,一种是分别编写删除头节点和删除其他节点的代码,另一种是采用虚拟头节点的方法,统一删除头节点和其他节点,这里只展示虚拟头节点方法,如下所示(注意怎么设置指针p的值,使得删除某节点时,p指向的是该节点的上一节点):

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode *p, *dummy_head;
    dummy_head = (struct ListNode*)calloc(sizeof(struct ListNode),1);
    dummy_head->next = head;
    p = dummy_head;
    while(p->next!=NULL) {
        if(p->next->val == val) {
            struct ListNode *temp;
            temp = p->next;
            p->next = p->next->next;
            free(temp);
        }
        else
            p = p->next;
    }
    return dummy_head->next;
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

3. 707.设计链表

Leetcode题目链接

题目:涉及到链表的五个基本操作。

思路:需要理解虚拟头节点的使用方法,注意循环的终止条件以及空指针的判断。代码如下:

typedef struct MyLinkedList{
    int val;
    struct MyLinkedList* next;
} MyLinkedList;

MyLinkedList* myLinkedListCreate() {
    MyLinkedList *head = (MyLinkedList *)calloc(sizeof(MyLinkedList),1);
    head -> next = NULL;
    return head;

}

int myLinkedListGet(MyLinkedList* obj, int index) {
    MyLinkedList *p = obj -> next;
    for(int i = 0; p != NULL; i++) {
        if(i == index)
            return p -> val ;
        else
            p = p -> next;
    }
    return -1;
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    MyLinkedList *new_head;
    new_head = (MyLinkedList *)calloc(sizeof(MyLinkedList),1);
    new_head -> val = val;
    new_head -> next = obj -> next;
    obj -> next = new_head;

}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    MyLinkedList *new_tail, *p = obj ;
    new_tail = (MyLinkedList *)calloc(sizeof(MyLinkedList),1);
    new_tail -> val = val;
    new_tail -> next = NULL;
    while(p->next != NULL)
        p = p -> next;
    p->next = new_tail;
}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    MyLinkedList *p = obj;
    MyLinkedList *nnode = (MyLinkedList *)calloc(sizeof(MyLinkedList),1);
    nnode -> val = val;
    for(int i = 0; p != NULL; i++) {
        if(i == index) {
            nnode -> next = p -> next;
            p -> next = nnode;
        }
        else
            p = p -> next;
    }

}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    MyLinkedList *p = obj;
    for(int i = 0; p != NULL; i++) {
        if(i == index && p->next != NULL)
            p -> next = p -> next -> next;
        else
            p = p -> next;
    }
}

void myLinkedListFree(MyLinkedList* obj) {
    free(obj);
}

4. 206.反转链表

Leetcode题目链接

题目:反转一个单链表。

示例:输入:1->2->3->4->5->NULL 输出:5->4->3->2->1->NULL

思路:双指针法,改变每个节点的指向即可,注意双指针的初始化以及反转结束的终止条件的设置。递归法,思路参考双指针法,代码更简洁(掌握得还不够熟练)。代码如下:

双指针法:

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode *cur = head, *pre = NULL, *temp;
    while(cur) {
        temp = cur -> next;
        cur -> next = pre;
        pre = cur;
        cur = temp; //将pre和cur往后移动一位
    }
    return pre;
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

递归法:

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* reverse(struct ListNode* cur, struct ListNode* pre);
    return reverse(head, NULL);
}

struct ListNode* reverse(struct ListNode* cur, struct ListNode* pre) {
    struct ListNode *temp;
    if(cur == NULL)
        return pre;
    temp = cur -> next;
    cur -> next = pre;
    return reverse(temp,cur);
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)(递归调用了n层栈空间)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值