链表面试题
- 1. 删除链表中等于给定值 val 的所有结点。
- 2. 反转一个单链表。
- 3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
- 4. 输入一个链表,输出该链表中倒数第k个结点。
- 5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。
- 6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
- 7. 链表的回文结构。
- 8. 输入两个链表,找出它们的第一个公共结点。
1. 删除链表中等于给定值 val 的所有结点。
题目链接
解题思想:用两个指针,来遍历整个链表,当出现cur指向的结点和val的值相等就,就将pre指向的结点指向cur的下一个结点,在free掉cur的结点。需要注意的特殊情况是,头删和空链表的情况。
struct ListNode* removeElements(struct ListNode* head, int val){
if(head==NULL)
return NULL;
struct ListNode*pre;
struct ListNode*cur;
pre=head;
cur=head;
while(cur)
{
if(cur->val==val)
{
if(cur==head)
{
head=head->next;
free(cur);
cur=head;
}
else
{
pre->next=cur->next;
free(cur);
cur=pre->next;
}
}
else
{
pre=cur;
cur=cur->next;
}
}
return head;
}
2. 反转一个单链表。
题目链接
解法一:用三指针来逆向指向结点
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL)
{
return head;
}
struct ListNode*n1,*n2,*n3;
n1=NULL;
n2=head;
n3=n2->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
{
n3=n3->next;
}
}
return n1;
}
解法二:头插法插入结点
struct ListNode* reverseList(struct ListNode* head){
struct ListNode*new_head;
new_head=(struct ListNode*)malloc(sizeof(struct ListNode));
if(new_head==NULL)
{
exit(1);
}
new_head->next=NULL;
struct ListNode*p=head;
while(p)
{
struct ListNode*tmp=p->next;
p->next=new_head->next;
new_head->next=p;
p=tmp;
}
head=new_head->next;
free(new_head);
return head;
}
3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
题目链接
解题思想:用快慢指针,慢指针一次走一步,快指针一次走两步,当快指针走完整个链表的时候,慢指针刚好走完链表的一半。此时慢指针就是中间结点。
注意:要考虑奇数和偶数的问题!
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode*slow,*fast;
slow=fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
4. 输入一个链表,输出该链表中倒数第k个结点。
题目链接
解题思路:用快慢指针来解决,先让快指针先走k步,在让慢指针开始走,当快指针走完的时候,慢指针的位置就是倒数第K个结点。
注意:①判断链表是否为空;②倒数第k个数是否存在
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
if(pListHead==NULL||k<1)
{
return NULL;
}
struct ListNode*low,*fast;
low=fast=pListHead;
for(int i=0;i<k;i++)
{
if(fast==NULL)
{
return NULL;
}
fast=fast->next;
}
while(fast)
{
low=low->next;
fast=fast->next;
}
return low;
}
5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。
题目链接
解题思路:两个链表比较,小的尾插到新的结点里。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode*head=(struct ListNode*)malloc(sizeof(struct ListNode));
if(head==NULL)
{
exit(1);
}
head->next=NULL;
struct ListNode*cur1,*cur2,*tail;
tail=head;
cur1=list1;
cur2=list2;
while(cur1&&cur2)
{
if(cur1->val<cur2->val)
{
tail->next=cur1;
tail=cur1;
cur1=cur1->next;
}
else
{
tail->next=cur2;
tail=cur2;
cur2=cur2->next;
}
}
if(cur1)
{
tail->next=cur1;
}
if(cur2)
{
tail->next=cur2;
}
struct ListNode*tmp=head->next;
free(head);
return tmp;
}
6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
题目链接
解题思路:创建两个链表,一个尾插小于x结点,一个尾插大于等于x的结点,最后将两个链表合并。
ListNode* partition(ListNode* pHead, int x) {
// write code here
struct ListNode*GreaterHead,*LowerHead,*GreaterTail,*LowerTail;
GreaterHead=GreaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
LowerTail=LowerHead=(struct ListNode*)malloc(sizeof(struct ListNode));
if(GreaterHead==NULL&&LowerTail==NULL)
{
exit(1);
}
GreaterHead->next=LowerHead->next=NULL;
struct ListNode*cur=pHead;
while(cur)
{
if(cur->val<x)
{
LowerTail->next=cur;
LowerTail=LowerTail->next;
cur=cur->next;
}
else
{
GreaterTail->next=cur;
GreaterTail=GreaterTail->next;
cur=cur->next;
}
}
GreaterTail->next=NULL;
LowerTail->next=GreaterHead->next;
pHead=LowerHead->next;
free(GreaterHead);
free(LowerHead);
return pHead;
}
7. 链表的回文结构。
题目链接
解题思路:根据回文结构关于中间结点的对称,那我们可以先找到中间结点,在将中间结点后面的结点逆序,最后将逆序后的结点和前面的结点进行比较,当存在一个不相等的时候,直接返回FALSE,循环结束则返回TRUE。
struct ListNode* reverseList(struct ListNode* head){
struct ListNode*new_head;
new_head=(struct ListNode*)malloc(sizeof(struct ListNode));
if(new_head==NULL)
{
exit(1);
}
new_head->next=NULL;
struct ListNode*p=head;
while(p)
{
struct ListNode*tmp=p->next;
p->next=new_head->next;
new_head->next=p;
p=tmp;
}
head=new_head->next;
free(new_head);
return head;
}
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode*slow,*fast;
slow=fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
bool chkPalindrome(ListNode* head) {
// write code here
struct ListNode*p=head;
struct ListNode*mid=middleNode(head);
struct ListNode*mid_head=reverseList(mid);
while(p&&mid_head)
{
if(p->val!=mid_head->val)
return false;
p=p->next;
mid_head=mid_head->next;
}
return true;
}
8. 输入两个链表,找出它们的第一个公共结点。
题目链接
解题思路:①先求两个链表的长度;②让长的链表先走差距步;③最后在一起走,相等就直接返回该结点的地址。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
int A=0;
int B=0;
struct ListNode *pa=headA;
struct ListNode *pb=headB;
while(pa)
{
A++;
pa=pa->next;
}
while(pb)
{
B++;
pb=pb->next;
}
if(pa!=pb)
return NULL;
pa=headA;
pb=headB;
int lenth=A-B;
if(lenth>0)
{
for(int i=0;i<lenth;i++)
{
pa=pa->next;
}
}
else if(lenth<0)
{
for(int i=0;i<-lenth;i++)
{
pb=pb->next;
}
}
while(pb)
{
if(pa==pb)
return pa;
pa=pa->next;
pb=pb->next;
}
return NULL;
}