LeetCode——链表

1.两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头
在这里插入图片描述

示例1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

示例2:

输入:l1 = [0], l2 = [0]
输出:[0]

示例3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

1)我的思路

/**
 * 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* l1, ListNode* l2) {
       ListNode* result=new ListNode;
       int flag=0;          //进位
       result->val=l1->val+l2->val;
       flag=result->val/10;
       result->val=result->val%10;
       ListNode* taile=result;      //始终指向链表尾部
       l1=l1->next;
       l2=l2->next;
       //某一个到达结尾的时候退出while
       while(l1!=nullptr&&l2!=nullptr)
       {
           ListNode *node=new ListNode;
           node->val=l1->val+l2->val+flag;
           flag=node->val/10;
           node->val=node->val%10;
           taile->next=node;
           taile=node;
           l1=l1->next;
           l2=l2->next;
       }
       //若两个同时为空,直接返回
       if(l1==nullptr&&l2==nullptr)
       {
           //最后一位有进位
           if(flag)
           {
               ListNode* node=new ListNode;
               node->val=1;
               taile->next=node;
               taile=node;
           }
           return result;
       }
       else
       {

            //若l1为空,说明l2不为空
            if(l1==nullptr)
            {
                //不为空
                while(l2!=nullptr)
                {
                    l2->val+=flag;
                    flag=l2->val/10;
                    l2->val=l2->val%10;
                    taile->next=l2;
                    taile=l2;
                    l2=l2->next;
                }
                //为空且有进位
                if(flag)
                {
                    ListNode* node=new ListNode;
                    node->val=1;
                    taile->next=node;
                    taile=node;
                    return result;
                }
                return result;
            }
            else
            {
                while(l1!=nullptr)
                {
                    l1->val+=flag;
                    flag=l1->val/10;
                    l1->val=l1->val%10;
                    taile->next=l1;
                    taile=l1;
                    l1=l1->next;
                }
                if(flag)
                {
                    ListNode* node=new ListNode;
                    node->val=1;
                    taile->next=node;
                    taile=node;
                    return result;
                }
                return result;
            }
       }
    }
};

运行结果:
在这里插入图片描述

2)官方解答

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head = nullptr, *tail = nullptr;
        int carry = 0;		//保存进位
        //当两个链表同时到达末尾时才结束循环
        while (l1 || l2) {
        	//获取l1和l2中的值;若为空,值为0;
            int n1 = l1 ? l1->val: 0;
            int n2 = l2 ? l2->val: 0;
            int sum = n1 + n2 + carry;
            //若链表为空,head和tail同时赋值,若不为空,添加到链表尾,并更新tail
            if (!head) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail->next = new ListNode(sum % 10);
                tail = tail->next;
            }
            //是否进位
            carry = sum / 10;
            //继续遍历链表
            if (l1) {
                l1 = l1->next;
            }
            if (l2) {
                l2 = l2->next;
            }
        }
        //若最后产生进位,链表需要新增一个节点
        if (carry > 0) {
            tail->next = new ListNode(carry);
        }
        return head;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/add-two-numbers/solution/liang-shu-xiang-jia-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.删除链表的倒数第N个节点

题目描述:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?

示例1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例2:
输入:head = [1], n = 1
输出:[]

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

1)我的思路

/**
 * 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* removeNthFromEnd(ListNode* head, int n) {
        int sz=0;
        ListNode* head2=head;
        //遍历求长度
        while(head2!=nullptr)
        {
            sz++;
            head2=head2->next;
        }
        //如果删除的是头结点
        if(sz==n)
        {
            head=head->next;
            return head;
        }
        head2=head;
        //求倒数第n个节点的前节点
        while((sz-n)>1)
        {
            head2=head2->next;
            sz--;
        }
        //删除第n个节点
        ListNode* temp=head2->next;
        head2->next=temp->next;
        delete temp;
        return head;
    }
};

2)官方解答

使用双指针:使用first和second指针,先让first指针走n步,然后first指针和second指针同步走,这样就会导致first指针和second指针相差n。最后当first指针为空时,second指针恰好是倒数第n个节点。
但是我们需要指导倒数第n个节点的前驱节点,才可以删除倒数第n个节点,因此second指针可以指向哑结点。

哑结点:哑结点的next指针指向头结点,值为0;

/**
 * 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* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);
        ListNode* first = head;
        ListNode* second = dummy;
        for (int i = 0; i < n; ++i) {
            first = first->next;
        }
        while (first) {
            first = first->next;
            second = second->next;
        }
        second->next = second->next->next;
        ListNode* ans = dummy->next;
        delete dummy;
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-b-61/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3.合并两个有序链表

题目描述:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例2:
输入:l1 = [], l2 = []
输出:[]

示例3:
输入:l1 = [], l2 = [0]
输出:[0]

1)我的思路

/**
 * 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* mergeTwoLists(ListNode* l1, ListNode* l2) {
        //边界条件判断
        if(l1==nullptr)     return l2;
        else if(l2==nullptr)        return l1;
        ListNode* ans=new ListNode();
        ListNode* tail=new ListNode(0,ans);
        //初始化ans
        if(l1->val<l2->val)  
        {
            ans=l1;
            tail=ans;
            l1=l1->next;
        }
        else    
        {
            ans=l2;
            tail=ans;
            l2=l2->next;
        }
        //一直到l1或者l2为空
        while(l1 && l2)
        {
           if(l1->val>l2->val)
           {
               ListNode* node=new ListNode();
               node->val=l2->val;
               tail->next=node;
               tail=node;
               l2=l2->next;
           }
           else
           {
               ListNode* node=new ListNode();
               node->val=l1->val;
               tail->next=node;
               tail=node;
               l1=l1->next;
           }
       }
       //若l1为空,连接l2
        if(l1==nullptr)
        {
            while(l2)
            {
                ListNode* node=new ListNode();
                node->val=l2->val;
                tail->next=node;
                tail=node;
                l2=l2->next;
            }
        }
        else if(l2==nullptr)
        {
            while(l1)
            {
                ListNode* node=new ListNode();
                node->val=l1->val;
                tail->next=node;
                tail=node;
                l1=l1->next;
            }
       }
       return ans;
    }     
};

2)官方解答:

(1)递归调用

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr) {
            return l2;
        } else if (l2 == nullptr) {
            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;
        }
    }
};

(2)遍历

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);

        ListNode* prev = preHead;
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val < l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }

        // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev->next = l1 == nullptr ? l2 : l1;

        return preHead->next;
    }
};

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

4.合并k个升序链表

题目描述:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例2:
输入:lists = []
输出:[]

示例3:
输入:lists = [[]]
输出:[]

1)我的思路

/**
 * 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) {}
 * };
 */
 ListNode* mergeTwoLists(ListNode* l1,ListNode*l2)
 {
     if (l1 == nullptr) {
            return l2;
        } else if (l2 == nullptr) {
            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;
        }
 }

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode* head=nullptr;
        for(vector<ListNode*>::iterator it=lists.begin();it!=lists.end();it++)
        {
            if(it==lists.begin())
            {
                head=*it;
                continue;
            }
            head=mergeTwoLists(head,*it);
        }
        return head;

    }
};

