记录一下leetcode刷题-剑指offer(2)

剑指offer06-从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000

思路:

使用栈做中间存储介质,先把链表顺序存储到栈里,此时实现倒序,然后再从栈里取出到vector内。
注意:
1.vector本身是动态数组,直接创建即可,不需要使用new;
2.vector插入元素使用push_back()函数。

代码

/**
 * 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>list;
        vector<int> zu;
        ListNode *p;
        p=head;
        while(p!=NULL){
            list.push(p->val);
            p=p->next;
        }        
        while(!list.empty())
        {
            zu.push_back(list.top());
            list.pop();
        }
        return zu;
    }

};
/*
执行用时:4ms
内存消耗:8.4MB
*/

剑指offer24-反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000

思路

此题思路参考了leetcode社区的大佬们的做法。
做法有很多,我选择了递归算法。
核心算法就是,每次反转时,把第一个元素替换成最后一个元素,本来是head的next指针指向剩下的链表,现在换成它的下一个元素指向它(此时它后面的链表一定是反转完的)。
所以要先递归返回,然后再替换next指针关系。
注意:
虽然每次递归感觉都新建了一个链表,但实际上进行操作的是同一条链表,同一批结点(没有新建结点),我个人的理解是新建了链表指针。

代码:

/**
 * 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==NULL||head->next==NULL)//递归的终点是链表开始就为空或者链表只有一个元素
        {
            return head;
        }
        //当链表不为空时,当前第一个节点是反转链表的最后一个节点
        ListNode* reversehead=reverseList(head->next);//新建反转链表(除最后一个节点之后的后面的链表)
        head->next->next=head;//给反转链表插入最后一个节点
        head->next=NULL;
        return reversehead;
    }
};
/*
执行时间:4ms
内存消耗:8.3MB
*/

误区

开始有些被上一道题误导到,一门心思想再用一个栈做介质,然后完全新建一条链表,新建一堆节点。然后我就卡在了创建节点这一步,先不说能不能建好,建好后我也得runtime error(用递归的时候一开始我多建了一个指针就导致runtime error了)。

剑指offer35-复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例
示例1
示例2
示例3、4和提示

思路

依旧是在评论区和解题区跌跌撞撞寻找解答
首先这个题目的难点在于他是个复杂链表的复制,如果没有随机指针,他可以直接一个一个地直接复制。
但是由于随机指针指向不确定,有可能会指向还没创建的节点,所以复杂。
我用的是原地修改法。首先只创建同元素的节点,分别插入每个被复制节点之后,random都默认为空。
然后依次修改random指针,参照前面的节点,指向其对应节点的后一个节点(只针对指向非空节点的指针)。
最后再依次修改每个节点的next指针,使他们变成两条链。

难点

对我来说,了解思路和算法并不难,难点在于创建节点和指针,哪些地方需要带星花,哪里需要加new;还有就是while判断语句容易出错。还需要多练习。

代码

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {       
        if(head==NULL)
        return NULL;//如果为空,输出null
        //不为空的话开始复制
        Node *p=head;
        while(p!=NULL){
            Node* newnode=new Node(p->val);//新建节点同元素
            newnode->next=p->next;//插入被复制节点之后
            p->next=newnode;
            p=p->next->next;
        }
        p=head;
        while(p!=NULL){
            if(p->random!=NULL){
                p->next->random=p->random->next;                
            }
            p=p->next->next;
        }
        p=head;
        Node* copyhead=head->next;
        Node* q=copyhead;
        while(p!=NULL){
            p->next=p->next->next;
            p=p->next;
            if(q->next!=NULL){
                q->next=q->next->next;
                q=q->next;
            }
        }
        return copyhead;
        

        
    }
};
/*
执行用时:4ms
内存消耗:11MB
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值