LeetCode刷题(十六)-----链表-------easy部分(Java、C++)

237. 删除链表中的节点

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:

在这里插入图片描述
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
• 链表至少包含两个节点。
• 链表中所有节点的值都是唯一的。
• 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
• 不要从你的函数中返回任何结果。

思路一:
方法:与下一个节点交换
从链表里删除一个节点node的最常见方法是修改之前节点的next指针,使其指向之后的节点。
在这里插入图片描述
因为,我们无法访问我们想要删除的节点之前的节点,我们始终不能修改该节点的 next 指针。相反,我们必须将想要删除的节点的值替换为它后面节点中的值,然后删除它之后的节点。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为我们知道要删除的节点不是列表的末尾,所以我们可以保证这种方法是可行的。
在这里插入图片描述
复杂度分析
时间和空间复杂度都是:O(1)。
链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list/solution/shan-chu-lian-biao-zhong-de-jie-dian-by-leetcode/
思路二:
替身攻击
在这里插入图片描述
链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list/solution/ti-shen-gong-ji-by-vailing/
我的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void deleteNode(ListNode* node) 
    {
        node -> val = node -> next -> val;
        node -> next = node -> next -> next;   
    }
};

206. 反转链表

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

思路一:
方法一:迭代
假设存在链表 1 → 2 → 3 → Ø,我们想要把它改成 Ø ← 1 ← 2 ← 3。
在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用!
在这里插入图片描述
复杂度分析
• 时间复杂度:O(n),假设n是列表的长度,时间复杂度是O(n)。
• 空间复杂度:O(1)。
方法二:递归
递归版本稍微复杂一些,其关键在于反向工作。假设列表的其余部分已经被反转,现在我该如何反转它前面的部分?
假设列表为:
在这里插入图片描述
若从节点n_{k+1}到n_{m}已经被反转,而我们正处于n_{k}。
在这里插入图片描述
我们希望 n_{k+1}的下一个节点指向n_{k}。
所以,n_{k}.next.next = n_{k}。
要小心的是 n_{1}的下一个必须指向 Ø 。如果你忽略了这一点,你的链表中可能会产生循环。如果使用大小为 2 的链表测试代码,则可能会捕获此错误。
在这里插入图片描述
复杂度分析
时间复杂度:O(n),假设 nn 是列表的长度,那么时间复杂度为 O(n)。
空间复杂度:O(n),由于使用递归,将会使用隐式栈空间。递归深度可能会达到 n层。

作者:LeetCode
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
思路二:
迭代:
在这里插入图片描述
在这里插入图片描述
递归:
在这里插入图片描述
我的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) 
    {
        if(!head)
        {
            return nullptr;
        }    
        ListNode* first = head;
        ListNode* target = head -> next;
        while(target != nullptr)
        {
            first -> next = target -> next;
            ListNode* temp = target -> next;
            target -> next = head;
            head = target;
            target = temp;
        }
        return head;
    }
};

21. 合并两个有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

思路一:
方法 1:递归
想法
我们可以如下递归地定义在两个链表里的merge操作(忽略边界情况,比如空链表等):
在这里插入图片描述
也就是说,两个链表头部较小的一个与剩下元素的merge操作结果合并。
算法

我们直接将以上递归过程建模,首先考虑边界情况。

特殊的,如果 l1 或者 l2 一开始就是 null ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个的头元素更小,然后递归地决定下一个添加到结果里的值。如果两个链表都是空的,那么过程终止,所以递归过程最终一定会终止。
在这里插入图片描述
复杂度分析
时间复杂度:O(n+m)。 因为每次调用递归都会去掉 l1 或者 l2 的头元素(直到至少有一个链表为空),函数 mergeTwoList 中只会遍历每个元素一次。所以,时间复杂度与合并后的链表长度为线性关系。
空间复杂度:O(n+m)。调用 mergeTwoLists 退出时 l1 和 l2 中每个元素都一定已经被遍历过了,所以 n + m个栈帧会消耗O(n+m)的空间。

方法 2:迭代
想法
我们可以用迭代的方法来实现上述算法。我们假设l1元素严格比l2元素少,我们可以将l2中的元素逐一插入l1中正确的位置。
算法
首先,我们设定一个哨兵节点 “prehead” ,这可以在最后让我们比较容易地返回合并后的链表。我们维护一个 prev 指针,我们需要做的是调整它的 next 指针。然后,我们重复以下过程,直到 l1 或者 l2 指向了 null :如果 l1 当前位置的值小于等于 l2 ,我们就把 l1 的值接在 prev 节点的后面同时将 l1 指针往后移一个。否则,我们对 l2 做同样的操作。不管我们将哪一个元素接在了后面,我们都把 prev 向后移一个元素。

在循环终止的时候, l1 和 l2 至多有一个是非空的。由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。这意味着我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表。
在这里插入图片描述
复杂度分析
时间复杂度:O(n+m) 。因为每次循环迭代中,l1和l2只有一个元素会被放进合并链表中,while 循环的次数等于两个链表的总长度。所有其他工作都是常数级别的,所以总的时间复杂度是线性的。

空间复杂度:O(1)。迭代的过程只会产生几个指针,所以它所需要的空间是常数级别的。

作者:LeetCode
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路二:
方法 1:递归
在这里插入图片描述
方法2:迭代
在这里插入图片描述
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-guan-fang-cban-b/
我的:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        if(l1 == NULL)
        {
            return l2;
        }
        else if(l2 == NULL)
        {
            return l1;
        }  
        else if(l1->val <= l2-> val)
        {
            l1 -> next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        else
        {
            l2 -> next = mergeTwoLists(l1,l2->next);
            return l2;
        }
    }
};

发布了47 篇原创文章 · 获赞 21 · 访问量 7227

猜你喜欢

转载自blog.csdn.net/qq_18315295/article/details/103773548