当前位置: 代码网 > it编程>软件设计>算法 > 顺序表和链表经典面试题

顺序表和链表经典面试题

2024年08月06日 算法 我要评论
经典面试题讲解

目录

一.顺序表经典面试题

1.移除元素 

2.删除有序数组中的重复项

3.合并两个有序数组

二.链表经典面试题

1.移除链表元素

2.反转一个单链表

3.链表的中间节点

4.链表中倒数第k个节点

5.合并两个有序链表

6.链表分割

7.链表的回文结构

8.相交链表

9.环形链表

10.环形链表||


一.顺序表经典面试题

1.移除元素 

oj链接力扣

题目描述:

代码:

int removeelement(int* nums, int numssize, int val){
    int arr[101];
    int i=0;//循环变量,以遍历数组
    int dst=0;//当前原数组被覆盖的值的数量
    for(i=0;i<numssize;i++)
    {
        if(nums[i]!=val)//判断是否数值等于val
        {
            nums[dst]=nums[i];//将不相等的元素赋值给原数组
            dst++;
        }
    }
    return dst;
}

2.删除有序数组中的重复项

oj链接力扣

题目描述:

代码;

int seach(int* nums, int numssize,int x)//查找函数
{
    int i=0;
    for(i=0;i<numssize;i++)
    {
        if(nums[i]==x)
        return i;//出现过则返回该元素在数组中下标
    }
    return -1;//没有出现过则返回-1
}
int removeduplicates(int* nums, int numssize){
    int i=0;
    int dst=1;
    for(i=1;i<numssize;i++)
    {
        int ret=seach(nums,i,nums[i]);//调用查找函数判断是否是重复元素
        if(ret==-1)//返回-1说明不是重复元素
        {
         nums[dst]=nums[i];赋值给原数组
         dst++;
        }
    }
    return dst;
}

3.合并两个有序数组

oj链接力扣

题目描述:

代码:

void merge(int* nums1, int nums1size, int m, int* nums2, int nums2size, int n){
    int ret1=m-1;//数组1的下标,从末尾开始遍历
    int ret2=n-1;//数组2的下标,从末尾开始遍历
    int j=m+n-1;//总空间的下标,从末尾开始
    while(ret1>=0&&ret2>=0)//一个数组遍历完则结束
    {
        if(nums1[ret1]>nums2[ret2])//比较大的元素从总空间最后面依次赋值
        {
            nums1[j]=nums1[ret1];
            ret1--;
            j--;
        }
        else if(nums1[ret1]==nums2[ret2])
        {
            nums1[j]=nums2[ret2];
            ret2--;
            j--;
        }
        else
        {
            nums1[j]=nums2[ret2];
            ret2--;
            j--;
        }
    }
        while(ret2>=0)//数组2没有遍历完,将剩余的元素赋值给总空间
        {
            nums1[j]=nums2[ret2];
            ret2--;
            j--;
        }
}

二.链表经典面试题

1.移除链表元素

oj链接力扣

题目描述:

代码:

/**
 * definition for singly-linked list.
 * struct listnode {
 *     int val;
 *     struct listnode *next;
 * };
 */


struct listnode* removeelements(struct listnode* head, int val)
{
    struct listnode* cur=head;//定义遍历指针
    struct listnode* guard,*tail;//定义带头节点的新链表
    guard=tail=(struct listnode*)malloc(sizeof(struct listnode));//开辟头结点
     while(cur)
     {
         if(cur->val!=val)//如果不是要删除的值,则尾插到新链表
         {
             tail->next=cur;
             tail=tail->next;
             cur=cur->next;
         }
         else//是则删除
         {
             struct listnode *next=cur->next;
             free(cur);
             cur=next;
         }
     }
     tail->next=null;//将尾及诶点的next置空
     struct listnode *newnode=guard->next;//将头指针指向第一个节点
     free(guard);//删除头结点
    return newnode;
}

2.反转一个单链表

oj链接力扣

题目描述:

代码:

/**
 * definition for singly-linked list.
 * struct listnode {
 *     int val;
 *     struct listnode *next;
 * };
 */


struct listnode* reverselist(struct listnode* head){
    struct listnode* newnode=null;//新建一个空链表
    struct listnode* cur=head;//新建两个遍历指针
    struct listnode* next=head;
    if(cur==null)//原链表为空则返回空
        return head;
    else
    {
        while(cur)//遍历原链表的节点,将每个节点头插到新链表
        {
            next=next->next;

            cur->next=newnode;
            newnode=cur;
            cur=next;
        }
    }
    return newnode;
}

3.链表的中间节点

oj链接力扣

题目描述:

代码:

