2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题

1、指定区间反转2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题_第1张图片

1.1 头插法 

 反转的整体思想是:每遍历到一个节点后,让该节点来到反转部分的起始位置。

2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题_第2张图片

 这个过程像是头插法。

ListNode *reverseBetween1(ListNode *head,int left,int right)
{
    ListNode *pre=NULL;
    ListNode *ans=(ListNode *)malloc(sizeof(ListNode));
    ans->next=head;
    pre=ans;
    for(int i=0;i     {
        pre=pre->next;
    }
    ListNode *cur=pre->next;
    ListNode *next=NULL;
    for(int i=0;i     {
        next=cur->next;
        cur->next=next->next;
        next->next=pre->next;
        pre->next=next;
    }
    ListNode *NewHead=ans->next;
    free(ans);
    return NewHead;

1.2 穿针引线法

2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题_第3张图片

先确定好需要反转的部分,然后将链表分成3部分,将要反转的部分拿出来,反转后放入正确的位置。

 2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题_第4张图片

ListNode *reverseBetween2(ListNode *head,int left,int right)//穿针引线法先把left和right之间的部分翻转再接上
{
    ListNode *dummyNode=(ListNode *)malloc(sizeof(ListNode));
    dummyNode->next=head;
    ListNode *pre=dummyNode;
    for(int i=0;i     {
        pre=pre->next;
    }
    ListNode *leftNode=pre->next;
    ListNode *rightNode=pre;
    for(int i=0;i     {
        rightNode=rightNode->next;
    }
    ListNode *succ=rightNode->next;
    pre->next=NULL;
    rightNode->next=NULL;
    ListNode *NewLeftNode=reverseList(leftNode);
    if(rightNode==NewLeftNode)
    cout<<"1"<     else 
    cout<<"0"<     leftNode->next=succ;
    //pre->next=NewLeftNode;//T
    pre->next=rightNode;//T
    ListNode *NewHead=dummyNode->next;
    free(dummyNode);
    return NewHead;
    
}

ListNode *reverseList(ListNode *head)//不建立虚拟头节点的翻转链表,可以背诵
{
    ListNode *pre=NULL;
    ListNode *cur=head;
    
    while(cur!=NULL)
    {
        ListNode *next=cur->next;
        cur->next=pre;
        pre=cur;
        cur=next;
    }
    return pre;
}  

 2.两两交换链表中的节点

  LeetCode 24

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题_第5张图片

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

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

 题目的意思是:如果原始顺序为dummyNode->node1->node2,我们需要把他变成 dummyNode->node2->node1。 

ListNode *SwapPairs(ListNode *head)
{
    ListNode *temp=NULL;
    ListNode *dummyNode=(ListNode *)malloc(sizeof(ListNode));
    dummyNode->next=head;
    temp=dummyNode;
    while(temp->next!=NULL&&temp->next->next!=NULL)
    {
        ListNode *node1=temp->next;
        ListNode *node2=temp->next->next;
        node1->next=node2->next;
        node2->next=node1;
        temp->next=node2;
        temp=node1;
    } 
    ListNode *NewHead=dummyNode->next;
    free(dummyNode);
    return NewHead;    
}  

3.链表加法

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

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

示例1:

2023.9.14 算法通关村第二关--白银挑战--链表反转的拓展问题_第6张图片

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

示例2:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]

示例3:

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

加法是从最低位开始,但链表的遍历从最高位开始。先把链表反转,从低位开始遍历。链表反转可以新建一个链表,也可以用原链表反转。然后用尾插法新建一个链表,从低位开始把节点插入链表。

ListNode *addTwoNumbers(ListNode *l1,ListNode *l2)
{
    ListNode *st1=NULL;
    ListNode *st2=NULL;
    ListNode *curr1=l1;
    ListNode *curr2=l2;
    while(curr1!=NULL)//st1在这里是第一个链表反转后的头节点 
        {
            ListNode *new_Node=(ListNode *)malloc(sizeof(ListNode));
            new_Node->val=curr1->val;
            new_Node->next=st1;
            st1=new_Node;
            curr1=curr1->next;    
        }    
    while(curr2!=NULL)//st2在这里是第二个链表反转后的头节点 
        {
            ListNode *new_Node=(ListNode *)malloc(sizeof(ListNode));
            new_Node->val=curr2->val;
            new_Node->next=st2;
            st2=new_Node;
            curr2=curr2->next;    
        }    
    curr1=st1;
    curr2=st2;
    int suma=0,sumb=0;
    ListNode *new_head=(ListNode *)malloc(sizeof(ListNode));//要返回的新链表的头节点
    new_head->val=-1;
    new_head->next=NULL; 
    int carry=0;
    while(curr1!=NULL||curr2!=NULL||carry!=0)
    {
        ListNode *new_Node=(ListNode *)malloc(sizeof(ListNode));
        if(curr1!=NULL)
        {
            suma=curr1->val;
            curr1=curr1->next;
        }
        else
        {
            suma=0;
        }
        if(curr2!=NULL)
        {
            sumb=curr2->val;
            curr2=curr2->next;
        }
        else
        {
            sumb=0;
        }
        int get_sum=suma+sumb+carry;
        int ans=get_sum%10;//ans是要存入新链表的数据 
        int carry=get_sum/10;//carry是进位 
        
        new_Node->val=ans;
        new_Node->next=new_head->next;
        new_head->next=new_Node;
    }
    ListNode *ret=new_head->next;
    free(new_head);
    return ret; 

 4.再论链表回文问题

判断链表回文。先反转一半链表,会将原链表分成两段新的链表(如果是偶数个节点,会分成两段链表。如果是奇数个节点,会分成3段。中间部分只是一个节点)。 分别从头遍历两段链表,只要有一次节点的数据域不相等,返回false。如果都遍历完成,则返回true。

bool isPalindrome(ListNode *head)
{
    if(head==NULL&&head->next==NULL)
    {
        return true;    
    }    
    ListNode *fast=head;
    ListNode *slow=head;
    ListNode *pre=head;
    ListNode *prepre=NULL;
    while(fast!=NULL&&fast->next!=NULL)//将一半链表反转 
    {
        pre=slow;
        slow=slow->next;
        fast=fast->next->next;
        pre->next=prepre;
        prepre=pre;
    }
    if(fast!=NULL)//提示是奇数个节点的链表,slow移动至中间节点的下一个节点 
    {
        slow=slow->next;
    }//pre和slow分别是两段链表的头节点 
    while(pre!=NULL&&slow!=NULL)
    {
        if(pre->val!=slow->val)
        return false;
        
        pre=pre->next;
        slow=slow->next;
    }
    return true;

你可能感兴趣的:(链表,数据结构)