画解数据结构刷题之单向链表(翻转函数)

本文详细介绍了链表的各种操作,包括判断回文、链表逆序、反转指定部分、两数相加以及节点操作。讲解了如何利用双指针、递归等方法高效解决链表问题,同时涉及到了链表的中间节点查找、索引处理和交换对等技巧。这些内容对于理解和掌握链表算法至关重要。
摘要由CSDN通过智能技术生成

链表回文

第一题

bool isPalindrome(struct ListNode* head){
struct ListNode*cur=head;
struct ListNode*vec[100001];
int i=0;
while(cur)
{
vec[i]=cur->val;
cur=cur->next;
i++;
}
int p=0;
int q=i-1;
while(p<q)
{
    if(vec[p]!=vec[q])
    {
        return false;
    }
    else{
        p++;
        q--;
    }
}
return true;

}

思路:将所有链表数据存入数组,用双指针比较

链表逆序

第一题

int* reversePrint(struct ListNode* head, int* returnSize){
   static int ret[10000];
struct ListNode*cur=head;
int i=0;
while(cur)
{
    ret[i++]=cur->val;
    cur=cur->next;
}
int q=i-1;
for(int j=0;j<i/2;j++)
{
    int temp=ret[j];
    ret[j]=ret[q];
    ret[q]=temp;
    q--;
}
*returnSize=i;
return ret;
}

第二题

struct ListNode* reverseList(struct ListNode* head){
struct ListNode*cur=head;
int num=0;
struct ListNode*vec[5001];
if(head==NULL)
{
    return NULL;
}
while(cur)
{
vec[num++]=cur;
cur=cur->next;
}
int temp=num-1;
for(int j=num-1;j>0;j--)
{
    vec[j]->next=vec[j-1];
}
vec[0]->next=NULL;
return vec[temp];
}

第三题 反转链表2

void reverse(struct ListNode*head)
{
    struct ListNode*pre=NULL;
    struct ListNode*cur=head;
    while(cur!=NULL)
    {
        struct ListNode*next=cur->next;
        cur->next=pre;
        pre=cur;
        cur=next;
    }
}

struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
struct ListNode*dummyhead=malloc(sizeof(struct ListNode));
dummyhead->val=0;
dummyhead->next=head;//虚拟头结点写法,用于头结点可能改变时
struct ListNode*pre=dummyhead;
for(int i=0;i<left-1;i++)//虚拟头结点走left-1步来到left前一个结点
{
    pre=pre->next;
}
struct ListNode*rightt=pre;
for(int i=0;i<right-left+1;i++)//来到right结点
{
    rightt=rightt->next;
}
struct ListNode*leftnode=pre->next;
struct ListNode*rightnode=rightt->next;//right的后面
pre->next=NULL;
rightt->next=NULL;
reverse(leftnode);
pre->next=rightt;
leftnode->next=rightnode;
return dummyhead->next;
}

注意:

(1)虚拟头结点的写法,dummyhead->next=head

(2)翻转链表函数的简易写法

void reverse (struct Listnode* head)
{
struct Listnode*pre=NULL;
struct Listnode* cur=head;
while(cur)
{
struct Listnode* next=cur->next;//记录cur->next
cur->next=pre;
pre=cur;
cur=next;
}

(3)如何获得链表中特定结点

for循环,记录步数

(4)用reverse函数后,之前记录的结点仍不变,只是后继结点改变而已,因此reverse后直接接上即可

第四题

两数相加2

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
struct ListNode*cur=l1;
struct ListNode*vec1[101];
struct ListNode*ret[101];
int len1=0;
int  m1=0;
while(cur)
{
    vec1[m1++]=cur;
    len1++;
    cur=cur->next;
}
struct ListNode*cur2=l2;
struct ListNode*vec2[101];
int len2=0;
int  m2=0;
while(cur2)
{
    vec2[m2++]=cur2;
    len2++;
    cur2=cur2->next;
}
if(len1>=len2)
{
    int temp=len1-len2;
    int q1=len1-1;
    int q2=len2-1;
    int add=0;
    for(int i=q1;i>=temp;i--)
    {
int temp2=vec1[i]->val+vec2[q2--]->val+add;

if(temp2>=10)
{
    add=1;
    temp2=temp2-10;
}
else{
    add=0;
}
vec1[i]->val=temp2;
    }
    return vec1[0];
}
else{
    int temp=len2-len1;
    int q1=len1-1;
    int q2=len2-1;
    int add=0;
    for(int i=q2;i>=temp;i--)
    {
        int temp3=vec2[q2]->val+vec1[q1--]->val+add;
        if(temp3>=10)
        {
            add=1;
            temp3=temp3-10;
        }
        else{
            add=0;
        }
        vec2[i]->val=temp3;
    }
    return vec2[0];
}
return 0;
}

