数据结构刷题:第八天

简介: 当我们遍历到链表的最后一个节点时,cur.next 为空节点,如果不加以判断,访问 cur.next 对应的元素会产生运行错误。因此我们只需要遍历到链表的最后一个节点,而不需要遍历完整个链表。

一,反转链表


206. 反转链表 - 力扣(LeetCode)

https://leetcode.cn/problems/reverse-linked-list/?envType=study-plan&id=shu-ju-jie-gou-ru-men

99e14ba2b3ef4b9185176fa6c172f9a0.png

1,迭代


假设链表为 1→2→3→∅,我们想要把它改成∅←1←2←3。


在遍历链表时,将当前节点的next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。


class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr) {
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
};


复杂度分析


  • 时间复杂度:O(n),其中 nn 是链表的长度。需要遍历链表一次。


  • 空间复杂度:O(1)。


2,递归


递归版本稍微复杂-些,其关键在于反向工作。假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?


假设链表为:

n1-→...→+nk-1→nk→nk+1→...→nm→0


若从节点nk+1到nm已经被反转,而我们正处于nk

n1→...→nk-1→Nh:→nk+1←...←nm

我们希望nk+1的下一个节点指向nk所以,np.next.next= nk。

需要注意的是n1的下一个节点必须指向0。如果忽略了这一点,链表中可能会产生环。


class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (!head || !head->next) {
            return head;
        }
        ListNode* newHead = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
};


复杂度分析


时间复杂度:O(n),其中n 是链表的长度。需要对链表的每个节点进行反转操作。


空间复杂度:O(n),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。


二,删除排序链表中的重复元素


83. 删除排序链表中的重复元素 - 力扣(LeetCode)

https://leetcode.cn/problems/remove-duplicates-from-sorted-list/?envType=study-plan&id=shu-ju-jie-gou-ru-men

88e5199720ff4939af12bca7d82a1439.png


1,一次遍历


思路与算法


由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。


具体地,我们从指针cur 指向链表的头节点,随后开始对链表进行遍历。如果当前 cur 与 cur.next 对应的元素相同,那么我们就将 cur.next 从链表中移除;否则说明链表中已经不存在其它与 cur 对应的元素相同的节点,因此可以将cur 指向 cur.next。


当遍历完整个链表之后,我们返回链表的头节点即可。


细节


当我们遍历到链表的最后一个节点时,cur.next 为空节点,如果不加以判断,访问 cur.next 对应的元素会产生运行错误。因此我们只需要遍历到链表的最后一个节点,而不需要遍历完整个链表。


代码


注意下面C++ 代码中并没有释放被删除的链表节点的空间。如果在面试中遇到本题,读者需要针对这一细节与面试官进行沟通。


class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head) {
            return head;
        }
        ListNode* cur = head;
        while (cur->next) {
            if (cur->val == cur->next->val) {
                cur->next = cur->next->next;
            }
            else {
                cur = cur->next;
            }
        }
        return head;
    }
};


复杂度分析


  • 时间复杂度:O(n),其中 nn 是链表的长度。


  • 空间复杂度:O(1)。
目录
相关文章
|
12月前
【数据结构刷题】数组oj
【数据结构刷题】数组oj
|
12月前
|
编译器 C语言
【数据结构刷题】消失的数字和轮转数组(下)
【数据结构刷题】消失的数字和轮转数组(下)
|
12月前
【数据结构刷题】消失的数字和轮转数组(上)
【数据结构刷题】消失的数字和轮转数组(上)
|
12月前
|
算法
数据结构刷题训练:用栈实现队列(力扣OJ)
数据结构刷题训练:用栈实现队列(力扣OJ)
57 0
|
4月前
|
存储 算法 C语言
【数据结构与算法 刷题系列】合并两个有序链表
【数据结构与算法 刷题系列】合并两个有序链表
|
4月前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-2
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
4月前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-1
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
4月前
|
算法
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
|
4月前
|
算法
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
|
4月前
|
算法
【数据结构与算法 刷题系列】移除链表元素
【数据结构与算法 刷题系列】移除链表元素