BAT互联网大厂高频笔试题-------链表系列

目录

 反转单链表

合并两个有序链表

剑指offer35.复杂链表的复制

返回倒数第K个节点

链表求和

两个链表的第一个公共节点

合并K个升序链表

回文链表

删除链表的倒数第 n 个结点

剑指 Offer 18. 删除链表的节点

 删除中间节点

 移除重复节点

 删除排序链表中的重复元素

从尾到头打印单链表 

两数相加

环形链表

 环形链表 II

对链表进行插入排序


 反转单链表

示例:

输入: 1->2->3->4->5->NULL

输出: 5->4->3->2->1->NULL

class Solution {
public:
      //递归
    ListNode *reverseList1(ListNode *head)
    {
        //递归结束条件肯定是head走到最后了那就是要么是null要么是末尾元素
        if (head == NULL || head->next == NULL)
            return head;
        //局部反转  当前元素的下一位元素的next指向当前元素 当前节点的next指向null
        ListNode *p = reverseList1(head->next);
        head->next->next = head;
        head->next = NULL;
        return p;
    }
    //双指针
    ListNode *reverseList2(ListNode *head)
    {
        /*
        双指针法 将当前节点与下一位节点反转
        */
        //当只有一个节点或者没有节点的时候
        if (head == NULL || head->next == NULL)
            return head;
        ListNode *cur = head;
        ListNode *pre = head->next;
        while (pre != NULL)
        {
            ListNode *tmp = pre->next; //保存pre next

            //反转
            pre->next = cur;
            //cur与pre同时想继续向后走
            //由于pre->已经指向cur了 所以我们必须提前保存pre->next
            cur = pre;
            pre = tmp;
        }
        return cur;
    }
};

合并两个有序链表

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

ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        if (l1 == NULL)
            return l2;
        else if(l2==NULL)
            return l1;

        ListNode *pre = new ListNode(-1);
        ListNode* p = pre;
        while(l1&&l2)
        {
            if(l1->val<=l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }
        p->next = l1==NULL?l2:l1;
       p = pre->next;
        delete pre;
        return p;
    }
};

剑指offer35.复杂链表的复制

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的 深拷贝

class Node
{
public:
    int val;
    Node *next;
    Node *random;

