链表(4题)

链表常用技巧

1.画图,直观形象,便于我们理解

2.引入虚拟“头”节点

便于处理边界情况

方便我们对链表操作

3.不要吝啬空间,大胆定义变量

        比如prev cur next,定义好之后把相应节点的指针存进去,然后就可以不用考虑前后顺序,不用担心找不到节点了

4.快慢双指针

判环,找链表中环的入口,找链表中倒数第n个节点

链表中常用操作

1.创建一个新节点 new

2.尾插

3.头插(链表逆序)

1.两数相加

. - 力扣(LeetCode)

/**
 * 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* addTwoNumbers(ListNode* list1, ListNode* list2) {
        
        ListNode* l1 = list1;
        ListNode* l2 = list2;
        ListNode* l3 = new ListNode;;
        ListNode* ret = l3;
        int up = 0;
        while(l1 || l2 || up)
        {
            int num1 = 0;
            int num2 = 0;
            if(l1)
            {
                num1 = l1->val;
                l1 = l1->next;
            }
            if(l2)
            {
                num2 = l2->val;
                l2 = l2->next;
            }
            int Add = (num1 + num2 +up)%10;
            up = (num1 + num2 + up)/10;
            l3->val = Add;
            if(l1 || l2 || up)
            {
                l3->next = new ListNode;
                l3 = l3->next;
            }

        }
        return ret;
    }
};

总体就是一个简易版的高精度加法 

(我们可以把进位一并放入循环中考虑)

2.两两交换链表中的节点

. - 力扣(LeetCode)

/**
 * 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* swapPairs(ListNode* head) 
    {
    ListNode* headnode = new ListNode(0,head);
    ListNode* prev = headnode;
    ListNode* cur = head;
    ListNode* next = nullptr;
    ListNode* nnext = nullptr;
    if(head)
    {
        next = head->next;
        if(next)
        {
            nnext = next->next;
        }
    } 
    while(cur && next)
    {
        prev->next = next;
        next->next = cur;
        cur->next = nnext;

        prev = cur;
        cur = nnext;
        if(cur)
        {
            next = cur->next;
        }
        if(next)
        {
            nnext = next->next;
        }
    }
   cur = headnode->next;
   delete headnode;
   return cur;
    }
};

        首先我们定义四个指针,但是在赋值的时候要判断是否有这个节点,从head开始判断,也可以特判然后返回。为了整体逻辑的统一,我们选择加上一个头节点。

        有两种情况,一种是偶数个节点,一种是奇数个节点,结束条件分别对应cur为空和next

为空。

3.重排链表

. - 力扣(LeetCode)

/**
 * 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) {
        ListNode *slow = head;
        ListNode *fast = head;
     
        while(fast)//寻找中间节点
        {
            fast = fast->next;
            if(fast)
            {
                fast = fast->next;
            }
            else break;
            slow = slow->next;
        }
        ListNode *begin = slow->next;
        slow->next = nullptr;

        ListNode *relist = new  ListNode ;
        
        while(begin)//头插法使后一个链表逆序
        {
            ListNode* next = relist->next;
            ListNode* tmp = begin->next;
            relist->next = begin;
            begin->next = next;
            begin = tmp;
        }

        ListNode *ret = head;//不断插入
        ListNode*prev = head;
        ListNode*next = head->next;
        ListNode*cur = relist->next;
        while(cur)
        {
            prev->next = cur;
            ListNode* tmp = cur->next;
            cur->next = next;
            cur = tmp;

            prev = next;
            if(prev)next = prev->next;
        }
    }
};

题目主要分为三个步骤。

因为链表的题目主要是模拟,所以我们只需要按部就班

第一个步骤是先找到链表中间节点,把链表一分为二

第二个步骤是把第二个链表逆序,方便后续插入

第三个步骤是把第二个链表插入到第一个链表中

4.k个一组翻转链表

. - 力扣(LeetCode)

/**
 * 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* reverseKGroup(ListNode* head, int k) {
        int n = 1;
        ListNode* count = head;
        while(count->next)
        {
            n++;
            count = count->next;
        }
        n = n / k;

        ListNode* newhead = new  ListNode;
        //ListNode* ret = newhead;

        ListNode* prev = newhead;
        ListNode* cur = head;

        for(int i = 1; i <= n; i++)
        {
            ListNode* nexthead = cur;
            for(int j = 1; j <= k; j++)
            {
                ListNode* next = cur->next; 
                cur->next = prev->next;
                prev->next = cur;
                cur = next;
            }
            prev = nexthead;
        }
        prev->next = cur;
        cur = newhead->next;
        delete newhead;
        return cur;
    }
};

这里我们先遍历一次链表,就可以得到翻转的次数,就不需要担心空指针问题了。

链表逆序的节点数是确定的,放在循环里即可。

然后后面只需要按部就班逆序链表即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值