java单链表删除重复元素_字节面试题 leetcode 83. 删除排序链表中的重复元素

b5924c4c0cb6da1dd0175088a2aecefe.png

今天给大家分享一道字节跳动的面试题,也就是 Leetcode 83. 删除排序链表中的重复元素,提供三种(递归、迭代(单指针、双指针))解题思路,供大家参考。

7a58a285a26fc0300f54659aeb6412f2.png

7702386c695dc58415a9d43884b1baf9.png

题目

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

示例 1:

输入: 1->1->2

输出: 1->2

示例 2:

输入: 1->1->2->3->3

输出: 1->2->3

7a58a285a26fc0300f54659aeb6412f2.png

7702386c695dc58415a9d43884b1baf9.png

递归解法

4eb7a6773dd613a95b9ff34cd4f1c92b.png

解题思路:在上上期的面试不可不会的单链表反转中,提到了针对链表的题目可以采用递归的思想去解答,其主要的思想:把链表看成头节点后面挂接一个更短的链表,这个更短的链表的头节点是原链表的第二个节点,更短的这个链表又可以看成是当前链表的头节点后面再挂接一个更更短的链表,这个更更短的链表的头节点是原链表的第三个节点,依次类推。以链表1->2->3->4为例,具体如下图示:

629371fe57d78faafc01ae8c2d4f1a29.png

22bf2eac69b1639a2fc30a312e5af0dd.png

有了上面的分析,可以先删除更短的链表(或者更更短的链表)中的重复元素,然后再判断头节点的值是否跟删除后更短链表的头节点值是否相等,相等则将头节点也删除,否则把删除后更短链表挂接在头节点的后面。以链表1->1->2->3->3 为栗子,如下图示:

acac8671c71771ff8537cb9cf9adbb1b.png

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

Show me the Code

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

// C 语言struct ListNode* deleteDuplicates(struct ListNode* head){    if (head == NULL || head->next == NULL) {        return head;    }    /* 删除头节点后面挂接的更短的链表中的重复元素 */    head->next = deleteDuplicates(head->next);    /* 头节点与后面挂接的链表中的头节点的值相同,则删除头节点,否则不删除 */    return head->val == head->next->val ? head->next : head;}

// go 语言func deleteDuplicates(head *ListNode) *ListNode {    if head == nil || head.Next == nil {        return head    }    head.Next = deleteDuplicates(head.Next)    if head.Val == head.Next.Val {        head = head.Next    }    return head}

7a58a285a26fc0300f54659aeb6412f2.png

7702386c695dc58415a9d43884b1baf9.png

迭代单指针解法

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

f76ff71f0aad23ff0062a3ef22e2e3d4.png

解题思路:由于题目已说明链表是排序链表,所以只需要遍历整个链表,然后挨个比较相邻节点的值是否相等,相等则通过将当前节点指向其下下个节点的方式去删除其下一个节点(重复元素)。

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

Show me the Code

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

// javaclass Solution {    public ListNode deleteDuplicates(ListNode head) {    if (head == null || head.next == null) {         return head;    }    /* 当前节点 */    ListNode cur = head;      /* 遍历直到当前节点为空或者当前节点是尾节点 */    while (cur != null && cur.next != null) {          /* 当前节点的值与其下一节点的值相同,则删除当前节点的下一节点,否则就继续遍历 */        if (cur.val == cur.next.val) {                   cur.next = cur.next.next;        } else {                                           cur = cur.next;        }    }    return head;        }}

#python3class Solution:    def deleteDuplicates(self, head: ListNode) -> ListNode:        if not head or not head.next: return head        cur = head        while cur and cur.next:            if cur.val == cur.next.val:                cur.next = cur.next.next            else: cur = cur.next        return head

7a58a285a26fc0300f54659aeb6412f2.png

7702386c695dc58415a9d43884b1baf9.png

迭代双指针解法

解题思路:定义两个指针,分别指向头节点和头节点的下一节点,移动这两个指针去遍历整个链表;边遍历边比较两个指针指向的节点的值是否相等,相等则将当前节点就指向其下下个节点(相当于删除其下一节点),然后继续遍历,否则不处理,遍历直到遍历完整个链表。

以链表 1->2->3->3->4->NULL 为栗子,如下图所示:

75b6d4b55344e2420006ce93f772fa3f.png

d94c6e2ca6ccb891086cba97a2971035.png

c3c25d35e10ab1c47afe25bc2168e68c.png

98cb7cf90bc1dd4a17ee964f0e9d6759.gif

Show me the Code

98cb7cf90bc1dd4a17ee964f0e9d6759.gif// C++class Solution {public:    ListNode* deleteDuplicates(ListNode* head) {        if (head == NULL || head->next == NULL) {            return head;        }        ListNode* cur = head;        ListNode* next = head->next;        while (next != NULL && cur != NULL) {            /* 当前节点的值不等于其下一节点的值,则继续遍历,否则删除其下一节点 */            if (next->val != cur->val) {                cur = cur->next;            } else {                cur->next = next->next;            }            /* 当前节点的下一节点不断移动,遍历整个链表 */            next = next->next;        }        return head;    }};

// go 语言func deleteDuplicates(head *ListNode) *ListNode {    if head == nil || head.Next == nil {        return head    }    cur, next := head, head.Next    for cur != nil && next != nil {        if (cur.Val == next.Val) {            cur.Next = next.Next        } else {            cur = cur.Next        }        next = next.Next    }    return head}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值