今天又把昨天卡了很久的设计链表题 试试能不能说是用不带长度的去写出来 但是试了很久就失败了 因此以后就用带长度的做就行了。 目前没办法用不带长度的做出来,以后可能实力强了再说吧
今天的第一题 虽然是二刷但是刚开始还是没思路 不知道怎么换 其实是要引入虚拟头结点
注意啊 注意 1 你引入了虚拟头结点后要把它的next置为头结点 这样才算成功引入了。
2这道题有一个关键就是 你pre指向的是prehead的话 那么再下一次挪的话 你还得是指向pre那个元素 而不能向后指一位 总体而言这个题就是引入了一个prehead 没什么难的
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* prehead=new ListNode();
prehead->next=head;
ListNode* pre=prehead;
ListNode* p=prehead->next;
ListNode* tem;
while(p!=NULL&&p->next!=NULL){
pre->next=p->next;
tem=p->next;
p->next=p->next->next;
tem->next=p;
pre=p;
p=pre->next;
}
head=prehead->next;
delete prehead;
return head;
}
};
它要是给你一个链表那就不能用size了 如果是让你去设计一个链表 那完全可以用加个size.
3现在还有个问题就是你要注意代码的边界问题 你要说是把代码写在规定的地方。
第二个题 删除链表的倒数第N个结点 二刷 几乎一遍过 就是想明白就行 不要遗留问题:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* prehead=new ListNode();
prehead->next=head;
ListNode* slow=prehead,*fast=prehead;
for(int i=1;i<=n+1;i++)
fast=fast->next;
while(fast!=NULL){
slow=slow->next;
fast=fast->next;
}
ListNode* tem=slow->next;
slow->next=slow->next->next;
delete tem;
head=prehead->next;
delete prehead;
return head;
}
};
还有一个问题是你没底的原因还是在于练的少 如果你基本提交一次过 那肯定就很有底了 不过不用着急 就是按着事情发生走就行 焦虑以后的事情完全没意义
第二道题 链表相交
二刷 几乎一遍过
唯一注意的一点就是 你在用ListNode *A=headA,*B=headB; 这么去用的时候 不能写成ListNode *A=headA,ListNode*B=headB; 这样不行 因为你要去连着定义 你就不能用两个Listnode类型。
其他没有什么 简单的小题
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *A=headA,*B=headB;
int a=0,b=0;
for(;A!=NULL;a++){
A=A->next;
}
for(;B!=NULL;b++)
B=B->next;
A=headA;
B=headB;
if(a>=b){
for(int i=a-b;i>0;i--)
A=A->next;
}
else{
for(int i=b-a;i>0;i--)
B=B->next;
}
while(A!=NULL&B!=NULL){
if(A==B){
return A;
}
A=A->next;
B=B->next;
}
return NULL;
}
};
第四题:
环形链表 这就是纯纯的数学题 虽然是第二次刷了 但是那些公式还是不好背
就是得背公式。
首先一个点是: 就是让快指针走两步 慢指针走一步 这样就肯定能在环里相遇 (如果没环的话 慢指针永远追不上快指针 所以肯定是在环里相遇)
第二个点是:相遇的位置怎么确定
这个公式肯定还是得自己推一下 不然根本记不住
其实主要关系就是fast走过的路=slow走过的路*2
但与其说去推公式 那太慢了 总而言之就是 因为fast是slow的两倍 所以你一定能找到他们相遇的结点 那么你得到一个相遇的结点 那么再去用从相遇结点出发和从起始结点出发的指针 再去相遇就是起始结点了 因为x=z 其他无非是再去转几圈
注意1 只有一个结点不会成环
2还有一个问题是一开始fast和slow是相等的 都指向第一个结点 所以循环根本不会执行 这里是个问题 因此要先赋值
3do {}while(); 要在最后whie的括号后面加分号 注意!!!
4还有一个问题就是你在判断是否为空上 如果你(fast==NULL&&fast->next==NULL)用这么去判断的话 那个如果fast为空 你还是会出错 所以只能说是分开 从循环中去判断 不是说你要去分开去判断 而是你这里应该用的是|| 而不是&& 因为是两个只要有一个满足就可以
另外也不用担心 因为:
你的观察是正确的。在C++中,如果一个指针是 NULL
,试图通过这个指针访问成员会导致未定义行为,通常会导致程序崩溃。
逻辑或操作符 ||
在C++中有一个“短路”行为。如果 ||
左边的表达式为 true
,那么 ||
右边的表达式就不会被求值。所以在 if(head==NULL || head->next==NULL)
这行代码中,如果 head
是 NULL
,那么 head->next
不会被访问,就不会出错。
有一个短路行为。
二刷 还是基本几次过的 还是简单的小题 主要就是要搞清楚||和&&的区别 和 一开始它们都相等 所以要先去移动指针 再去做比较。