[蓝蓝计算机考研算法训练二期]-day14

98 阅读2分钟

19、删除排序链表中的重复元素

给定一个已排序的链表的头 head删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表

示例 1:

输入:head = [1,1,2] 输出:[1,2]

示例 2:

输入:head = [1,1,2,3,3] 输出:[1,2,3]

提示:

  • 链表中节点数目在范围 [0, 300] 内

  • -100 <= Node.val <= 100

  • 题目数据保证链表已经按升序 排列

思路

本算法是一个较为基本的遍历链表的算法,因为已经说明链表为升序,所以只需要删除重复元素部分,即对比本元素和下一个元素的val值是不是相同,若相同,则将下一个元素删除即可,遍历至链表尾结束。

具体实现

// 删除链表重复元素
#include <stdio.h>
#include <stdlib.h>

// 链表结构体
struct ListNode {
    int val;
    struct ListNode* next;
};

// 删除排序链表中重复元素的函数
struct ListNode* deleteDuplicates(struct ListNode* head) {
    struct ListNode* current = head;
    
    while (current != NULL && current->next != NULL) {
        if (current->val == current->next->val) {
            // 当前节点与下一个节点值相等,删除下一个节点
            struct ListNode* temp = current->next;
            current->next = temp->next;
            free(temp);
        } else {
            // 当前节点与下一个节点值不等,移动当前节点指针
            current = current->next;
        }
    }
    
    return head;
}

// 创建链表的函数
struct ListNode* createList() {
    int val;
    printf("请输入链表元素的值(输入-1结束):\n");
    scanf("%d", &val);
    
    struct ListNode* head = NULL;
    struct ListNode* current = NULL;
    
    while (val != -1) {
        struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
        node->val = val;
        node->next = NULL;
        
        if (head == NULL) {
            head = node;
            current = node;
        } else {
            current->next = node;
            current = node;
        }
        
        scanf("%d", &val);
    }
    
    return head;
}

// 打印链表的函数
void printList(struct ListNode* head) {
    struct ListNode* current = head;
    while (current != NULL) {
        printf("%d ", current->val);
        current = current->next;
    }
    printf("\n");
}

int main() {
    struct ListNode* list1 = createList();
    
    struct ListNode* result1 = deleteDuplicates(list1);
    
    printf("删除重复元素后的链表:");
    printList(result1);
    
    return 0;
}

image.png

20、反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2:

输入:head = [1,2] 输出:[2,1] 示例 3:

输入:head = [] 输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]

  • -5000 <= Node.val <= 5000

思路

本算法是基本的链表的算法,逆转函数使用了头插法的思想,每次拿到当前元素curr时,curr读取下一个元素,并将当前元素赋值给prev,遍历至链表尾结束。

具体实现

#include <stdio.h>
#include <stdlib.h>

// 链表节点结构体
struct ListNode {
    int val;
    struct ListNode *next;
};

// 反转链表函数
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode *prev = NULL, *curr = head, *next = NULL;
    while (curr != NULL) {
        next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

// 创建链表函数
struct ListNode* createList() {
    int val;
    struct ListNode *head = NULL, *tail = NULL;
    printf("请输入链表元素的值(输入-1结束)\n");
    while (1) {
        scanf("%d", &val);
        if (val == -1) {
            break;
        }
        struct ListNode *node = (struct ListNode*) malloc(sizeof(struct ListNode));
        node->val = val;
        node->next = NULL;
        if (head == NULL) {
            head = node;
            tail = node;
        } else {
            tail->next = node;
            tail = tail->next;
        }
    }
    return head;
}

// 打印链表函数
void printList(struct ListNode* head) {
    for (struct ListNode* p = head; p != NULL; p = p->next) {
        printf("%d ", p->val);
    }
}

int main() {
    struct ListNode *head = createList();
    struct ListNode *newHead = reverseList(head);
    printf("反转后的链表: ");
    printList(newHead);
    return 0;
}

image.png

小结

今天的两个算法都是较为简单和基础的算法,就是代码量大了一点,对于链表的编写、遍历以及值的传递(删除、逆转)都有涉及。