BM1 反转链表
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
数据范围: 0≤n≤1000
要求:空间复杂度 O(1) ,时间复杂度 O(n) 。
如当输入链表{1,2,3}时,
经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。
思考:
空间o1,时间on,链表倒置,用头插法处理即可,注意特判。
代码:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include <cstddef>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* ReverseList(ListNode* head) {
// write code here
if (!head) return nullptr;
ListNode* t = head;
head = head->next;
t->next = nullptr;
while (head){
ListNode* tmp = head;
head = head->next;
tmp->next = t;
t = tmp;
}
return t;
}
};
BM2 链表内指定区间反转 ※
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。
例如:
给出的链表为 1→2→3→4→5→NULL, m=2,n=4
返回 1→4→3→2→5→NULL
数据范围: 链表长度 0<size≤1000,0<m≤n≤size,链表中每个节点的值满足 ∣val∣≤1000
要求:时间复杂度 O(n)O(n) ,空间复杂度 O(n)O(n)
进阶:时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)
思考:
在刚才的题目之上进行改进。遍历整个链表,在指定的起始位置开始头插法,在指定的终点结束,最后返回头指针。
代码:
这道题目是今天做的最难的一道题目,也是最有收获的一道题目
收获一:
在使用头插法逆置的过程中,可以灵活使用尾指针,防止在一次遍历的过程中断链。
在链表的计算中,应该更灵活的使用指针,而不是只用一个头指针然后多次遍历。
收获二:
指向元素的head指针不是万能的,可能指向的元素,在链表中被调换位置,并非头指针
收获三:
ListNode* t = new ListNode(0); // 空指针
在牛客里,空指针的申请方式,不然分分钟段错误……
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
ListNode* reverseBetween(ListNode* head, int m, int n) {
// write code here
ListNode* t = new ListNode(0); // 空指针
t->next = head;
ListNode* pre = t;
for (int i = 1;i < m;i++) pre = pre->next;
ListNode* res = t;
t = pre->next;
ListNode* llast = t;
for (int i = m;i <= n;i++) {
ListNode* tmp = t;
t = t->next;
tmp->next = pre->next;
pre->next = tmp;
llast->next = t;
}
// return head; 这里是不能用head返回的,
// 因为head指针链接在元素上,而这个元素是存在被逆置的可能性
return res->next;
}
};
BM4 合并两个排序的链表
描述
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
数据范围: 0≤n≤10000≤n≤1000,−1000≤节点值≤1000−1000≤节点值≤1000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
思考:
有递归,非递归两种解法,要注意代码实现上的一些问题
代码:
非递归版本
注意两个链表比较的时候要用,<=在这里错了一次
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
// write code here
ListNode* head = new ListNode(0);
ListNode* tt = head;
head->next = tt;
while (true) {
if (pHead1 == nullptr && pHead2 == nullptr) {tt->next = nullptr;break;}
if (pHead1 == nullptr) {tt->next = pHead2;break;}
if (pHead2 == nullptr) {tt->next = pHead1;break;}
if (pHead1->val <= pHead2->val) {
tt->next = pHead1;
pHead1 = pHead1->next;
tt = tt->next;
continue;
}
if (pHead2->val <= pHead1->val) {
tt->next = pHead2;
pHead2 = pHead2->next;
tt = tt->next;
continue;
}
}
head = head->next;
return head;
}
};
递归版本
在递归的思路中,仅返回当前情况下需要的指针即可
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
// write code here
if (pHead1 == nullptr && pHead2 == nullptr) return nullptr;
if (pHead1 == nullptr) return pHead2;
if (pHead2 == nullptr) return pHead1;
// 三种递归的终止条件
if (pHead1->val <= pHead2->val) {
ListNode* res = pHead1;
pHead1 = pHead1->next;
res->next = Merge(pHead1, pHead2);
return res;
}
if (pHead2->val <= pHead1->val) {
ListNode* res = pHead2;
pHead2 = pHead2->next;
res->next = Merge(pHead1, pHead2);
return res;
}
return nullptr;
}
};
297

被折叠的 条评论
为什么被折叠?



