1、删除问题
递归删除的思路:
- 先删除,再不断往后递归(迭代思路,手动删除)
- 先递归到最后,递归的过程制定连接规则;符合的return当前head,不符合的返回head->next,也就是删除了当前head,作为下一次栈弹出的返回值。
- 写完代码,完整地写出递归调用栈的弹出过程,即可知道递归写的对不对
五种解题方法:6种写法
- 带头结点迭代删除:最基础最简单的方法
pre->next = pre->next->next; - 带头结点递归删除:
- 递归无返回值写法:先删除,后递归【迭代的思路】,带头结点,删除的结点是next结点,没啥好说的和迭代一样
- 不带头结点迭代删除:注意head位置删除对于空指针的处理
- 不带头结点递归删除
- 递归无返回值写法:先删除,后递归【迭代的思路】 (由于是不带头结点,删除的结点就是当前结点,则可能断链,因此要传入引用!!)
- 递归有返回值的两种写法:都是先递归到尾,制定连接/删除规则;再从后往前根据弹出返回值head连接
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
return func6(head, val);
}
ListNode* func1(ListNode* head, int val){
ListNode* dummyNode = new ListNode();
dummyNode->next = head;
ListNode* pre = dummyNode;
while(pre->next != NULL){
if(pre->next->val == val)
pre->next = pre->next->next;
else
pre = pre->next;
}
return dummyNode->next;
}
ListNode* func2(ListNode* head, int val){
ListNode* dummyNode = new ListNode();
dummyNode->next = head;
recursion1(dummyNode, val);
return dummyNode->next;
}
void recursion1(ListNode* dummyNode, int val){
if(dummyNode->next == NULL)
return ;
else if(dummyNode->next->val == val){
dummyNode->next = dummyNode->next->next;
recursion1(dummyNode, val);
}
else
recursion1(dummyNode->next, val);
}
ListNode* func3(ListNode* head, int val){
while(head != NULL && head->val == val)
head = head->next;
if(head == NULL) return NULL;
ListNode* pre = head;
while(pre->next != NULL){
if(pre->next->val == val)
pre->next = pre->next->next;
else
pre = pre->next;
}
return head;
}
ListNode* func4(ListNode* head, int val){
recursion2(head, val);
return head;
}
void recursion2(ListNode* &head, int val){
if(head == NULL)
return ;
else if(head->val == val){
ListNode* delNode = head;
head = head->next;
delete delNode;
recursion2(head, val);
}
else
recursion2(head->next, val);
}
ListNode* func5(ListNode* head, int val){
if(head == NULL)
return head;
else if(head->val == val)
return func5(head->next, val);
else
head->next = func5(head->next, val);
return head;
}
ListNode* func6(ListNode* head, int val){
if(head == NULL)
return head;
head->next = func6(head->next, val);
if(head->val == val)
return head->next;
return head;
}
};
题解
2、逆置链表
1、迭代法:新建pre结点
p往哪里插:用pre指向p->next位置
新建pre,也相当于头插法新建一个dummyHead
时间复杂度:O(N):遍历整个链表1次 空间复杂度:O(1):只需要新建一个pre结点
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
ListNode *pre = NULL;
ListNode *p = head;
ListNode *r;
while(p){
r = p->next;
p->next = pre;
pre = p;
p = r;
}
return pre;
}
};
2、头插法
p往哪里插:用dummyHead->next指向p->next位置【本质和第一种方法没区别】
时间复杂度:O(N):遍历整个链表1次 空间复杂度:O(1):
dummyHead->next = NULL; 的两种含义:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
ListNode* dummyHead = new ListNode();
dummyHead->next = NULL;
ListNode* p = head;
ListNode* r = head;
while(p != NULL){
r = p->next;
p->next = dummyHead->next;
dummyHead->next = p;
p = r;
}
return dummyHead->next;
}
};
1、递归
时间复杂度O(N) 空间复杂度O(N):递归栈
using namespace std;
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
wangdao_02(head);
return NULL;
}
void wangdao_02(ListNode* head){
func1(head);
}
void func1(ListNode* head){
if(head == NULL)
return ;
wangdao_02(head->next);
printf("%d",head->val);
}
void func2(ListNode* dummyNode){
if(dummyNode->next == NULL)
return ;
func2(dummyNode->next);
printf("%d", dummyNode->next->val);
}
};
2. 先逆置链表,再正序输出
时间复杂度:O(N):逆置链表和正序输出都是O(N) 空间复杂度:O(1):原地逆置不消耗空间
4. 拆分链表
using namespace std;
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* dummyHeadA = new ListNode();
dummyHeadA->next = head;
ListNode* headx = wd_11(dummyHeadA);
ListNode* p = headx;
while (p != NULL){
printf("%d", p->val);
p = p->next;
}
return NULL;
}
ListNode* wd_10(ListNode* dummyHeadA){
ListNode* dummyHeadB = new ListNode();
ListNode* tailB = dummyHeadB;
ListNode* preA = dummyHeadA;
int i = 0;
while(preA->next != NULL){
if(i % 2 == 0){
tailB->next = preA->next;
tailB = tailB->next;
preA->next = preA->next->next;
}
else
preA = preA->next;
i += 1;
}
tailB->next = NULL;
return dummyHeadA->next;
}
ListNode* wd_11(ListNode* dummyHeadA){
ListNode* dummyHeadB = new ListNode();
dummyHeadB->next = NULL;
ListNode* preA = dummyHeadA;
ListNode* pA = new ListNode();
int i = 0;
while(preA->next != NULL){
if(i % 2 == 0){
pA = preA->next;
preA->next = preA->next->next;
pA->next = dummyHeadB->next;
dummyHeadB->next = pA;
}
else
preA = preA->next;
i += 1;
}
return dummyHeadB->next;
}
};
5. 去重
注意递归方法
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
return func2(head);
}
ListNode* func1(ListNode* head){
ListNode* p = head;
while(p != NULL){
if(p->next != NULL && p->next->val == p->val){
ListNode* delNode = p->next;
p->next = p->next->next;
delete delNode;
}
else
p = p->next;
}
return head;
}
ListNode* func2(ListNode* head){
if(head == NULL || head->next == NULL)
return head;
head->next = func2(head->next);
if(head->val == head->next->val)
return head->next;
return head;
}
};
6. 两个有序链表
- leetcode 21:合并两升序为1升序,使用原节点
- 王道13:合并两升序为1逆序,使用原节点
- 王道14:找到两有序链表公共元素,new一个新链表存放公共元素,结点都新new
- 王道15:找到两有序链表l1,l2的公共元素,l1存放公共元素。【本题特地写成了含有delete的形式,注意参考】
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
return wd_15(l1, l2);
}
ListNode* func(ListNode* l1, ListNode* l2){
if(l1 == NULL && l2 == NULL)
return NULL;
ListNode* dummyNode = new ListNode(-101);
ListNode* tail = dummyNode;
while(l1 && l2){
if(l1->val <= l2->val){
tail->next = l1;
l1 = l1->next;
tail = tail->next;
}
else{
tail->next = l2;
l2 = l2->next;
tail = tail->next;
}
}
if(l1)
tail->next = l1;
if(l2)
tail->next = l2;
return dummyNode->next;
}
ListNode* wd_13(ListNode* l1, ListNode* l2){
ListNode* dummyHead = new ListNode();
dummyHead->next = NULL;
ListNode* r = new ListNode();
while(l1 && l2){
if(l1->val < l2->val){
r = l1->next;
l1->next = dummyHead->next;
dummyHead->next = l1;
l1 = r;
}
else{
r = l2->next;
l2->next = dummyHead->next;
dummyHead->next = l2;
l2 = r;
}
}
while(l1){
r = l1->next;
l1->next = dummyHead->next;
dummyHead->next = l1;
l1 = r;
}
while(l2){
r = l2->next;
l2->next = dummyHead->next;
dummyHead->next = l2;
l2 = r;
}
return dummyHead->next;
}
ListNode* wd_14(ListNode* l1, ListNode* l2){
ListNode* dummyHead = new ListNode();
ListNode* tail = dummyHead;
while(l1 && l2){
if(l1->val == l2->val){
ListNode* newNode = new ListNode(l1->val);
tail->next = newNode;
tail = tail->next;
l1 = l1->next;
l2 = l2->next;
}
else if(l1->val < l2->val)
l1 = l1->next;
else
l2 = l2->next;
}
tail->next = NULL;
return dummyHead->next;
}
ListNode* wd_15(ListNode* l1, ListNode* l2){
ListNode* dummyHead1 = new ListNode();
dummyHead1->next = l1;
ListNode* pre1 = dummyHead1;
ListNode* delNode = new ListNode();
while(pre1->next != NULL && l2 != NULL){
if(pre1->next->val == l2->val){
pre1 = pre1->next;
delNode = l2;
l2 = l2->next;
delete delNode;
}
else if(pre1->next->val < l2->val){
delNode = pre1->next;
pre1->next = pre1->next->next;
delete delNode;
}
else{
delNode = l2;
l2 = l2->next;
delete delNode;
}
}
while(pre1->next != NULL){
delNode = pre1->next;
pre1->next = pre1->next->next;
delete delNode;
}
while(l2 != NULL){
delNode = l2;
l2 = l2->next;
delete delNode;
}
return dummyHead1->next;
}
};
真题
using namespace std;
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
return exam_2020(head);
}
ListNode* exam_2020(ListNode* head){
ListNode* dummyNode = new ListNode();
dummyNode->next = head;
ListNode* curNode = dummyNode;
ListNode* pre_maxNode = dummyNode;
ListNode* pre_minNode = dummyNode;
float cur_sum =0, len = 0;
while(curNode->next != NULL){
cur_sum += curNode->next->val;
len += 1;
if(curNode->next->val > pre_maxNode->next->val)
pre_maxNode = curNode;
if(curNode->next->val < pre_minNode->next->val)
pre_minNode = curNode;
curNode = curNode->next;
}
printf("\nmax:%d\t", pre_maxNode->next->val);
printf("min:%d\t", pre_minNode->next->val);
printf("sum:%f\t", cur_sum);
float new_avg = (cur_sum - pre_maxNode->next->val - pre_minNode->next->val) / (len-2);
printf("\n删除后平均值:%.2f", new_avg);
if(pre_maxNode->next == pre_minNode)
pre_maxNode->next = pre_maxNode->next->next->next;
else if(pre_minNode->next == pre_maxNode)
pre_minNode->next = pre_minNode->next->next->next;
else{
pre_maxNode->next = pre_maxNode->next->next;
pre_minNode->next = pre_minNode->next->next;
}
printf("\n输出删除后链表: ");
ListNode* p = dummyNode;
while(p->next!=NULL){
printf("%d", p->next->val);
p = p->next;
}
return dummyNode->next;
}
};
思路
注意点:
- 元素值各不相同,代表min和max不是同一个结点,这个很重要
- 计算平均值除法要得到小数值,要doube/double或者float/float,;
printf("删除后链表avg:%0.2lf\n", avg); :0.2表示保留两位小数
思路一:遍历链表2次:
O
(
2
N
)
O(2N)
O(2N)
- 遍历原链表,找到最大值并删除,得到链表1
- 遍历链表1,找到最小值并删除,得到链表2
- 遍历链表3,计算平均值
稍微优化下,第三步可以在第一步就求出所有元素和然后减去min和max即可 该方法唯一优点就是:删除思路简单,由于min,max不是同一个结点,删除一个个来就行了
思路二:遍历一次链表即可:
O
(
N
)
O(N)
O(N)
- 遍历原链表做以下事情:
- 计算所有元素和
- 找到最大值结点p的pre_p
- 找到最小值结点q的pre_q
- 计算剩余链表平均值
- 删除min和max结点【考虑二者相对位置】
- 情况1:->pre_p->p->[…]->pre_q->q->:
pre_p->next = pre_p->next->next 【可以=pre_q】 pre_q->next = pre_q->next->next - 情况2:
if(pre_p->next = pre_q) :->pre_p->p/pre_q->q-> pre_p->next = pre_p->next->next->next 【同时删除p,q】if(pre_q->next = pre_p) : ->pre_q->q/pre_p->p-> pre_q->next = pre_q->next->next->next 【同时删除p,q】
|