思路1:
struct listnode* middlenode(struct listnode* head){
    struct listnode* cur=head;//定义一个遍历指针
    int num=0;//用来统计链表节点的数量
    while(cur)//遍历统计数量
    {
        num++;
        cur=cur->next;
    }
    cur=head;
    int i=0;
    for(i=0;i<num/2;i++)//让指针走到中间节点
    {
        cur=cur->next;
    }
    return cur;  
}

思路2:
    struct listnode* middlenode(struct listnode* head){
    struct listnode*low=head;//定义快慢指针
    struct listnode*fast=head;
    if(head==null)//原链表为空则返回空
    return null;
    while(fast&&fast->next)//节点数量为奇数和偶数的两种结束条件
    {
        low=low->next;//慢指针一次走一步
        fast=fast->next->next;//快指针一次走两步
    }
    return low;
}

4.链表中倒数第k个节点

oj链接链表中倒数第k个结点_牛客题霸_牛客网

题目描述:

代码:


思路1:
    struct listnode* findkthtotail(struct listnode* plisthead, int k ) {
    int i=0;
    struct listnode*cur=plisthead;//遍历指针统计节点数量
    int n=0;
    while(cur)
    {
        n++;
        cur=cur->next;
    }
    cur=plisthead;
    if(k>0&&k<=n)//判断k的合法性,合法则让遍历指针走n-k步
    {
        for(i=0;i<n-k;i++)//让遍历指针走n-k步
        {
            cur=cur->next;
        }
        return cur;
    }
    else//不合法返回空
    {
        return null;
    }
}
思路2:
struct listnode* findkthtotail(struct listnode* plisthead, int k ) {
    if(plisthead==null)//判断链表是否为空,为空则返回为空
    return null;
    struct listnode*cur=plisthead;//定义三个遍历指针
    struct listnode*p1=plisthead;
    struct listnode*p2=plisthead;
    int num=0;//记录节点数量
    while(cur)//遍历统计节点数量
    {
        num++;
        cur=cur->next;
    }
    if(k<=0||k>num)//判断k的合法性
    return null;
    k=k-1;
    while(k--)//让p1先走k-1步
    {
        p1=p1->next;
    }
    while(p1->next)//之后两个指针一起走
    {
        p1=p1->next;
        p2=p2->next;
    }
    return p2;
}

5.合并两个有序链表

oj链接力扣

题目描述:

代码:

struct listnode* mergetwolists(struct listnode* list1, struct listnode* list2){
    struct listnode *cur1=list1;//两个指针分别指向两个链表
    struct listnode *cur2=list2;
    struct listnode *guard,*tail;//新建一个带头结点的单链表
    guard=tail=(struct listnode*)malloc(sizeof(struct listnode));//开辟头结点
    while(cur1&&cur2)//遍历两个链表,当有一个链表遍历完则结束
    {
        if(cur1->val<cur2->val)//节点的值比较,较小的值尾插到新链表
        {
            tail->next=cur1;
            tail=tail->next;
            cur1=cur1->next;
        }
        else
        {
            tail->next=cur2;
            tail=tail->next;
            cur2=cur2->next;
        }
    }
    //检查哪个链表没有遍历完,没有遍历完的链表的节点则尾插到新链表中
    if(cur1==null)
    {
        while(cur2)
        {
            tail->next=cur2;
            tail=tail->next;
            cur2=cur2->next;
        }
        tail->next=null;
    }
    else if(cur2==null)
    {
        while(cur1)
        {
        tail->next=cur1;
        tail=tail->next;
        cur1=cur1->next;
        }
        tail->next=null;
    }
    else{
        return null;
    }
    struct listnode*newnode=guard->next;//头指针指向第一个节点
    free(guard);//删除头结点
    return newnode;
}

6.链表分割

oj链接链表分割_牛客题霸_牛客网

题目描述:

代码:

 listnode* partition(listnode* phead, int x) {
        // write code here
        if(phead==null)//判断原链表是否为空
        return null;
        listnode* cur=phead;//定义遍历指针
        listnode* guard1,*tail1,*guard2,*tail2;//定义两个新链表
        //开辟头结点
        guard1=tail1=(listnode*)malloc(sizeof(listnode));
        guard1->next=null;
        guard2=tail2=(listnode*)malloc(sizeof(listnode));
        guard2->next=null;
        //遍历原链表,值小于x的节点尾插到一个新链表中,大于x的节点尾插到另一个新链表中
        while(cur)
        {
            if(cur->val<x)
            {
                tail1->next=cur;
                tail1=tail1->next;
                cur=cur->next;
            }
            else
            {
               tail2->next=cur;
                tail2=tail2->next;
                cur=cur->next; 
            }
        }
        tail1->next=guard2->next;//两个新链表链接在一起
        tail2->next=null;//链表的最后一个节点next置空
        listnode* newnode1=guard1->next;//头指针指向第一个节点
        listnode* newnode2=guard2->next;
        //删除头结点
        free(guard1);   
        free(guard2);
        return newnode1;
    }
}

