《剑指 Offer II》—链表08

学习计划链接

剑指offer——学习计划

题目解析

1. 剑指 Offer II 024. 反转链表

1) 问题描述

在这里插入图片描述

2) 思路分析

  1. 法1:使用递归;
  2. 法2:三指针
    ① 用prev、cur、next指向三个连续的节点,用于更改连接关系
    ② 迭代更改cur的next指向,直到最后更改到链表结束,更新头节点。

3) leetcode链接

剑指 Offer II 024. 反转链表

4) 代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
 //法1:使用递归;
 //法2:三指针
class Solution {
public:
	ListNode* reverseList(ListNode* head) {
            if(head==nullptr||head->next==nullptr){
                return head;
            }  
            ListNode *cur = reverseList(head->next);
            head->next->next=head;
            head->next=nullptr;
            return cur;
    }
    ListNode* reverseList1(ListNode* head) {
        if(head==nullptr||head->next==nullptr)
        {
            return head;
        }
        //用prev、cur、next指向三个连续的节点,用于更改连接关系
        ListNode *prev=nullptr;
        ListNode *cur=head;
        ListNode *next=head->next;
        while(cur)
        {
            cur->next=prev;
            prev=cur;
            cur=next;
            //判断当前更改关系是否为最后一个
            if(next)
                next=next->next;
            else
                head=prev;
        }
        return head;
    }
};

2. 剑指 Offer II 025. 链表中的两数相加

1) 问题描述

在这里插入图片描述

2) 思路分析

逆置链表(由于加法运算是从低位到高位相加,故逆置链表,模拟加法,每一位的值等于sum%10 ———— sum=b1+b2+carry——其中b1,b2分别为r1、r2对应为的数值、carry为低位向上的进位,本位向上一高位的进位为sum/10)

  1. 逆置两链表;
  2. 求和,并插入新链表;
  3. 逆置新链表得结果。

3) leetcode链接

剑指 Offer II 025. 链表中的两数相加

4) 代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* l)
    {
        if(l==nullptr || l->next==nullptr)
            return l;
        ListNode *prev=nullptr;
        ListNode *cur=l;
        ListNode *next=l->next;
        while(cur)
        {
            cur->next=prev;
            prev=cur;
            cur=next;
            if(next)
            {
                next=next->next;
            }
        }
        return prev;
    }
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        //1.逆置链表。(由于加法运算是从低位到高位相加,故逆置链表,模拟加法,每一位的值等于sum%10 ———— sum=b1+b2+carry——其中b1,b2分别为r1、r2对应为的数值、carry为低位向上的进位,本位向上一高位的进位为sum/10)
        ListNode *r1 = reverseList(l1);
        ListNode *r2 = reverseList(l2);
        int sum=0;
        int carry=0;
        ListNode *rhead = nullptr;       //逆置两链表之后的结果。
        ListNode *rtail = nullptr;        //指向rhead的尾节点,方便尾插
        while(r1||r2)
        {
            //1. 取r1和r2对应值
            int n1=0;
            if(r1)
            {
                n1= r1->val;
                r1=r1->next;
            }
            int n2=0;
            if(r2)
            {
                n2=r2->val;
                r2=r2->next;
            }

            //2.求两数之和。
            sum=n1+n2+carry;

            //3.得出当前位的进位和当前位的值。判断当前节点是否为链表第一个节点,若为第一个,则更新头指针;否则,将当前位的值插入rhead尾部中,并更新尾节点。
            carry=sum/10;
            ListNode *newNode=new ListNode(sum%10);
            if(rhead==nullptr)               //判断当前节点是否为链表第一个节点,若为第一个,则更新头指针
            {
                rhead=newNode;                         
            }
            else
                rtail->next=newNode;
            rtail=newNode;
        }

        //遍历完链表,若进位非0,则向链表尾部再插入一个值为进位的节点。
        if(carry)
        {
            ListNode *newNode=new ListNode(carry);
            rtail->next=newNode;
        }           

        //逆置链表,即得到结果。
        ListNode* head = reverseList(rhead);
        return head;
    }

    //结果超过long long范围,溢出
    // long long toNumber(ListNode *l)
    // {
    //     ListNode *cur=l;
    //     long long ret=0;
    //     while(cur)
    //     {
    //         ret=ret*10+cur->val;
    //         cur=cur->next;
    //     }
    //     return ret;
    // }
    // ListNode* addTwoNumbers1(ListNode* l1, ListNode* l2) {
    //     if(l1->val==0 &&l2->val==0)
    //         return l2;
    //     //1.将两个链表转为数字并相加
    //     long long n1=toNumber(l1);
    //     long long n2=toNumber(l2);
    //     long long add=n1+n2;
    //     //2.将结果连起来
    //     ListNode *nextNode=nullptr;
    //     long long tmp=add;
    //     ListNode *newNode=nullptr;
        
    //     while(tmp)
    //     {
    //         newNode=new ListNode(tmp%10);
    //         newNode->next=nextNode;
    //         nextNode=newNode;
    //         tmp/=10;
    //     }
    //     return newNode;
    // }
};

3. 剑指 Offer II 026. 重排链表

1) 问题描述

在这里插入图片描述

2) 思路分析

队列和栈辅助实现

  1. 记录链表个数,前n/2个插入队列中,后n/2个插入栈中。
  2. 如果当前位置为链表偶数位,则从队列中取数据,否则,从栈中取数据。
    注意:尾指针的next一定要置为空,否则,会出现带环链表

3) leetcode链接

剑指 Offer II 026. 重排链表

4) 代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        queue<ListNode *> q;
        stack<ListNode *> s;
        int i=0;
        int n=0;
        //1. 记录链表个数,前n/2个插入队列中,后n/2个插入栈中。
        ListNode *cur=head;
        while(cur)
        {
            n++;
            cur = cur->next;
        }
        cur=head;
        while((n%2==0 && i<n/2)||(n%2!=0 && i<n/2+1))
        {
            i++;
            q.push(cur);
            cur=cur->next;
        }
        while(i<n)
        {
            s.push(cur);
            cur=cur->next;
            i++;
        }

        ListNode *tail=nullptr;            //记录新链表尾部
        //ListNode *newhead=nullptr;       //记录新链表头部
        head=nullptr;
        i=0;
        //如果当前位置为链表偶数位,则从队列中取数据,否则,从栈中取数据。
        while(!q.empty()||!s.empty())
        {
            if(i%2==0)
            {
                ListNode *x=q.front();
                q.pop();
                if(head==nullptr)
                {
                    head=x;
                }
                else
                {
                    tail->next=x;
                }
                tail=x;
            }
            else
            {
                ListNode *x=s.top();
                s.pop();

                tail->next=x;
                tail=x;
            }
            i++;
        }
        tail->next=nullptr;                 //注意尾指针的next一定要置为空,否则,会出现带环链表
        //head=newhead;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值