链表OJ题(2)

目录

1.移除链表元素√

2.反转链表

3.相交链表

4.链表的中间节点

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

6.合并链表√

7.分割链表√


 今天链表面试OJ题目

  • 移除链表元素
  • 反转链表
  • 相交链表
  • 链表的中间节点
  • 链表中倒数第k个节点
  • 合并链表
  • 分割链表

  • 起始条件 中间节点 结束条件
  • 结束条件while易错
  • 单独处理头和尾
  • 处理链表为NULL的情况
  • 释放的先后顺序-----野指针
  • 指针的指向问题tail / tail->next
  • && ||  == = (赋值)
  • return 返回值的问题
  • 往极端情况考虑

1.移除链表元素√

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

链表OJ题(2)_第1张图片

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

【双指针】 

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode*cur=head;
    struct ListNode*prve=NULL;
    while(cur)
    {
        if(cur->val == val)
        {
            if(prve)
            {
                prve->next=prve->next->next;
                free(cur);
                cur=prve->next;
            }
            else
            {
                head=head->next;
                free(cur);
                cur=head;
            }
        }
        else
        {
            prve=cur;
            cur=cur->next;
        }
    }
    return head;
}
cur是指当前节点的指针
prve是指向前一个节点的指针

链表OJ题(2)_第2张图片


【三指针不带头节点】

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode* cur=head;
    struct ListNode* tail=NULL;
    struct ListNode* newhead=NULL;
    while(cur)
    {
        if(cur->val != val)
        {
            if(tail)
            {
                tail->next=cur;//易错
                tail=tail->next;
            }
            //处理头
            else
            {
                newhead=tail=cur;//易错
            }
            cur=cur->next;
        }
        else
        {
            struct ListNode* tmp=cur->next;
            free(cur);
            cur=tmp;
        }
    }
    //处理尾
    if(tail)
    {
        tail->next=NULL;
    }
    return newhead;
}

链表OJ题(2)_第3张图片


【三指针带头节点】

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode* cur=head;
    struct ListNode* newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* tail=newhead;
    while(cur)
    {
        if(cur->val != val)
        {
            tail->next=cur;
            tail=tail->next;
            cur=cur->next;
        }
        else
        {
            struct ListNode* tmp=cur->next;
            free(cur);
            cur=tmp;
        }
    }
    //处理尾
    if(tail)
    {
        tail->next=NULL;
    }
    struct ListNode*tmp=newhead;
    newhead=newhead->next;
    free(tmp);
    tmp=NULL;
    
    return newhead;
}

2.反转链表

 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

链表OJ题(2)_第4张图片

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

【头插】

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode*newhead=NULL;
    struct ListNode*cur=head;
    while(cur)
    {
        struct ListNode*tmp=cur->next;
        cur->next=newhead;
        newhead=cur;
        cur=tmp;
    }
    return newhead;
}
//可以不用处理头
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode*newhead=NULL;
    struct ListNode*cur=head;
    while(cur)
    {
        struct ListNode*tmp=cur->next;
        if(newhead == NULL)
        {
            newhead = cur;
            newhead->next = NULL;//易错
        }
        else
        {
            cur->next=newhead;
            newhead=cur;
        }
        cur=tmp;
    }
    return newhead;
}

链表OJ题(2)_第5张图片


【三指针】

struct ListNode* reverseList(struct ListNode* head)
{
    if(head == NULL)
    {
        return NULL;
    }
    struct ListNode*n1=NULL;
    struct ListNode*n2=head;
    struct ListNode*n3=head->next;
    while(n2)//易错
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
        n3=n3->next;
    }
    return n1;//易错
}

链表OJ题(2)_第6张图片


3.相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

链表OJ题(2)_第7张图片

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

链表OJ题(2)_第8张图片

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。

 【双指针】

  • 题目中有明确的说明两个链表都不为NULL 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int A=1;
    int B=1;
    struct ListNode *curA=headA;
    struct ListNode *curB=headB;
    int N=0;
    while(curA->next)
    {
        A++;
        curA=curA->next;
    }
    while(curB->next)
    {
        B++;
        curB=curB->next;
    }
    if(curA != curB)
    {
        return NULL;
    }
    else
    {
        N=abs(A-B);
        if(A>B)
        {
            while(N--)
            {
                headA=headA->next;
            }
            while(headA != headB)
            {
                headA=headA->next;
                headB=headB->next;
            }
            return headA;
        }
        else
        {
            while(N--)
            {
                headB=headB->next;
            }
            while(headA != headB)
            {
                headA=headA->next;
                headB=headB->next;
            }
            return headA;
        }
    }
}

 【简化】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int A=1;
    int B=1;
    struct ListNode *curA=headA;
    struct ListNode *curB=headB;
    int N=0;
    while(curA->next)
    {
        A++;
        curA=curA->next;
    }
    while(curB->next)
    {
        B++;
        curB=curB->next;
    }
    if(curA != curB)
    {
        return NULL;
    }
    else
    {
        N=abs(A-B);
        //简写------假设法
        struct ListNode *longlist=headA;
        struct ListNode *shortlist=headB;
        if(B>A)
        {
            longlist=headB;
            shortlist=headA;
        }
        //
        while(N--)
        {
            longlist=longlist->next;
        }
        while(longlist != shortlist)
        {
            longlist=longlist->next;
            shortlist=shortlist->next;
        }
            return longlist;
    }
}

 链表OJ题(2)_第9张图片


