emmm,链表刷完,感悟挺多的。
如果是对链表节点直接利用的话,是要小心成环的,因为一个节点那可不是你眼里的一个节点,人家可能是一桶节点。
这些天做题我可算真切感受到了。
第一题:合并两个有序链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第二题:回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第三题:环型链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/linked-list-cycle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的题解(1)
在吃过多次链表成环的亏之后,我学聪明了。
#include<iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
//////////创建结点/////////
ListNode* creat(int data)
{
ListNode* p = new ListNode(NULL);
p->val = data;
p->next = NULL;
return p;
}
ListNode* my_merge(ListNode* l1, ListNode* l2)
{
ListNode* head = l1; //留住头结点
while (l1->next != NULL && l2 != NULL)
{
//默认l1的头比l2的小
if (l1->val <= l2->val && l1->next->val>l2->val) //将新节点插入
{
ListNode* temp = creat(l2->val);
temp->next = l1->next;
l1->next = temp;
l1 = l1->next;
l2 = l2->next;
}
else
{
l1 = l1->next;
}
}
//l1走完,l2还没完
if (l1->next == NULL && l2 != NULL)
{
l1->next = l2;
}
return head;
}
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
if(l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
ListNode *head = NULL;
if (l1->val < l2->val)
head = my_merge(l1,l2);
else
head = my_merge(l2,l1);
return head;
}
int main()
{
ListNode* a = new ListNode(1);
ListNode* b = new ListNode(3);
ListNode* c = new ListNode(4);
// ListNode* d = new ListNode(8);
ListNode* e = new ListNode(1);
ListNode* f = new ListNode(2);
ListNode* g = new ListNode(4);
// ListNode* h = new ListNode(9);
a->next = b;
b->next = c;
// c->next = d;
e->next = f;
f->next = g;
// g->next = h;
ListNode* i = mergeTwoLists(e,a);
while (i != NULL)
{
cout << i->val;
i = i->next;
}
}
我的题解(2)
不得不说,官方题解秀。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int len;
bool isPalindrome(ListNode* head) {
if(head == NULL || head->next == NULL) {
return true;
}
len = 0;
ListNode* re = reLink(head);
int length = 0;
while(head != NULL) {
if(head->val != re->val)
return false;
re = re->next;
head = head->next;
length++;
if(length > len/2)
break;
}
return true;
}
ListNode* reLink(ListNode* head) {
ListNode* temp = head;
ListNode* re = NULL;
while(temp){
ListNode* node = new ListNode(temp->val);
node->next = re;
re = node;
temp = temp->next;
len++;
}
return re;
}
};
我的题解(3)
先看上面这篇。
掌握了方法,简单的很。
bool hasCycle(ListNode* head)
{
if (head == NULL || head->next == NULL)
return false;
ListNode* fast = head;
ListNode* slow = head;
fast = fast->next->next;
while (fast!=NULL && fast->next != NULL && fast!=slow)
{
slow = slow->next;
fast = fast->next->next;
}
if (fast == slow)
return true;
else
return false;
}
官方题解(1)
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
else if (l2 == null) {
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;
}
}
}
> 作者:LeetCode-Solution
> 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
> 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
官方题解(2)
方法三:
避免使用 O(n)O(n) 额外空间的方法就是改变输入。
我们可以将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,因为使用该函数的人不希望链表结构被更改。
算法:
我们可以分为以下几个步骤:
找到前半部分链表的尾节点。
反转后半部分链表。
判断是否为回文。
恢复链表。
返回结果。
执行步骤一,我们可以计算链表节点的数量,然后遍历链表找到前半部分的尾节点。
或者可以使用快慢指针在一次遍历中找到:慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时,慢指针到链表的中间。通过慢指针将链表分为两部分。
若链表有奇数个节点,则中间的节点应该看作是前半部分。
步骤二可以使用在反向链表问题中找到解决方法来反转链表的后半部分。
步骤三比较两个部分的值,当后半部分到达末尾则比较完成,可以忽略计数情况中的中间节点。
步骤四与步骤二使用的函数相同,再反转一次恢复链表本身。
作者:LeetCode
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
官方题解(3)
和我的一样。
总结:
链表,小心成环,每个节点到底隐藏了多少,需要我们去画图缕清楚。
然后,推荐环形链表里的那篇博客>>l链表误成环