题目链接:https://leetcode-cn.com/problems/reverse-linked-list/
思路一:双指针解决
定义1个prev的前驱指针,cur来工作指针,next来保存cur的下一个,如果不保存cur的下一个,cur指向prev后则找不到cur的next了。当cur走到空时循环结束。注意返回头结点,结束时头结点是prev
。
如下图:
代码如下:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//定义1个前驱指针
ListNode* prev = nullptr;
ListNode* cur = head;
while(cur)
{
ListNode* next = cur->next;
//修改链接关系
cur->next = prev;
//继续迭代往下走
prev = cur;
cur = next;
}
//最后的头是prev
return prev;
}
};
思路二:头插法
设定义1个newhead为头指针,next保存cur的下一个,依次拿下头插,在更新头接节点即可。
代码如下:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* newhead = nullptr;
ListNode* cur = head;
while(cur)
{
ListNode* next = cur->next;
//取下来头插
cur->next = newhead;
//更新头结点
newhead = cur;
cur = next;
}
return newhead;
}
};
题目链接:https://leetcode-cn.com/problems/middle-of-the-linked-list/description/
分析:快慢指针解决问题,slow走1步,fast走2步,当结点个数为奇数个,循环结束条件是fast的next为空,当结点个数为偶数个,fast走到空就结束了,总结循环结束的条件为fast且fast的next不为空
代码如下:
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* slow,*fast = head;
while(fast && fast->next)
{
//慢的走1步,快的走2步
slow=slow->next;
fast=fast->next->next;
}
//最后返回慢的就是中间结点
return slow;
}
};
题目链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
思路跟上面的找中间结点是一样的,快的先走K步,注意的细节是:当K大于链表的长度,fast会空指针的问题。
代码如下;
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
ListNode *slow = head;
ListNode *fast = head;
//快的先走k步,在同时一起走
while(k--)
{
if(fast == nullptr)
return nullptr;
fast = fast->next;
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
题目链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/submissions/
思路:用1个带哨兵卫的来解决,比较2个链表结点的值,将小的拿下来尾插即可。
tail要记录尾结点来尾插,当2个结点的值一样的随便拿哪个下来尾插都行,当其中1个链表有1个走完就将没走完全部链在后面,因为它是有序的
。当其中1个链表为空,就返回另一个链表。
代码如下:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
//当2个链表其中1个为空的情况
if(list1 == nullptr)
return list2;
if(list2 == nullptr)
return list1;
//用带哨兵卫的头结点尾插解决
ListNode* newnode=new ListNode(0);
ListNode* l1 = list1;
ListNode* l2 = list2;
//定义tail来记录尾指针
ListNode* tail = newnode;
//当有1个链表走完,循环就结束
while(l1 && l2)
{
//比较2个链表的结点值的大小
//小的拿下去尾插
if(l1->val <= l2->val)
{
tail->next = l1;
tail = l1;
l1 = l1->next;
}
else
{
tail->next = l2;
tail = l2;
l2 = l2->next;
}
}
//当2个链表中有1个走完就将剩下的全链接起来
if(l1)
tail->next = l1;
if(l2)
tail->next = l2;
//记得释放哨兵卫的头
//先记录头的下一个,在释放
ListNode* head = newnode->next;
delete(newnode);
return head;
}
};
题目链接:https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking
牛客的题目给的条件有点少,题目要求不能改变原来的数据顺序。思路:根据上一题的经验用带哨兵卫头结点来解决。
搞2个哨兵卫,cur比x的值小就尾插到1个的后面,大的尾插到另一个哨兵后,当cur走到空时,最后less链接在graterTail的后面。
代码如下:
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
//开2个哨兵卫的头结点
ListNode* lessHead = new ListNode(0);
ListNode* graterHead = new ListNode(0);
ListNode* cur = pHead;
//定义2个指针分别指向头结点
ListNode* lessTail = lessHead;
ListNode* gratertail = graterHead;
while(cur)
{
//小的尾插到小的后面
if(cur->val < x)
{
lessTail->next = cur;
lessTail = cur;
}
//大的尾插到大的后面
else
{
gratertail->next = cur;
gratertail = cur;
}
cur = cur->next;
}
//分别先保存头的下一个结点,在释放哨兵卫的头
lessTail->next = graterHead->next;
ListNode* first = lessHead->next;
delete(graterHead);
delete(lessHead);
//左后返回小的
return first;
}
};
提交看看:
他说内存不够用,我们只是开了2个结点而已。看下图:
我们只是拿下来尾插,没有动结点的next,此时20的next还是指向的9,此时链表代码进入死循环了,所以要将 大的尾结点的next置空
。