7.链表的回文结构

oj链接链表的回文结构_牛客题霸_牛客网

题目描述:

代码:

//返回中间节点
struct listnode* middlenode(struct listnode* head){
    struct listnode* cur=head;
    int num=0;
    while(cur)
    {
        num++;
        cur=cur->next;
    }
    cur=head;
    int i=0;
    for(i=0;i<num/2;i++)
    {
        cur=cur->next;
    }
    return cur;  
}
//反转链表
struct listnode* reverselist(struct listnode* head){
    struct listnode* newnode=null;
    struct listnode* cur=head;
    struct listnode* next=head;
    if(cur==null)
        return head;
    else
    {
        while(cur)
        {
            next=next->next;
            cur->next=newnode;
            newnode=cur;
            cur=next;
        }
    }
    return newnode;
}
 bool chkpalindrome(listnode* a) {
        // write code here
        listnode *mid=middlenode(a);//返回原链表的中间节点
        listnode *rhead=reverselist(mid);//翻转原链表的后半部分
        while(a&&rhead)//遍历两个链表,比较节点的值
        {
            if(a->val!=rhead->val)
            return false;
            a=a->next;
            rhead=rhead->next;
        }
        return true;
    }
}

8.相交链表

oj链接力扣

题目描述:

代码:

struct listnode *getintersectionnode(struct listnode *heada, struct listnode *headb) {
    //定义两个遍历指针
    struct listnode *cur1=heada;
    struct listnode *cur2=headb;
    //分别统计两个链表节点数量
    int num1=0;
    int num2=0;
    //遍历统计两个链表节点数量
    while(cur1)
    {
        num1++;
        cur1=cur1->next;
    }
    while(cur2)
    {
        num2++;
        cur2=cur2->next;
    }
    cur1=heada;
    cur2=headb;
    //让节点数量多的链表遍历指针先走差值的步数
    if(num1>num2)
    {
        int k=num1-num2;
        while(k--)
        cur1=cur1->next;
    }
    else if(num1<num2)
    {
        int k=num2-num1;
        while(k--)
        cur2=cur2->next;
    }
    //两个链表一起遍历
    while(cur1)
    {
        //两个链表的节点相比较,相同则返回
        if(cur1==cur2)
        return cur1;
        if(cur1->next==cur2->next)
        return cur1->next;
        //不同则继续遍历
        else
        {
            cur1=cur1->next;
            cur2=cur2->next;
        }
    }
    return null;
}

9.环形链表

oj链接力扣

题目描述:

代码:

bool hascycle(struct listnode *head) 
{
    if(head==null)//判断原链表是否为空,为空则返回空
    return false;
    //定义两个快慢指针
   struct listnode* low=head;
   struct listnode* fast=head;
   low=low->next;//慢指针每次走一步
   fast=fast->next->next;//快指针每次走两步
   while(low!=fast&&fast!=null)//两个指针一直走,直到相遇或者为空结束
   {
       low=low->next;
   fast=fast->next->next;
   }
   if(low==fast)//相遇则返回真
    return true;
    if(fast==null)//为空则返回假
    return false;
}

10.环形链表||

oj链接力扣

题目描述:

证明:假设直线区长度为l,环的长度为c,快慢指针相遇点至入环口的距离为n,第9题的快指针走的路程是慢指针的两倍

        慢指针走的路程:l+n

        快指针走的路程:假设快指针已经在环走了k圈,则路程为l+kc+n

        则由(l+n)*2=l+kc+n,化解得l=kc-n=(k-1)c+c-n,(k-1)c可以认为指针走了k圈又回到原点,故得证l=c-n

 代码:

struct listnode *detectcycle(struct listnode *head) {
    if(head==null||head->next==null)//判断链表是否为空或者只有一个节点
    return null;
    //定义两个快慢指针
    struct listnode *low=head;
    struct listnode *fast=head;
    while(fast&&fast->next)//快慢指针遍历
    {
        
        low=low->next;
        fast=fast->next->next;
        //如果快慢指针相遇则让一个指针从头开始走,另一个指针从相遇点开始走
        if(low==fast)
        {
            struct listnode *meet=low;
            while(head!=meet)
            {
                head=head->next;
                meet=meet->next;
            }
            return meet;
        }
    }
    //上面的循环结束到这里说明链表没有环,返回空
    return null;
}

好啦,顺序表和链表经典面试题就先学习到这里,如果文章对您有帮助,欢迎一键三连~

最后附上寄语:种一棵树最好的时间是十年前,其次是现在

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com