• 链表面试题-刷题


    第一题:移除链表元素

     首先我们要明确目标,看到是删除链表中 所有 满足的节点,并且返回新的头节点。

    1. public ListNode removeElements(ListNode head, int val) {
    2. if (head == null) {
    3. return null;
    4. }
    5. ListNode cur = head.next;
    6. ListNode pre = head;
    7. while (cur != null) {
    8. if (cur.val == val) {
    9. pre.next = cur.next;
    10. cur = cur.next;
    11. }else {
    12. pre = cur;
    13. cur = cur.next;
    14. }
    15. }
    16. if (head.val == val) {
    17. head = head.next;
    18. }
    19. return head;
    20. }

    第二题:反转链表

     第一种方法:使用栈解决

     因为栈是先进后出的。实现原理就是把链表节点一个个入栈,当全部入栈完之后再一个个出栈,出栈的时候在把出栈的结点串成一个新的链表。

    1. public ListNode ReverseList(ListNode head) {
    2. Stack stack= new Stack<>();
    3. //把链表节点全部摘掉放到栈中
    4. while (head != null) {
    5. stack.push(head);
    6. head = head.next;
    7. }
    8. if (stack.isEmpty())
    9. return null;
    10. ListNode node = stack.pop();
    11. ListNode dummy = node;
    12. //栈中的结点全部出栈,然后重新连成一个新的链表
    13. while (!stack.isEmpty()) {
    14. ListNode tempNode = stack.pop();
    15. node.next = tempNode;
    16. node = node.next;
    17. }
    18. //最后一个结点就是反转前的头结点,一定要让他的next等于空,否则会构成环
    19. node.next = null;
    20. return dummy;
    21. }

    第二种方法:双链表求解

    双链表求解是把原链表的结点一个个摘掉,每次摘掉的链表都让他成为新的链表的头结点,然后更新新链表。

    1. public ListNode ReverseList(ListNode head) {
    2. //新链表
    3. ListNode newHead = null;
    4. while (head != null) {
    5. //先保存访问的节点的下一个节点,保存起来
    6. ListNode temp = head.next;
    7. //每次访问的原链表节点都会成为新链表的头结点,
    8. head.next = newHead;
    9. //更新链表
    10. newHead = head;
    11. head = temp;
    12. }
    13. return newHead;
    14. }

    第三题:求链表的中间节点

     快慢指针法,用两个指针 slow 与 fast 一起遍历链表。slow 一次走一步,fast 一次走两步。那么当 fast 到达链表的末尾时,slow 必然位于中间。

    1. public ListNode middleNode(ListNode head) {
    2. ListNode fast = head;
    3. ListNode slow = head;
    4. while (fast != null && fast.next != null) {
    5. slow = slow.next;
    6. fast = fast.next.next;
    7. }
    8. return slow;
    9. }

    第四题:链表中倒数第k个节点

    还是使用快慢指针,首先让快指针先行k步,然后让快慢指针每次同行一步,直到快指针指向空节点,慢指针就是倒数第K个节点。

    1. public ListNode FindKthToTail(ListNode head,int k) {
    2. ListNode fast = head;
    3. ListNode slow = head;
    4. for (int i = 0; i < k; i++) {
    5. if (fast == null) {
    6. return null;
    7. }
    8. fast = fast.next;
    9. }
    10. while (fast != null) {
    11. fast = fast.next;
    12. slow = slow.next;
    13. }
    14. return slow;
    15. }

    第五题:合并两个有序链表 

    采用递归的思想解题。

    每次都用两个链表头部值较小的一个节点与剩下元素的 merge 操作结果合并。

    1. public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    2. if (list1 == null) {
    3. return list2;
    4. }
    5. if (list2 == null) {
    6. return list1;
    7. }
    8. if (list1.val < list2.val) {
    9. list1.next = mergeTwoLists(list1.next, list2);
    10. return list1;
    11. } else {
    12. list2.next = mergeTwoLists(list1, list2.next);
    13. return list2;
    14. }
    15. }

    第六题:链表分割

     因为是在原链表上,所以操作会比较繁琐,我这里是把链表分成两段,第一段为小于目标值得,第二段为大于等于目标值的,然后去遍历链表,去判断这个值应该在链表的那个部分,循环结束后把第二段尾插到第一段最后就行了。

    1. public ListNode partition(ListNode head, int x) {
    2. //小于x的部分
    3. ListNode bs = null;
    4. ListNode be = null;
    5. //大于x的部分
    6. ListNode as = null;
    7. ListNode ae = null;
    8. while (head != null) {
    9. //判断当前head的val是哪一部分
    10. if (head.val < x) {
    11. //判断是否是第一次插入
    12. if (bs == null) {
    13. bs = head;
    14. be = head;
    15. }else {
    16. be.next = head;
    17. be = be.next;
    18. }
    19. head = head.next;
    20. }else {
    21. if (as == null) {
    22. as = head;
    23. ae = head;
    24. }else {
    25. ae.next = head;
    26. ae = ae.next;
    27. }
    28. head = head.next;
    29. }
    30. }
    31. //链表数据全部大于x
    32. if (bs == null) {
    33. return as;
    34. }
    35. if (as != null) {
    36. ae.next = null;
    37. }
    38. be.next = as;
    39. return bs;
    40. }

    第七题:判断链表是否回文

    思路:

    1. 先判断链表是否为空
    2. 前后指针法找中点找中点,设置两个引用fast、slow从头开始走,fast每次走两个节点,slow每次走一个节点,当fast走到链表尾,slow正好走到链表中点。
    3. 翻转后段链表
    4. .分别从链表头尾两端开始比较,如果遇到val值不一样的情况,则不是回文,否则是回文。
    1. public boolean chkPalindrome(ListNode head) {
    2. if (head == null || head.next == null) {
    3. return true;
    4. }
    5. ListNode fast = head;
    6. ListNode slow = head;
    7. //找到中点
    8. while (fast != null && fast.next != null) {
    9. fast = fast.next.next;
    10. slow = slow.next;
    11. }
    12. //翻转
    13. ListNode cur = slow.next;
    14. while (cur != null) {
    15. ListNode curNext = cur.next;
    16. cur.next = slow;
    17. slow = cur;
    18. cur = curNext;
    19. }
    20. //对比
    21. while (head != slow) {
    22. if (head.val != slow.val) {
    23. return false;
    24. }
    25. if (head.next == slow) {
    26. return true;
    27. }
    28. head = head.next;
    29. slow = slow.next;
    30. }
    31. return true;
    32. }

    第八题:相交链表

     首先我们需要明白一件事,按照题意那就是相交链表只能是  字型相交。

    思路:我们先求出两个链表长度的差距,然后先让长的那个链表先走差值步数,再然后两个链表一起开始向后走,看两链表是否相遇。

    1. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    2. //两链表长度
    3. int lenA = 0;
    4. int lenB = 0;
    5. ListNode listLong = headA;//指向长链表,后面不对再换
    6. ListNode listShort = headB;//短链表
    7. while (listLong != null) {
    8. lenA++;
    9. listLong = listLong.next;
    10. }
    11. while (listShort != null) {
    12. lenB++;
    13. listShort = listShort.next;
    14. }
    15. listLong = headA;
    16. listShort = headB;
    17. //差值步
    18. int len = lenA - lenB;
    19. if (len < 0) {
    20. listLong = headB;
    21. listShort = headA;
    22. len = lenB - lenA;
    23. }
    24. //长链表先走差值步
    25. while (len != 0) {
    26. listLong = listLong.next;
    27. len--;
    28. }
    29. while (listLong != listShort) {
    30. listShort = listShort.next;
    31. listLong = listLong.next;
    32. }
    33. if (listLong == null) {
    34. return null;
    35. }
    36. return listLong;
    37. }

    第九题:判断链表是否有环 

    思路:还是老样子快慢指针,两指针相遇就是有环

    1. public boolean hasCycle(ListNode head) {
    2. //快慢指针
    3. ListNode slow = head;
    4. ListNode fast = head;
    5. while (fast != null && fast.next != null) {
    6. fast = fast.next.next;
    7. slow = slow.next;
    8. if (fast == slow) {
    9. break;
    10. }
    11. }
    12. if (fast == null || fast.next == null) {
    13. return false;
    14. }
    15. return true;
    16. }

  • 相关阅读:
    MySQL如何记忆
    使用 Swift 的并发系统并行运行多个任务
    Linux Kernel 之四 移植过程详解、STM32F769I-EVAL 开发板适配
    微服务注册中心:Eureka详解
    Spring Cloud OpenFeign - - - > 超时时间配置
    B. M-arrays
    基于Python的海贼王知识图谱构建设计
    小啊呜产品读书笔记001:《邱岳的产品手记-05》第9讲 产品案例分析:Hopper的“人工智能” & 第10讲 产品被抄袭了怎么办?
    【专栏必读】数字图像处理(MATLAB+Python)专栏目录导航及学习说明
    第六章 图论 8 AcWing 1624. 地铁地图
  • 原文地址:https://blog.csdn.net/qq_52592775/article/details/126004250