1->一个单链表L0->L1->L2->.......->Ln-1->Ln,翻转链表使其成为L0->Ln->L1->Ln-1.........不能通过改变结点的值来实现
解题方法:找到链表的中间结点,断开链表,把后半部分链表reverse一下,再合并两个单链表。算法的时间复杂度为O(n),空间复杂度为O(1)
ListNode* Reverse(ListNode *head){ //反转链表的代码
if(head==NULL ||head->next==NULL) return head;
ListNode* cur=head;
ListNode* pre=NULL;
while(cur){
ListNode* pNext=cur->next;
cur->next=pre;
pre=cur;
cur=pNext;
}
head=pre;
return head;
}
void reorderList(ListNode *head){
if(head==NULL ||head->next==NULL) return ;
ListNode *prev=NULL; ListNode *pslow=head; ListNode *pfast=head;
while(pfast && pfast->next){
prev=pslow; pslow=pslow->next; pfast=pfast->next->next;
}
prev->next=NULL; //将链表从中间位置断开
pslow=Reverse(pslow); //将后半段链表反转
/*合并两个链表*/
ListNode* cur=head;
while(cur->next){
ListNode* tmp=cur->next; cur->next=pslow; pslow=pslow->next; cur->next->next=tmp; cur=tmp;
}
cur->next=pslow;
}
2->判断一个链表是否存在环
解题方法:设置两个指针,一个快一个慢,慢的一次走一步,快的一次走两步。如果两个相遇则说明存在环。
bool hasCycle(ListNode *head){
ListNode* p1=head;
ListNode* p2=head;
while(p2 &&p2->next){
p1=p1->next;
p2=p2->next->next;
if(p1==p2) return true;
}
return false;
}
3->先判断一个链表是否存在环,若存在返回环的入口结点,否则返回NULL
解题方法:
ListNode *detectCycle(ListNode *head){
ListNode *p1=head; ListNode* p2=head;
while(p2 && p2->next){
p1=p1->next; p2=p2->next->next;
if(p1==p2){
ListNode *p=head;
while(p!=p1){p=p->next; p1=p1->next}
return p;
}
}
return NULL;
}
4->复杂链表复制
解题方法:先复制链表的每个结点,再设置链表Random指针的指向,最后将链表拆分成两个链表。
struct RandomListNode{
int label;
RandomListNode *next,*random;
RandomListNode(int x):label(x),next(NULL),random(NULL){}
};
RandomListNode *copyRandomList(RandomListNode *head){
for(RandomListNode *cur=head ; cur!=NULL;){
RandomListNode *newNode=new RandomListNode(cur->lable); //创建新的结点
newNode->next=cur->next; cur->next=newNode; cur=newNode->next; //将新建的结点加入到当前链表
}
/*设置新建结点的Random指针的值*/
for(RandomListNode *cur=head;cur!=NULL;){
if(cur->random!=NULL) cur->next->random=cur->random->next;
cur->next->next;
}
/*将一个链表拆分成两个链表*/
RandomListNode dummy(-1);
for(RandomListNode *cur=head,*new_cur=&dummy;cur!=NULL;){
new_cur->next=cur->next; new_cur=new_cur->next;
cur->next=cur->next->next; cur=cur->next;
}
return dummy->next;
}
5->将一个链表分成KGroups,分别反转每一组内的链表。例如1->2->3->4->5.当k=2时,返回2->1->4->3->5.当k=3时返回3->2->1->4->5
解题方法:采用递归的方法按组逐个递归。
ListNode * reverseKGroup(ListNode* head,int k){
if(head==NULL ||head->next==NULL ||k<2) return head;
/*将链表分组,当出现剩余元素不足以构成一组时,不反转*/
ListNode *next_group=head;
for(int i=0;i<k;i++){
if(next_group) next_group=next_group->next;
else return head;
}
/*调用递归程序反转下一个组的元素*/
ListNode *new_next_group=reverseKGroup(next_group,k);
/*反转当前组内的元素*/
ListNode *prev=NULL,*cur=head;
while(cur!=next_group){
ListNode *next=cur->next;
if(prev==NULL) cur->next=new_next_group; else cur->next=prev;
prev=cur; cur=next;
}
return prev;
}
6->成对的反转链表,相当于5题中k=2的情况。例如1->2->3->4 经过变换后成为2->1->3->4
解题方法:当然这题也可以采用5的递归的办法解决,其中将k设置为2.下面提供一种非递归的方法求解这个问题
ListNode *swapPairs(ListNode *head){
if(head==NULL ||head->next==NULL) return head;
ListNode dummy(-1);
dummy.next=head;
for(ListNode* prev=dummy,*cur=dummy->next,*next=cur->next; next ; prev=cur,cur=cur->next,next=cur?cur->next:NULL){
pre->next=next; cur->next=next->next; next->next=cur;
}
return dummy.next;
}
7->删除链表的倒数第K个节点。例如:1->2->3->4->5.删除链表的倒数第2个节点之后的链表为1->2->3->5
解题方法:定义两个指针等于头节点,p1=p2=head.p1先走k步,P2才开始走。当p1到达链表的尾部时,p2刚好指向要删除的节点
ListNode *removeNthFromEnd(ListNode* head,int k){
int len=0;
for(ListNode *p=head;p!=NULL;p=p->next) len++;
if(head==NULL || len<k) return NULL;
ListNode* prev=NULL,*p1=head,*p2=head;
for(int i=0;i<k;i++){
p1=p1->next;
}
while(p2!=NULL){
prev=p2;p1=p1->next; p2=p2->next;
}
prev->next=p2->next; free(p2);
return head;
}
8->在链表的倒数第K个位置翻转链表。例如:1->2->3->4->5->NULL,当k=2时,返回4->5->1->2->3->NULL
解题方法:先遍历一遍链表,得出链表的长度len,因此令k%=len。然后将尾节点指向首节点形成一个环,接着走len-k步,在此处断开。就得到题目要求的链表
ListNode *rotateRight(ListNode *head,int k){
if(head==NULL ||k==0) return head;
/*求链表的长度,并使p指向链表的最后一个节点*/
int len=1; ListNode *p=head;
while(p->next){
len++; p=p->next;
}
k=len-k%len;
p->next=head; //尾首相接形成一个环
for(int i=0;i<k;i++){
p=p->next;
}
head=p->next; p->next=NULL;
return head;
}
9->删除一个已经排序的链表中值重复的节点。例如:1->1->2->2->3 返回1->2->3
ListNode *deleteDuplicates(ListNode *head){
if(head==NULL) return NULL;
for(ListNode *prev=head,*cur=head->next;cur;cur=cur->next){
if(prev->val==cur->val){ prev->next=cur->next; delete(cur)}
else prev=cur;
}
return head;
}
10->一个已经排序好的链表,删除所有出现过重复的节点。例如:1->1->1->2->3 返回链表2->3
ListNode *deleteDuplicates(ListNode *head){
if(head==NULL) return head;
ListNode dummy(INT_MIN); //定义一个额外的头结点
ListNode* prev=&dummy,*cur=head;
while(cur!=NULL){
bool flags=false;
while(cur->next!=NULL && cur->val==cur->next->val){
flags=true;
ListNode *tmp=cur; cur=cur->next; free(tmp);
}
if(flags){ListNode * tmp=cur; cur=cur->next; free(tmp); continue;} //删除重复的最后一个元素
prev->next=cur; prev=prev->next; cur=cur->next;
}
prev->next=cur;
return dummy->next;
}
11->将一个链表按照value x的值分割成两部分,一部分值全都小于x,另一部分的值都大于等于x
ListNode *partition(ListNode *head,int x){
ListNode left_dummy(-1); //定义辅助头结点
ListNode right_dummy(-1);
ListNode *left_cur=&left_dummy;
ListNode *right_cur=&right_dummy;
for(ListNode *cur=head;cur;cur=cur->next){
if(cur->val<x){left_cur->next=cur; left_cur=cur}
else {right_cur->next=cur; right_cur=cur;}
}
left_cur->next=right_dummy.next;
right_cur>next=NULL;
return left_dummy.next;
}
12->反转链表m到n的子链
ListNode *reverseBetween(ListNode *head,int m,int n){
ListNode dummy(-1); dummy.next=head;
/*找到要反转的子链的前一个结点*/
ListNode *prev=&dummy;
for(int i=0;i<m-1;i++) prev=prev->next;
ListNode *head2=prev;
/*反转子链*/
prev=prev->next; ListNde* cur=prev->next;
for(int i=m;i<n;i++){
prev->next=cur->next; cur->next=head2->next;
head2->next=cur; cur=prev->next; //头插入法
}
return dummy.next;
}
13->两个链表中的值相加
ListNode *addTwoNumbers(ListNode *l1,ListNode *l2){
ListNode dummy(-1); //头结点
int carry=0;
ListNode* prev=&dummy;
for(ListNode *pa=l1,*pb=l2;pa!=NULL | pb!=NULL; pa=(pa==NULL)?NULL:pa-next,pb=(pb==NULL)?NULL:pb->next,prev=prev->next){
const int ia=(pa==NULL)?0:pa->val;
const int ib=(pb==NULL)?0:pb->val;
cont int value=(ia+ib+carry)/10; carry=(ia+ib+carry)/10;
pre->next=new ListNode(value); //尾插入法
}
if(carry>0)
prev->next=new ListNode(carry);
return dummy.next;
}