由于之前看了牛客网的数据结构和算法的课程知道了左神,现在找到了这本书当作入门书做做吧,虽然书的题解都是java实现的,但好在用c++实现难度不大。
第二章 链表问题
第一题:翻转部分单向链表
本题有可能存在换头问题
1.先判断是否满足条件
2.找到第from-1和to+1个节点,把翻转部分先翻转,然后正确连接
3.如果fpr!=NULL直接返回新的头节点;如果为NULL,说明翻转部分是包含头节点的,则连接后返回head;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* reversePartOfList(ListNode* head,int from,int to){
if (head==NULL||head->next==NULL)
{
return head;
}
int len=0;
ListNode* cur=head;
ListNode* fpr=NULL;
ListNode* tpo=NULL;
while (cur!=NULL)
{
++len;
fpr=len==from-1?cur:fpr;
tpo=len==to+1?cur:tpo;
cur=cur->next;
}
if(from>to||from<1||to>len){
return head;
}
//不知道怎么分配翻转用的pre、cur、next;
ListNode* pre=NULL;
pre=fpr==NULL?head:fpr->next;
pre->next=tpo;
cur=pre->next;
ListNode* next=NULL;
while (cur!=tpo)
{
next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
if (fpr!=NULL)
{
fpr->next=cur;
return head;
}
return pre;//之前return了cur,而cur是null的
}
第二题:判断一个链表是否为回文结构
方法三:不需要栈和其他数据结构,只用三个变量,额外空间复杂度为O(1),就可以在时间复杂度为O(N)内完成所有过程
1.改变链表右半区的结构,使其翻转,指向中间节点
2.两端节点头同时向中间点移动并比较是否相等,即判断是否回文,当出现否的情况是直接break循环
3.恢复链表原先结构,返回检查结果
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
bool isPalindrome(ListNode* head){
if(head==NULL||head->next==NULL){
return true;
}
ListNode* n1=head,*n2=head;
//找到中间点n1
while (n2->next!=NULL&&n2->next->next!=NULL)
{
n1=n1->next;
n2=n2->next->next;
}
bool res=true;
//开始翻转
ListNode* n3=NULL;
n2=n1->next;
n1->next=NULL;
while (n2!=NULL)
{
n3=n2->next;
n2->next=n1;
n1=n2;
n2=n3;
}
//之前没有保存最后一个节点导致检查完后无法复原,同时也没有用n2代替head进行接下来的检查
n3=n1;
n2=head;
//检查回文
while(head!=NULL&&n1!=NULL){//之前用的head去比较,那样会改变原head,与本愿相违
if (head->val!=n1->val)
{
res=false;
break;//少加了个break
}
head=head->next;
n2=n2->next;
}
n1=n3->next;
n3->next=NULL;
while(n1!=NULL){
n2=n1->next;
n1->next=n3;
n3=n1;
n1=n2;
}
return res;
}