• 【LeetCode力扣】234 快慢指针 | 反转链表 | 还原链表


     

    目录

    1、题目介绍

    2、解题思路

    2.1、暴力破解法

    2.2、快慢指针反转链表


     

    1、题目介绍

    原题链接: 234. 回文链表 - 力扣(LeetCode)

    示例 1:

    输入:head = [1,2,2,1]
    输出:true 

    示例 2:

    输入:head = [1,2]
    输出:false 

    提示: 

    • 链表中节点数目在范围[1, 10^5] 内
    • 0 <= Node.val <= 9

    进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

    2、解题思路

    判断回文,就是判断是否是对称的。有些朋友对于数组的回文判断非常熟悉,但是对链表的回文判断可能就无从下手了,其实都一样的。有一种非常简单的方式就是将链表转化成数组,然后就是判断该数组是否回文就可以了,这种方式统称暴力破解法,简单粗暴。下面就来先带着大家看一下这道题的暴力破解法

    2.1、暴力破解法

    一共为两个步骤:

    1. 复制链表值到数组列表中。
    2. 使用双指针法判断是否为回文。

    首先按照题目要求的最大大小定义一个大小为100001的整型数组,接着通过循环遍历将链表中每个结点的值取出放入数组中,最后通过两个指针,一个从左一个从右分别判断是否相等,只要遇到一个不相等就返回false,否则当循环结束时返回true。

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. bool isPalindrome(struct ListNode* head){
    9. int arr[100001] = {0},num = 0;
    10. while(head)
    11. {
    12. arr[num] = head->val;
    13. head = head->next;
    14. num++;
    15. }
    16. int i= 0;
    17. int j =0;
    18. for(i = 0,j = num-1; i
    19. {
    20. if(arr[i]!=arr[j])
    21. {
    22. return false;
    23. }
    24. }
    25. return true;
    26. }

    时间复杂度:O(n),其中 n 指的是链表的元素个数。

    • 第一步:遍历链表并将值复制到数组中,O(n)。
    • 第二步:双指针判断是否为回文,执行了 O(n/2) 次的判断,即O(n)。
    • 总的时间复杂度:O(2n)=O(n)。

    空间复杂度:O(n),其中 n 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。

    进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

    下面带大家做一下本题的进阶,使用快慢指针反转链表实现空间复杂度为O(1)的算法。

    2.2、快慢指针反转链表

    整个流程可以分为以下五个步骤:

    1. 找到前半部分链表的尾节点。
    2. 反转后半部分链表。
    3. 判断是否回文。
    4. 恢复链表。
    5. 返回结果。

    对于第一步找到前半部分链表的尾结点,我们可以计算链表结点个数然后再找到前半部分的尾结点,也可以通过快慢指针一次遍历找到前半部分的尾结点。

    慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。通过慢指针将链表分为两部分。

    此时slow就是前半部分的尾结点,而slow的下一个结点就是后半部分的头结点。于是让fast回到slow的next结点处,将后半部分的结点全部反转,然后slow即前半部分的尾结点置空。

    紧接着将让slow从head重新出发,fast从最后结点出发,分别向中间结点靠近并判断,只要相等就一直向中间靠近,遇到不相同时直接返回false,否则当循环退出时返回true。

    最后在将反转链表还原回去即可。 

     代码实现:

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. bool isPalindrome(struct ListNode* head){
    9. if(head == NULL || head->next == NULL)
    10. {
    11. return true;
    12. }
    13. struct ListNode* n1 = head;
    14. struct ListNode* n2 = head;
    15. //快慢指针遍历
    16. while(n2->next != NULL && n2->next->next != NULL)
    17. {
    18. n1 = n1->next; //慢指针
    19. n2 = n2->next->next; //快指针
    20. }
    21. n2 = n1->next; //右边第一个
    22. n1->next = NULL;
    23. struct ListNode* n3;
    24. //反转右半边链表
    25. while(n2 != NULL)
    26. {
    27. n3 = n2->next; //n3存放n2的next
    28. n2->next = n1;
    29. n1 = n2;
    30. n2 = n3;
    31. }
    32. //当循环结束时n1所指向的位置就是链表最后一个结点,
    33. n2 = n3 = n1; //将n2和n3指回最后一个节点
    34. n1 = head; //n1回到头结点
    35. bool flag = true;
    36. //判断是否是回文
    37. while(n1 != NULL && n2 != NULL)
    38. {
    39. if(n1->val != n2->val)
    40. {
    41. flag = false;
    42. break;
    43. }
    44. n1 = n1->next;
    45. n2 = n2->next;
    46. }
    47. //还原链表
    48. n2 = n3->next; //n3此时指向最后一个结点,因为反转了链表,n3的next就是上一个结点
    49. n3->next = NULL;
    50. while(n2!=NULL)
    51. {
    52. n1 = n2->next;
    53. n2->next = n3;
    54. n3 = n2;
    55. n2 = n1;
    56. }
    57. return flag;
    58. }

    时间复杂度:O(n),其中 n 指的是链表的大小。

    空间复杂度:O(1)。我们只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)。

     更多【LeetCode刷题】 推荐:

    【LeetCode力扣】86. 分隔链表-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133942678?spm=1001.2014.3001.5501【LeetCode力扣】297. 二叉树的序列化与反序列化-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133827375【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解)_Hacynn的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/133578735

     

    如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

    如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

    如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

     

  • 相关阅读:
    jq/h5 实现实时获取大文件下载进度
    基于SSM实现在线租房系统
    五元组评价算法实现简易五子棋【人工智能】
    怎么在Linux中用tmux跑深度学习模型
    点击微信公众号菜单发送图片
    python_函数
    JS--数组类型 Array 1
    MTK6765/MT6765联发科4G安卓核心板安兔兔跑分
    如何在洛谷里面新建自己的题目、配置数据点
    Kafka的这些重要概念,不管啥时候都得牢记
  • 原文地址:https://blog.csdn.net/zzzzzhxxx/article/details/133958602