首页 > 其他分享 >【8.5】链表-删除排序链表中的重复元素

【8.5】链表-删除排序链表中的重复元素

时间:2024-12-26 13:55:03浏览次数:5  
标签:head ListNode cur next 链表 8.5 排序 节点

一、题目

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

示例 1:

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

示例 2:

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

提示:

  • 链表中节点数目在范围 [0, 300]
  • -100 <= Node.val <= 100
  • 题目数据保证链表已经按升序 排列

二、解题思路

2.1 使用一个指针解决       

        这道题目中提到,链表中的节点值是按照升序排列的。既然链表是有序的,那么值相同的节点一定是相邻的。我们可以使用一个指针 `cur` 来遍历链表,每次判断当前节点 `cur` 的值是否与下一个节点的值相同。如果相同,就将下一个节点删除。接下来,我们以示例 2 为例,来展示具体的操作过程。

#include <iostream>

// 定义链表节点结构体
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* deleteDuplicates(ListNode* head) {
    // 如果当前节点是空,或者是单个节点,直接返回
    if (head == nullptr || head->next == nullptr)
        return head;

    // 只用一个指针 cur 指向当前节点
    ListNode* cur = head;
    while (cur->next != nullptr) {
        // 如果当前节点的值和下一个节点的值相同,
        // 就把下一个节点删除
        if (cur->val == cur->next->val) {
            cur->next = cur->next->next;
        } else {
            // 否则 cur 就往后移一步
            cur = cur->next;
        }
    }
    return head;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    ListNode* curr = head;
    while (curr != nullptr) {
        std::cout << curr->val << " ";
        curr = curr->next;
    }
    std::cout << std::endl;
}

int main() {
    // 创建一个示例链表:1 -> 1 -> 2 -> 3 -> 3
    ListNode* head = new ListNode(1);
    head->next = new ListNode(1);
    head->next->next = new ListNode(2);
    head->next->next->next = new ListNode(3);
    head->next->next->next->next = new ListNode(3);

    // 调用 deleteDuplicates 函数
    ListNode* result = deleteDuplicates(head);

    // 打印结果链表
    printList(result);

    return 0;
}

2.2 递归解决

        除了前面提到的使用单个指针的方法外,我们还可以通过递归的方式来解决这个问题。递归的实现需要对链表的逆序访问有一定的理解,如果你对链表的逆序操作不太熟悉,可以参考“倒序打印链表”的相关内容。接下来,我们以示例 1 为例,通过一个图示来详细说明递归的具体过程。

#include <iostream>

// 定义链表节点结构体
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* deleteDuplicates(ListNode* head) {
    // 递归的边界条件判断
    if (head == nullptr || head->next == nullptr)
        return head;

    // 递归,相当于从后往前遍历
    head->next = deleteDuplicates(head->next);

    // 如果当前节点和下一个节点值相同,直接返回下一个节点,
    // 否则返回当前节点
    return head->val == head->next->val ? head->next : head;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    ListNode* curr = head;
    while (curr != nullptr) {
        std::cout << curr->val << " ";
        curr = curr->next;
    }
    std::cout << std::endl;
}

int main() {
    // 创建一个示例链表:1 -> 1 -> 2 -> 3 -> 3
    ListNode* head = new ListNode(1);
    head->next = new ListNode(1);
    head->next->next = new ListNode(2);
    head->next->next->next = new ListNode(3);
    head->next->next->next->next = new ListNode(3);

    // 调用 deleteDuplicates 函数
    ListNode* result = deleteDuplicates(head);

    // 打印结果链表
    printList(result);

    return 0;
}

标签:head,ListNode,cur,next,链表,8.5,排序,节点
From: https://blog.csdn.net/linshantang/article/details/144738404

相关文章

  • 「数据结构课程设计」二叉排序树与文件操作
    功能要求:(1)从键盘输入一组学生记录建立二叉排序树;(2)中序遍历二叉排序树;(3)求二叉排序树深度;(4)求二叉排序树的所有节点数和叶子节点数;(5)向二叉排序树插入一条学生记录;(6)从二叉排序树中删除一条学生记录;(7)从二叉排序树中查询一条学生记录;(8)以广义表的形式输出二叉排序树该文件也......
  • 解锁桶排序:全面掌握其核心知识与技巧
    一、基本原理核心思想桶排序的基本思想是将数组中的数据分到有限数量的桶里。每个桶再分别进行排序(可以使用其他排序算法,如插入排序),最后将各个桶中的数据有序地合并起来,得到最终的排序结果。工作方式类比可以把它想象成在一个有很多小格子(桶)的柜子里整理物品。首先根据物......
  • 全面解析基数排序:定义、原理、复杂度、稳定性及实现步骤详解
    定义基数排序(RadixSort)是一种非比较型整数排序算法,它是根据数字的每一位来排序。它的基本思想是将整数按位数切割成不同的数字,然后按每个位数分别比较。对于有d位的整数,需要进行d趟排序。工作原理以最低有效位(Least-Significant-Digit,LSD)为例首先,考虑待排序的整数......
  • 深入剖析堆排序:从基础概念到实际应用
    基本概念堆是一种完全二叉树的数据结构。在堆排序中,主要使用两种堆:最大堆和最小堆。最大堆的特点是每个节点的值都大于或等于它的子节点的值;最小堆则是每个节点的值都小于或等于它的子节点的值。例如,对于最大堆,根节点是整个堆中的最大值。完全二叉树是一种特殊的二叉树,除了最......
  • 计数排序:原理、步骤、复杂度及应用全解析
    一、基本原理计数排序的基本思想是对于给定的输入序列中的每一个元素x,确定小于x的元素个数。通过统计每个元素出现的次数,然后根据统计结果将元素放到有序序列中的正确位置。假设输入的数组是A,长度为n,数组中的元素范围是0到k。它需要额外创建两个辅助数组:计数数组C(长度为k+......
  • 插入排序知识点汇总:原理、特性与实践
    一、基本原理概念插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。可以类比为人们整理手中的扑克牌,每次拿到一张新牌,就将它插入到已经排好序的牌中的合适位置。算法步骤从第一个元素开始,该元素可以认为已经被排序。......
  • 冒泡排序全攻略:概念、原理、复杂度与代码详解
    一、冒泡排序的基本概念冒泡排序(BubbleSort)是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢......
  • 详解选择排序:从概念到代码的完整指南
    一、选择排序的基本概念选择排序(SelectionSort)是一种简单的排序算法。它的基本思想是:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。二、选择排序的过程......
  • 冒泡排序算法-C语言
    冒泡排序的基本思想是通过重复遍历待排序的数列,比较相邻的元素,并将顺序错误的元素交换过来,从而把最大(或最小)的元素“冒泡”到数列的一端,就如同气泡最终会上浮到顶端一样,故名“冒泡排序”。  下面看个直接示例: 冒泡排序算法的基本步骤:1.从第一个元素开始,比较相邻的两个......
  • 算法刷题_链表篇
    算法刷题Day8_链表相交文章目录算法刷题Day8_链表相交@[TOC](文章目录)前言一、求出两个链表的长度和差值二、让其中较长一个链表移动到和第二链表对齐的位置三、其他解法_双指针法:总结前言简单来说,就是求两个链表交点节点的指针。一、求出两个链表的长度和差值......