【剑指Offer专题】链表系列:从尾到头打印链表、反转链表、回文链表、合并两个排序的链表(C++和Python实现)...

关注上方深度学习技术前沿,选择“星标公众号”

资源干货,第一时间送达!

剑指Offer(三):从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1:

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

1、思路

通常,这种情况下,我们不希望修改原链表的结构。返回一个反序的链表,这就是经典的“后进先出”,我们可以使用栈实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始逐个输出结点的值,给一个新的链表结构,这样链表就实现了反转。

2、代码
  • C++实现:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> reversePrint(ListNode* head) {
            stack<int> result;
            vector<int> reverse;
            ListNode* nodes = head;
            while(nodes !=NULL){
                result.push(nodes->val);
                nodes = nodes->next;
            }
            while(!result.empty()){
                reverse.push_back(result.top());
                result.pop();
            }
            return reverse;
    
    
        }
    };
    
  • Python实现:

    # -*- coding:utf-8 -*-
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    
    class Solution:
        def printListFromTailToHead(self, listNode):
            # write code here
            result = []
            while listNode:
                result.insert(0, listNode.val)
                listNode = listNode.next
            return result
    

剑指Offer(十五):反转链表

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

1、思路
  • 这个很简单,我们使用三个指针,分别指向当前遍历到的结点、它的前一个结点以及后一个结点。

  • 在遍历列表时,将当前节点的 next 指针改为指向前一个元素.

2、代码
  • C++:

    /**
     * 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) {
            ListNode* pReversedHead = NULL;
            ListNode* pNode = head;
            ListNode* pPrev = NULL;
            while(pNode != NULL){
                ListNode* pNext = pNode->next;
                if(pNext == NULL){
                    pReversedHead = pNode;
                }
                pNode->next = pPrev;
                pPrev = pNode;
                pNode = pNext;
            }
            return pReversedHead;
        }
    };
    
  • python:

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    
    class Solution:
        def reverseList(self, head: ListNode) -> ListNode:
            if not head or not head.next:
                return head
            last = None
    
    
            while head:
                tmp = head.next
                head.next = last
                last = head
                head = tmp
            return last
    

LeetCode 234. 回文链表

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

1、算法思路
  • 复制链表值到数组列表中。

  • 使用双指针法判断是否为回文。

  1. 遍历链表将值复制到数组列表中。用 currentNode 指向当前节点。每次迭代向数组添加 currentNode.val,并更新 currentNode = currentNode.next,当 currentNode = null 则停止循环。

  2. 在 Python 中,很容易构造一个列表的反向副本,也很容易比较两个列表。因此最好使用双指针法来检查是否为回文。我们在起点放置一个指针,在结尾放置一个指针,每一次迭代判断两个指针指向的元素是否相同,若不同,返回 false;相同则将两个指针向内移动,并继续判断,直到相遇。

在编码的过程中,注意我们比较的是节点值的大小,而不是节点本身。正确的比较方式是:node_1.val == node_2.val。而 node_1 == node_2 是错误的。

2、复杂度分析
  • 时间复杂度:O(n),其中 n 指的是链表的元素个数。

    • 第一步:遍历链表并将值复制到数组中,O(n)。

    • 第二步:双指针判断是否为回文,执行了 O(n/2)次的判断,即 O(n)。

    • 总的时间复杂度:O(2n) = O(n)。

  • 空间复杂度:O(n),其中 n 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。

3、代码实现:
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None


class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        vals = []
        current_node = head
        while current_node is not None:
            vals.append(current_node.val)
            current_node = current_node.next
        return vals == vals[::-1]

剑指Offer(十六):合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

1、思路
  1. 先判断输入的链表是否为空的指针。如果第一个链表为空,则直接返回第二个链表;如果第二个链表为空,则直接返回第一个链表。如果两个链表都是空链表,合并的结果是得到一个空链表。

  2. 两个链表都是排序好的,我们只需要从头遍历链表,判断当前指针,哪个链表中的值小,即赋给合并链表指针即可。使用递归就可以轻松实现。

2、代码实现
  • C++:

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
                val(x), next(NULL) {
        }
    };*/
    class Solution {
    public:
        ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
        {
            //判断指针是否为空
            if(pHead1 == NULL){
                return pHead2;
            }
            else if(pHead2 == NULL){
                return pHead1;
            }
            ListNode* pMergedHead = NULL;
            if(pHead1->val < pHead2->val){
                pMergedHead = pHead1;
                   pMergedHead->next = Merge(pHead1->next, pHead2);
            }
            else{
                pMergedHead = pHead2;
                   pMergedHead->next = Merge(pHead1, pHead2->next);
            }
            return pMergedHead;
        }
    };
    
  • Python:

    # -*- coding:utf-8 -*-
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    class Solution:
        # 返回合并后列表
        def Merge(self, pHead1, pHead2):
            # write code here
            if not pHead1:
                return pHead2
            if not pHead2:
                return pHead1
            pMergeHead = None
            if pHead1.val < pHead2.val:
                pMergeHead = pHead1
                pMergeHead.next = self.Merge(pHead1.next, pHead2)
            else:
                pMergeHead = pHead2
                pMergeHead.next = self.Merge(pHead1, pHead2.next)
            return pMergeHead
    

-END-

推荐阅读:

既然来了,给个在看可否!~  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值