链表习题及详解

LCR 027. 回文链表 - 力扣(LeetCode)

思路:我们把链表看成前半部分和后半部分,把后半部分翻转和前半部分对比,看是否是回文链表。这里用c语言写的。

步骤:

1.找到后半部分的链表表头:快慢指针做法,快指针一次走两步,慢指针一次走一步,快指针不能再继续走的时候慢指针正好走到中点。

2.翻转后半部分链表

3.对比前半部分

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head) {
   if(head==NULL || head->next==NULL) return head;
   struct ListNode* pnewhead=NULL;
   struct ListNode* ptake=head;
   struct ListNode* pbroke=head->next;
   while(1)
   {
       ptake->next=pnewhead;
       if(pbroke==NULL) return ptake;
       pnewhead=ptake;
       ptake=pbroke;
       pbroke=pbroke->next;
   }
}

struct ListNode* ListHalf(struct ListNode* head) {
   struct ListNode* fast=head;
   struct ListNode* slow=head;
   while(fast->next && fast->next->next)
   {
       fast=fast->next->next;
       slow=slow->next;
   }
   return slow;
}

bool isPalindrome(struct ListNode* head) {
   if(head==NULL)
    return true;
    struct ListNode* head2=ListHalf(head);
    head2=reverseList(head2->next);
    bool res=true;
    while(res && head2)
    {
        if(head->val!=head2->val) return false;
        head2=head2->next;
        head=head->next;
    }
    return res;
}

92. 反转链表 II - 力扣(LeetCode)

思路:在区间[left,right]翻转链表,然后再拼接上。

步骤:

1.需要四个位置的节点,left的前一个结点,left节点,right节点,right的后一个节点。

2.翻转[left,right]。

3.重新连接,left前一个结点连right节点,left节点连right后一个节点。

注:由于考虑到表头翻转之后改变这个情况,引入虚拟头节点Head。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 #include<stdio.h>
 void reverseList(struct ListNode* head) {
  
   struct ListNode* pnewhead=NULL;
   struct ListNode* ptake=head;
   struct ListNode* pbroke=head->next;
   while(1)
   {
       ptake->next=pnewhead;
       if(pbroke==NULL) break;
       pnewhead=ptake;
       ptake=pbroke;
       pbroke=pbroke->next;
   }
}

struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
    int len=0;
    struct ListNode* Head=malloc(sizeof(struct ListNode));
    Head->val=-1;
    Head->next=head;
    //left的前一个结点
     struct ListNode* leftlinkheadpre=Head;
    while(len!=left-1)
    {
        leftlinkheadpre=leftlinkheadpre->next;
        len++;
    }
     //right节点
      struct ListNode* rightlinkend=leftlinkheadpre;
    while(len!=right)
    {
        len++;
        rightlinkend=rightlinkend->next;
    }
    //left节点
    struct ListNode* leftlinkhead=leftlinkheadpre->next;
    //right后一个节点
    struct ListNode* rightlinkhend=rightlinkend->next;
    leftlinkhead->next==NULL;
    rightlinkend->next=NULL;
   reverseList(leftlinkhead);
   leftlinkheadpre->next=rightlinkend;
   leftlinkhead->next= rightlinkhend;
   return Head->next;
}

这种方法在left是头节点,right是尾节点时,会遍历两次链表,那么还有一种头插法方式,可以遍历一次。

思路:在需要反转的区间里,每遍历到一个新的节点,就把新节点插到前面去,举个例子,蓝色是需要翻转的区间。

1->2->3->4->5->6  =>  1->2->4->3->5->6  =>  1->2->5->4->3->6

定义left的前一个节点preleft,向后移动的节点back,向前移动的节点front。

perleft不动然后按照(1)(2)(3)顺序移动

  back->next=front->next;   front->next=preleft->next;     leftpre->next=front;

(其实back一直指向3)back一直不动,front=back->next;  然后继续执行这三步 back->next=front->next;   front->next=preleft->next;     leftpre->next=front;

最后变成这样

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
    int len=0;
    struct ListNode* Head=malloc(sizeof(struct ListNode));
    Head->val=-1;
    Head->next=head;
    //left的前一个结点
     struct ListNode* leftpre=Head;
    while(len!=left-1)
    {
        leftpre=leftpre->next;
        len++;
    }
     //back节点
      struct ListNode* back=leftpre->next;
      //front节点
      struct ListNode* front=NULL;
    while(len!=right-1)
    {
        len++;
        front=back->next;
        back->next=front->next;
        front->next=leftpre->next;
        leftpre->next=front;
    }
   return Head->next;
}

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值