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