2)官方解答

class Solution {
public:
    ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
        if ((!a) || (!b)) return a ? a : b;
        ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
        while (aPtr && bPtr) {
            if (aPtr->val < bPtr->val) {
                tail->next = aPtr; aPtr = aPtr->next;
            } else {
                tail->next = bPtr; bPtr = bPtr->next;
            }
            tail = tail->next;
        }
        tail->next = (aPtr ? aPtr : bPtr);
        return head.next;
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode *ans = nullptr;
        for (size_t i = 0; i < lists.size(); ++i) {
            ans = mergeTwoLists(ans, lists[i]);
        }
        return ans;
    }
};

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

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

题目描述:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
第一个节点与第二个节点交换,第三个节点与第四个节点交换,以此类推。

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

示例2:
输入:head = []
输出:[]

示例3:
输入:head = [1]
输出:[1]

1)我的思路

/**
 * 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) {
        //head为空或者只有一个节点
        if(head==nullptr||head->next==nullptr)   return head;
        ListNode* next=head->next;
        head->next=next->next;
        next->next=head;
        //递归调用
        if(head->next!=nullptr)
        {
            head->next=swapPairs(head->next);
        }
        //next会变成新的头结点
        return next;
    }
};

2)官方解答:

思路与算法

创建哑结点 dummyHead,令 dummyHead.next = head。令 temp 表示当前到达的节点,初始时 temp = dummyHead。每次需要交换 temp 后面的两个节点。
如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。
具体而言,交换之前的节点关系是 temp -> node1 -> node2,交换之后的节点关系要变成 temp -> node2 -> node1,因此需要进行如下操作。

temp.next = node2
node1.next = node2.next
node2.next = node1

完成上述操作之后,节点关系即变成 temp -> node2 -> node1。再令 temp = node1,对链表中的其余节点进行两两交换,直到全部节点都被两两交换。
两两交换链表中的节点之后,新的链表的头节点是 dummyHead.next,返回新的链表的头节点即可。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* temp = dummyHead;
        while (temp->next != nullptr && temp->next->next != nullptr) {
            ListNode* node1 = temp->next;
            ListNode* node2 = temp->next->next;
            temp->next = node2;
            node1->next = node2->next;
            node2->next = node1;
            temp = node1;
        }
        return dummyHead->next;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/solution/liang-liang-jiao-huan-lian-biao-zhong-de-jie-di-91/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

6.翻转链表

题目描述:
翻转一个给定链表。

示例1:
输入:list = [1,2,3,4,5]
输出:[5,4,3,2,1]

/**
 * 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* head) {
	if(head==nullptr||head->next==nullptr)	return head;
	ListNode* current=head;
	ListNode* pre=nullptr;
	while(current)
	{
		ListNode* temp=current->next;
		current->next=pre;
		pre=current;
		current=temp;
	}
	
	return pre;
	}
}

7.K个一组翻转链表

题目描述:
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

进阶:
你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

示例3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]

示例4:
输入:head = [1], k = 1
输出:[1]

class Solution {
public:
    // 翻转一个子链表,并且返回新的头与尾
    pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
        ListNode* prev = tail->next;
        ListNode* p = head;
        while (prev != tail) {
            ListNode* nex = p->next;
            p->next = prev;
            prev = p;
            p = nex;
        }
        return {tail, head};
    }

    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* hair = new ListNode(0);
        hair->next = head;
        ListNode* pre = hair;

        while (head) {
            ListNode* tail = pre;
            // 查看剩余部分长度是否大于等于 k
            for (int i = 0; i < k; ++i) {
                tail = tail->next;
                if (!tail) {
                    return hair->next;
                }
            }
            ListNode* next = tail->next;
            // 这里是 C++17 的写法,也可以写成
            // pair<ListNode*, ListNode*> result = myReverse(head, tail);
            // head = result.first;
            // tail = result.second;
            tie(head, tail) = myReverse(head, tail);
            // 把子链表重新接回原链表
            pre->next = head;
            tail->next = nex;
            pre = tail;
            head = tail->next;
        }

        return hair->next;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/solution/k-ge-yi-zu-fan-zhuan-lian-biao-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值