    Node(int _val)
    {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
    Node *copyRandomList(Node *head)
    {
        if (head == NULL)
            return NULL;
        //1.将拷贝的节点插入到被拷贝节点的下一个
        Node *cur = head;
        while (cur != NULL)
        {
            Node *p = new Node(cur->val);
            Node *next = cur->next;

            cur->next = p;
            p->next = next;

            cur = next;
        }
        //2.将拷贝的节点的rand进行设置
        cur = head;
        while (cur != NULL)
        {
            Node *p = cur->next;
            if (cur->random != NULL)
                p->random = cur->random->next;
            else
                p->random = NULL;
            cur = p->next;
        }

        //3.偶数位上的就是拷贝的节点
        //将拷贝的节点摘下来,进行尾插
        Node *copyHead = NULL;
        Node *copyTail = NULL;
        cur = head;
        while (cur != NULL)
        {
            Node* p = cur->next;
            cur->next = p->next;
            p->next = NULL;
            if (copyTail == NULL)
            {
                copyTail = copyHead = p;
            }
            else
            {
                copyTail->next = p;
                copyTail = p;
            }

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

返回倒数第K个节点

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

输入 1,  {1,2,3,4,5}

返回值  {5}

ListNode *FindKthToTail(ListNode *pListHead, unsigned int k)
    {
        //快慢指针法
        //快指针先走k-1步 然后快慢指针一起走 快指针走到头慢指针就是倒数第5个
        if (k == 0 || pListHead == NULL)
            return NULL;
        ListNode *fast = pListHead;
        ListNode *slow = pListHead;
        while (k && fast != NULL)
        {
            fast = fast->next;
            k--;
        }
        if (k == 0)
        {
            while (fast != NULL)
            {
                fast = fast->next;
                slow = slow->next;
            }
            return slow;
        }
        return NULL;
    }

链表求和

给定两个用链表表示的整数,每个节点包含一个数位。

这些数位是反向存放的,也就是个位排在链表首部。

编写函数对这两个整数求和,并用链表形式返回结果。

示例:

输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即617 + 295

输出:2 -> 1 -> 9,即912

716  592  1308

    ListNode* reverseList(ListNode *head)
    {
        if (head == nullptr)
            return nullptr;
        ListNode *cur = head->next;
        head->next = nullptr;
        while (cur)
        {
            ListNode *p = cur;
            cur = cur->next;

            p->next = head;
            head = p;
        }
        return head;
    }
    ListNode *addInList(ListNode *head1, ListNode *head2)
    {
        // write code here
        /*
        3 6
        7 3 9
        0 0 0 1
        */
        head1 = reverseList(head1);
        head2 = reverseList(head2);
        ListNode *p1 = head1;
        ListNode *p2 = head2;
        ListNode *pre = nullptr;
        int flag = 0;
        while (p1 && p2)
        {
            int sum = p1->val + p2->val + flag;
            flag = 0;
            if (sum > 9)
            {
                flag = 1;
                sum -= 10;
            }
            p1->val = sum;
            pre = p1;
            p1 = p1->next;
            p2 = p2->next;
        }
        if (p2)
        {
            pre->next = p2;
            p1 = p2;
        }
        while (p1)
        {
            int sum = p1->val + flag;
            flag = 0;
            if (sum > 9)
            {
                flag = 1;
                sum -= 10;
            }
            p1->val = sum;
            pre = p1;
            p1 = p1->next;
        }
        if (flag)
            pre->next = new ListNode(1);
        
        return reverseList(head1);
    }

两个链表的第一个公共节点

    //双指针分别指向两个链表 求出两个链表的长度 他们长度的差值就是长链表指针先走的长度 然后一起走直到相遇

    //两个指针同时走 当一个走到头就让他指向另一个头结点继续走
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
    {
        if (headB==nullptr||headA==nullptr)
            return nullptr;
        ListNode *pa = headA, *pb = headB;

        while(pa!=pb)
        {
            pa = pa!=nullptr?pa->next:headB;
            pb = pb!=nullptr?pb->next:headA;
        }
        return pa;
    }

合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

class Solution
{
public:
    ListNode *twoMergeLists(ListNode *l1, ListNode *l2)
    {
        if (l1 == nullptr && l2 == nullptr)
            return nullptr;
        if (l1 == nullptr)
            return l2;
        if (l2 == nullptr)
            return l1;
        ListNode *pre = new ListNode(-1);
        ListNode *p = pre;
        while (l1 && l2)
        {
            if (l1->val < l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }
        p->next = l1 == nullptr ? l2 : l1;
        p = pre->next;
        delete pre;
        return p;
    }
    ListNode *mergeList(vector<ListNode *> &lists,int left,int right)
    {
        if(left==right)return lists[left];
        if(left>right)return nullptr;
        int mid = (left+right)>>1;
        return twoMergeLists(mergeList(lists,left,mid),mergeList(lists,mid+1,right));
    }
    ListNode *mergeKLists(vector<ListNode *> &lists)
    {
        return mergeList(lists, 0, lists.size()-1);
    }
};

回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 

class Solution
{
public:
    bool isPalindrome(ListNode *head)
    {
        if(head==NULL||head->next==NULL)
            return true;
        stack<int> s;
        ListNode* cur = head;
        while(cur!=NULL)
        {
            s.push(cur->val);
            cur = cur->next;
        }
        while(!s.empty())
        {
            if(head->val==s.top())
            {
                head = head->next;
                s.pop();
            }
            else
            {
                return false;
            }
        }
        return true;
    }
};

先写这么多吧,眼睛有点酸后面在写然后在更新吧!

------------------------------------------------------------------------------------------------------

继续肝!!!

删除链表的倒数第 n 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点

示例 1:

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

输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1

输出:[]

示例 3:

输入:head = [1,2], n = 2

 输出:[2]

class Solution
{
public:
    ListNode *removeNthFromEnd(ListNode *head, int n)
    {

        if (head == NULL || n <= 0)
            return head;

        ListNode *fast = head;
        ListNode *slow = head;
        while (fast && n + 1 > 0)
        {
            fast = fast->next;
            n--;
        }
        while (fast)
        {
            fast = fast->next;
            slow = slow->next;
        }
        if (head == slow)
        {
            if (n == 0)
            {
                head = head->next;
            }
            else
            {
                head->next = head->next->next;
            }
        }
        else
        {
            slow->next = slow->next->next;
        }
        return head;
    }
};

 

剑指 Offer 18. 删除链表的节点

// 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

// 返回删除后的链表的头节点。

// 示例 1:

// 输入: head = [4,5,1,9], val = 5

// 输出: [4,1,9]

// 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

// 示例 2:

// 输入: head = [4,5,1,9], val = 1

// 输出: [4,5,9]

// 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

class Solution
{
public:
    ListNode *deleteNode(ListNode *head, int val)
    {
        if (head == NULL)
            return head;
        ListNode *cur = head;
        ListNode *pre = NULL;
        while (cur != NULL && cur->val != val)
        {
            pre = cur;
            cur = cur->next;
        }
        if (pre == NULL)
            head = head->next;
        else
            pre->next = cur->next;
        return head;
    }
    void deleteNode(ListNode *node)
    {
        ListNode *del = node->next;
        node->val = del->val;

        node->next = del->next;
    }

};

 删除中间节点

实现一种算法,删除单向链表中间的某个节点(即不是第一个或最后一个节点),假定你只能访问该节点。

示例:

输入:单向链表a->b->c->d->e->f中的节点c

结果:不返回任何数据,但该链表变为a->b->d->e->f

class Solution
{
public:
    void deleteNode(ListNode *node)
    {
        if(node==nullptr||node->next==nullptr)
            return;
        node->val = node->next->val;
        node->next  = node->next->next;
    
    }
};

 移除重复节点

移除未排序链表中的重复节点。保留最开始出现的节点。

// 示例1:

//  输入:[1, 2, 3, 3, 2, 1]

//  输出:[1, 2, 3]

// 示例2:

//  输入:[1, 1, 1, 1, 2]

//  输出:[1, 2]

class Solution
{
public:
    ListNode *removeDuplicateNodes(ListNode *head)
    {
        if (head == nullptr || head->next == nullptr)
            return head;
        ListNode *pi = head;
        while (pi != nullptr)
        {
            ListNode *pj = pi;
            while (pj->next != nullptr)
            {
                if (pi->val != pj->next->val)
                {
                    pj = pj->next;
                }
                else
                {
                    pj->next = pj->next->next;
                }
            }
            pi = pi->next;
        }
        return head;
    }
};

 删除排序链表中的重复元素

// 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。

    // 返回同样按升序排列的结果链表。

    //输入:head = [1,1,1,1,1,1,2,3,3]

    //输出:[1,2,3]

class Solution
{
public:
    ListNode *deleteDuplicates(ListNode *head)
    {
        if (head == nullptr || head->next == nullptr)
            return head;
        ListNode *pa = head;
        ListNode *pb = head->next;
        while (pb)
        {
            if (pa->val == pb->val)
            {
                pa->next = pb->next;
                pb = pa->next;
            }
            else
            {
                pa = pa->next;
                pb = pb->next;
            }
        }
        return head;
    }
};

从尾到头打印单链表 

 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

// 输入:head = [1,3,2]

// 输出:[2,3,1]

 

class Solution {
public:
    vector<int> reversePrint(ListNode* head)
    {
        
        vector<int>vec;
        ListNode*cur = head;
        while(cur!=NULL)
        {
            vec.push_back(cur->val);
            //s.push(cur->val);
            cur = cur->next;
        }
        reverse(vec.begin(),vec.end());
        return vec;
    }
};

两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

输入:l1 = [2,4,3], l2 = [5,6,4]

输出:[7,0,8]

解释:342 + 465 = 807.

输入:l1 = [0], l2 = [0]

输出:[0]

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]

输出:[8,9,9,9,0,0,0,1]

 

class Solution
{
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
    {
        int len1 = 0;
        int len2 = 0;
        ListNode *p = l1;
        ListNode *q = l2;
        while (p != nullptr)
        {
            len1++;
            p = p->next;
        }
        p = l2;
        while (p != nullptr)
        {
            len2++;
            p = p->next;
        }
        if (len1 > len2)
        {
            p = l1;
            q = l2;
        }
        else
        {
            p = l2;
            q = l1;
        }

        int carry = 0;
        while (p && q)
        {
            int num = p->val + l2->val + carry;
            carry = 0;
            if (num > 10)
            {
                num /= 10;
                carry = 1;
            }
            p->val = num;
            p = p->next;
            l2 = l2->next;
        }
        while (p)
        {
            int num = p->val + carry;
            carry = 0;
            if (num > 10)
            {
                num /= 10;
                carry = 1;
            }
            p->val = num;
            p = p->next;
        }
        if (carry == 1)
            p->next = new ListNode(1);
        return l1;
    }
};

环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
 

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

class Solution {
public:
    bool hasCycle(ListNode *head)
    {
        if (head == NULL)
            return false;
        //快慢指针
        ListNode *fast = head;
        ListNode *slow = head;
        while (fast && fast->next != NULL)
        {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow)
                return true;
        }
        return false;
    }
};

 环形链表 II

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
 

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
 

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

 

class Solution {
public:
    ListNode *detectCycle(ListNode *head)
    {
        if(head==nullptr)
            return nullptr;
        ListNode *fast = head;
        ListNode *slow = head;
        while(fast&&fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if(fast==slow)
            {
                fast = head;
                while(fast!=slow)
                {
                    fast = fast->next;
                    slow = slow->next;
                }
                return slow;

            }
        }
        return nullptr;
    }
};

对链表进行插入排序

    ListNode *insertionSortList(ListNode *head)
    {
        if (head == NULL || head->next == NULL)
            return head;

        ListNode *p = head;
        ListNode *q = p->next;
        //断开链表
        head->next = NULL;
        //插入数据
        while (q != NULL)
        {
            p = q;
            q = q->next;

            ListNode *s = head;
            ListNode *pre = NULL;
            //找位置
            while (s != NULL && p->val > s->val)
            {
                pre = s;
                s = s->next;
            }
            //插入位置在头部
            if (pre == NULL)
            {
                p->next = head;
                head = p;
            }
            else
            {
                p->next = pre->next;
                pre->next = p;
            }
        }
        return head;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值