4.链表的中间节点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

【快慢双指针】

  • 保持相对速度
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode*faster=head;
    struct ListNode*slow=head;
    while(faster && faster->next)//条件没想到
    {
        faster=faster->next->next;
        slow=slow->next;
    }
    return slow;
}

链表OJ题(2)_第10张图片


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

输入一个链表,输出该链表中倒数第k个结点

示例1:输入:1,{1,2,3,4,5}

返回值:{5}

示例2:输入:6,{1,2,3,4,5}

返回值:{}


 【快慢指针】 

  • 保持相对距离 

 -----------【k步】

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode*faster=pListHead;
    struct ListNode*slow=pListHead;

    while(k--)//走k
    {
        if(faster == NULL)
        {
            return NULL;
        }
        faster=faster->next;
    }

    while(faster)
    {
        faster=faster->next;
        slow=slow->next;
    }
    return slow;
}

链表OJ题(2)_第11张图片

----------------【k-1步】

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

/**
 * 
 * @param pListHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode*faster=pListHead;
    struct ListNode*slow=pListHead;

    while(--k)//走k-1
    {
        if(faster == NULL)
        {
            return NULL;
        }
        faster=faster->next;
    }
    //当循环结束的时候faster为NULL
    if(faster == NULL)//判断一下即可乖乖
    return NULL;

    while(faster->next)
    {
        faster=faster->next;
        slow=slow->next;
    }
    return slow;
}

链表OJ题(2)_第12张图片

链表OJ题(2)_第13张图片


6.合并链表√

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

链表OJ题(2)_第14张图片

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4

【三指针带头】

  • 取小尾插
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode*cur1=list1;
    struct ListNode*cur2=list2;
    struct ListNode*newhead=NULL;
    struct ListNode*tail=NULL;
    if(list1 == NULL)
    return list2;
    if(list2 == NULL)
    return list1;
    while(cur1 && cur2)
    {
        if(cur1->val <= cur2->val)
        {
            if(newhead == NULL)
            {
                newhead=tail=cur1;//易错
            }
            else
            {
                tail->next=cur1;//已经放进去//易错
                tail=tail->next;//tail是尾节点,可以往后移动了
            }
            cur1=cur1->next;
        }
        else
        {
            if(newhead == NULL)
            {
                newhead=tail=cur2;
            }
            else
            {
                tail->next=cur2;//已经放进去
                tail=tail->next;//tail是尾节点,可以往后移动了
            }
            cur2=cur2->next;
        }
    }
    if(cur1 == NULL)
    {
        tail->next=cur2;
    }
    else
    {
        tail->next=cur1;//已经不用在往后走了
    }
    return newhead;
}

链表OJ题(2)_第15张图片


7.分割链表√

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

【三指针带头】

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
//用不带头节点来写,两个链表都可能为NULL,都要判断非常麻烦
//所以我们用带头节点来写
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        ListNode* list1=(ListNode*)malloc(sizeof(ListNode));
        ListNode* list2=(ListNode*)malloc(sizeof(ListNode));
        ListNode* tail1=list1;
        ListNode* tail2=list2;
        ListNode* cur=pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                tail1->next=cur;
                tail1=tail1->next;
            }
            else//cur->val >= x
            {
                tail2->next=cur;
                tail2=tail2->next;
            }
            cur=cur->next;
        }
        //尾巴处理
        tail1->next=list2->next;
        tail2->next=NULL;//易错
        return list1->next;
    }
};

 链表OJ题(2)_第16张图片


❓我们√三道题都有异曲同工之妙。

代码---------→【唐棣棣 (TSQXG) - Gitee.com】

联系---------→【邮箱:[email protected]

你可能感兴趣的:(笔试题&练习题,c语言,开发语言,数据结构,1024程序员节)