• 经典链表OJ强训题——快慢双指针高效解法


    目录

    链表分割

    链表回文结构

    合并两个有序链表

    ​编辑

    相交链表

    移除链表元素

    反转链表

    链表的中间结点

    链表中倒数第K个结点


    链表分割

     思路:

    1. 创建两个链表(A,B):分别创建两个头尾指针置null
    2. 创建一个cur的指针遍历题目所给链表
    3. 将结点值小于x的尾插入A中,否则插入B中
    4. 判断若A段为空,返回B段头结点
    5. 为了防止死循环,若B段存在,则有可能B段最后一个结点不为空,若不为空,则置为空
    6. 用A链表的尾结点,连接B链表的头结点
    1. public class Partition {
    2. public ListNode partition(ListNode head, int x) {
    3. ListNode as = null;
    4. ListNode ae = null;
    5. ListNode bs = null;
    6. ListNode be = null;
    7. ListNode cur = head;
    8. while(cur != null){
    9. //进a段
    10. if(cur.val < x){
    11. //第一次进as
    12. if(as == null){
    13. as = cur;
    14. ae = cur;
    15. }
    16. else{
    17. ae.next = cur;
    18. ae = cur;
    19. }
    20. }
    21. else{
    22. if(bs == null){
    23. bs = cur;
    24. be = cur;
    25. }
    26. else{
    27. be.next = cur;
    28. be = cur;
    29. }
    30. }
    31. cur = cur.next;
    32. }
    33. //如果a段为空
    34. if(as == null){
    35. return bs;
    36. }
    37. //防止死循环,如果b段存在,那么有可能b段最后一个结点的不为空
    38. if(bs != null){
    39. be.next = null;
    40. }
    41. ae.next = bs;
    42. return as;
    43. }
    44. }

    链表回文结构

     思路:

    1. 创建快慢指针
    2. 通过快慢指针遍历链表
    3. 从慢指针的next开始反转后半段链表
    4. 最后用两指针,分别从头尾判断链表是否回文
    1. public class PalindromeList {
    2. public boolean chkPalindrome(ListNode head) {
    3. if(head == null){
    4. return true;
    5. }
    6. ListNode fast = head;
    7. ListNode slow = head; //快慢指针注意前后顺序,否则会引起对null指针的解引用操作
    8. while(fast != null && fast.next != null){
    9. slow = slow.next;
    10. fast = fast.next.next;
    11. }// 1 2 2 1
    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. cur = head;
    22. while(cur != slow){
    23. if(cur.val != slow.val){
    24. return false;
    25. }
    26. if(cur.next == slow){
    27. return true;
    28. }
    29. cur = cur.next;
    30. slow = slow.next;
    31. }
    32. return true;
    33. }
    34. }

    合并两个有序链表

     思路:

    1. 创建一个虚拟结点
    2. 从头开始比较两个结点value值,将较小值连接虚拟结点
    3. 若有一个结点为空时,将该结点指向另一个结点即可
    4. 返回虚拟结点的下一个接待
    1. class Solution {
    2. public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    3. ListNode newHead = new ListNode(-1);
    4. ListNode tmp = newHead;
    5. while(list1 != null && list2 != null){
    6. if(list1.val < list2.val){
    7. tmp.next = list1;
    8. list1 = list1.next;
    9. tmp = tmp.next;
    10. }else{
    11. tmp.next = list2;
    12. list2 = list2.next;
    13. tmp = tmp.next;
    14. }
    15. }
    16. if(list1 == null){
    17. tmp.next = list2;
    18. }
    19. else{
    20. tmp.next = list1;
    21. }
    22. return newHead.next;
    23. }
    24. }

    相交链表

     

    思路:

    1. 分别用两指针遍历A,B两链表,求出长度
    2. 求长度差值,因为是Y性,所有相同结点后面的长度是一样的

    3. 求出差值后,让长的走完这段差值,两个再同时走

    4. 最后判断如果两指针相等,则返回相等结点

    1. public class Solution {
    2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    3. int szA = 0;
    4. int szB = 0;
    5. ListNode curA = headA;
    6. ListNode curB = headB;
    7. //求A链表长度
    8. while(curA != null){
    9. curA = curA.next;
    10. szA++;
    11. }
    12. //求B链表长度
    13. while(curB != null){
    14. curB = curB.next;
    15. szB++;
    16. }
    17. curA = headA;
    18. curB = headB;
    19. if(szA > szB){
    20. //求差值,因为是Y性,所有相同结点后面的长度是一样的,所以求差值,让长的走完这段差值,两个再同时走
    21. int diff = szA - szB;
    22. while(diff != 0){
    23. curA = curA.next;
    24. diff--;
    25. }
    26. }
    27. else{
    28. int diff = szB - szA;
    29. while(diff != 0){
    30. curB = curB.next;
    31. diff--;
    32. }
    33. }
    34. while(curA != curB){
    35. /* if(curA == null){
    36. return null;
    37. }*/ //判不判断无所谓,因为最后都会返回空
    38. curA = curA.next;
    39. curB = curB.next;
    40. }
    41. return curA;
    42. }
    43. }

    移除链表元素

     思路:

    1. 创建两个指针
    2. 一个为cur用来遍历链表,找出要删除的元素
    3. 另一个为dp指向cur上一个结点
    4. dp的next指向cur的next结点,同时使cur指向下一个结点,达到删除多个结点的目的
    1. class Solution {
    2. public ListNode removeElements(ListNode head, int val) {
    3. if(head == null){
    4. return null;
    5. }
    6. ListNode cur = head;
    7. ListNode dp = cur;
    8. while(cur != null) {
    9. if (cur.val == val) {
    10. dp.next = cur.next;//其实这里可以不用找前一个结点,直接插入结点,交换值即可
    11. cur = dp.next;
    12. } else {
    13. dp = cur;
    14. cur = cur.next;
    15. }
    16. }
    17. if(head.val == val){
    18. head = head.next;
    19. }
    20. return head;
    21. }
    22. }

    反转链表

    思路 

    1. 创建一个cur指针,指向头结点的next
    2. 将头节点置空,作为反转后的尾结点
    3. 创建一个curNext指针,让他始终指向cur的next
    4. 让将head指针当作cur的上一个结点用,将head的结点的地址赋给cur的next,让cur指向curNext,curNext指向cur的next循环即可
    1. class Solution {
    2. public ListNode reverseList(ListNode head) {
    3. if(head == null){
    4. return null;
    5. }
    6. if(head.next == null){
    7. return head;
    8. }
    9. ListNode cur = head.next;
    10. head.next = null;
    11. while(cur != null){
    12. ListNode curNext = cur.next;
    13. cur.next = head;
    14. head = cur;
    15. cur = curNext;
    16. }
    17. return head;
    18. }
    19. }

    链表的中间结点

    思路:

    1. 通过快慢指针遍历链表即可
    2. fast指向null或者fast.next指向null的时候停下,此时慢指针便是中间结点 
    1. class Solution {
    2. public ListNode middleNode(ListNode head) {
    3. if(head == null){
    4. return null;
    5. }
    6. ListNode slow = head;
    7. ListNode fast = head;
    8. while(fast != null && fast.next != null){
    9. slow = slow.next;
    10. fast = fast.next.next;
    11. }
    12. return slow;
    13. }
    14. }

    链表中倒数第K个结点

     思路:

    1. 创建快慢指针
    2. 让快指针先走K-1步
    3. 再让快指针和慢指针同时向后一步一步挪动
    4. fast指向空时,slow指针指向的便是倒数第K个元素
    1. public class Solution {
    2. public ListNode FindKthToTail(ListNode head,int k) {
    3. if(k <= 0 || head == null){
    4. return null;
    5. }
    6. ListNode fast = head;
    7. ListNode slow = head;
    8. while(k-1 != 0){
    9. fast = fast.next;
    10. if(fast == null){
    11. return null;//k过大
    12. }
    13. k--;
    14. }
    15. while(fast.next != null){
    16. fast = fast.next;
    17. slow = slow.next;
    18. }
    19. return slow;
    20. }
    21. }

     

  • 相关阅读:
    排列字母(蓝桥杯)
    一文快速学会linux shell 编程基础!!!
    Java中Integer的最大值和最小值
    后台管理系统项目-中
    centos7安装mysql8
    JavaScript注册页面的前端验证(1+X Web前端开发初级 例题)
    Unity类银河恶魔城学习记录13-1 p142 Save system源代码
    关于eclipse导入项目出现红色叉或者红色感叹号的各种处理方法
    SDXL微调5分钟入门
    诸葛智能荣登《2022中国企业数智化转型升级创新服务企业》榜单!
  • 原文地址:https://blog.csdn.net/CYK_byte/article/details/126076587