实在看不懂题解里的栈,我是废物

下为翻转函数头尾指针版,返回的是翻转后的头

struct ListNode*reverse(struct ListNode*head,struct ListNode*tail){
    if(head->next==tail)
    return head;
    struct ListNode*p1=reverse(head->next,tail);
    head->next->next=head;
    head->next=NULL;
    return p1;
}

链表遍历

第一题

struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* small=malloc(sizeof(struct ListNode));
struct ListNode*p1=small;
struct ListNode*smallhead=small;
struct ListNode* big=malloc(sizeof(struct ListNode));
struct ListNode*p2=big;//因为是新链表所以要malloc
struct ListNode*largehead=big;
struct ListNode*cur=head;
while(cur)
{
    if(cur->val<x)
    {
        p1->next=cur;
        cur=cur->next;
        p1=p1->next;
    }
    else
    {
        p2->next=cur;
        cur=cur->next;
        p2=p2->next;
    }
}
p2->next=NULL;
p1->next=largehead->next;
return smallhead->next;
}

维护两个链表,一个小于x,一个大于等于x

第二题

struct ListNode* swapNodes(struct ListNode* head, int k){
    struct ListNode *tar1,*tar2;//目标结点
    int num=0;
    struct ListNode *fast;
    fast=head;
    tar2=head;
    while(--k)
    {
        fast=fast->next;
    }
    tar1=fast;//此时tar1为第k个结点
    while(fast->next)
    {
        fast=fast->next;
        tar2=tar2->next;//此时tar2为倒数第k个结点
    }
    num=tar1->val;
    tar1->val = tar2->val;
    tar2->val = num;

return head;

}

一次遍历找到第k个和倒数第k个,先遍历k-1次,找到第k个,然后让fast继续遍历len-(k-1)次,tar2同时从头开始遍历len-(k-1)次

链表结点删除

第一题

struct ListNode* deleteNode(struct ListNode* head, int val){
struct ListNode*dummyhead=malloc(sizeof(struct ListNode));
dummyhead->next=head;
dummyhead->val=-1;//虚拟头指针
struct ListNode*cur=head;
if (cur->val == val) {
        return cur->next;
    }
while(cur)
{
    if(cur->next->val==val)
    {
        cur->next=cur->next->next;
        break;
    }
    cur=cur->next;
}
return dummyhead->next;
}

第二题

void deleteNode(struct ListNode* node) {
    node->val=node->next->val;
    node->next=node->next->next;
}

 将next赋值给node,把next的next赋值给node的next

第三题

struct ListNode* removeZeroSumSublists(struct ListNode* head){
struct ListNode*pre=malloc(sizeof(struct ListNode));
pre->next=head;
pre->val=0;
struct ListNode*left=pre;
int sum;
while(left)
{
sum=0;
struct ListNode*right=left->next;
while(right)
{
    sum+=right->val;
    if(sum==0)
    {
        left->next=right->next;
    }
    right=right->next;
}
left=left->next;
}
return pre->next;
}

思路:维护n方的前缀和,注意第一次的left从头结点的前继结点开始算,因为right=left->next,让right从头结点开始算

链表索引

第一题

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

找中间结点,快指针一次走两步,慢指针一次走一步,当快指针走到表尾或快要走到表尾时,慢指针就会达到中间结点

第二题

int* nextLargerNodes(struct ListNode* head, int* returnSize){
struct ListNode*left=head;
int *ret =  (int*)malloc(sizeof(int)*10001);
    memset(ret,0,sizeof(int)*10001);
int i=0;
while(left)
{
    struct ListNode*right=left->next;
    while(right)
    {
    if(right->val>left->val)
    {
        ret[i]=right->val;
        break;
    }
    right=right->next;
    ret[i]=0;
    }
    i++;
    left=left->next;
}
*returnSize=i;
return ret;
}

链表交换

第一题

 

struct ListNode* swapPairs(struct ListNode* head) {
    struct ListNode dummyHead;
    dummyHead.next = head;
    struct ListNode* temp = &dummyHead;
    while (temp->next != NULL && temp->next->next != NULL) {
        struct ListNode* node1 = temp->next;
        struct ListNode* node2 = temp->next->next;
        temp->next = node2;
        node1->next = node2->next;
        node2->next = node1;
        temp = node1;
    }
    return dummyHead.next;
}

思路:当需要分组作业时,可以不用划分特定组,可以像这道题一样,规定一个temp做检测变量,每次变换temp后的两个结点,最后把第二个结点赋值给temp即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值