链表

写在最前面lol,为链表创建一个头结点的方法
eg:struct ListNode* l1,指针l1指向一个无头结点的链表

 struct ListNode header;
 header.next=l1;
 l1=&header;

则,l1现在指向有头结点的链表了

另外,对于&&
part1&&part2,如果part1为0,则不再继续验证part2的真假


160. 相交链表

这道题,说来很伤心,我初试的原题,当时抽了,没写出来,结果在准备复试的时候再一次刷到了。
这里提供和王道上(先分别计算两个链表的长度,然后先遍历长的链表,直到两个链表剩下未遍历的长度同之后,两个链表同时遍历,直到所指向的值相同,或者任何一个链表到尽头为止)不同的方法:

设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。

当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表
A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。

如果不存在交点,那么 a + b = b + a,以下实现代码中 l1 和 l2 会同时为 null,从而退出循环。

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *l1=headA,*l2=headB;
    while(l1!=l2){
        l1=(NULL!=l1)? l1->next:headB;
        l2=(NULL!=l2)? l2->next:headA;
    }
    return l1;
}

206. 反转链表

struct ListNode* reverseList(struct ListNode* head){
      struct ListNode* p,*q,*pre=NULL;//pre为造的头结点
   p=head;
   while(p){
       q=p->next;
       p->next=pre;//注意此处为pre,和本来就带有头结点的单链表不同
       pre=p;
       p=q;
   }
   return pre;
}

21. 合并两个有序链表

值得注意的是,这两个链表都为有序的
我将L1做为返回链表,把L2的每一个值与L1中的值依次比较,找到插入点

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){//l1为被插入链表,l2为被遍历的链表
    struct ListNode* t;
    struct ListNode header;
    header.next=l1;
    l1=&header;
    while(l2!=0){
        while(l1->next!=0&&l1->next->val<l2->val)//呜呜,这个先后顺序也要讲究一下,要是第一个结点就为空就不行了
            l1=l1->next;
        t=l2;
        l2=l2->next;
        t->next=l1->next;
        l1->next=t;
    }
    return header.next;
}

92. 反转链表 II

在这里插入图片描述
这道题也不难,就是指针指来指去有点昏。
思路就是把链表切成三段,然后再连起。
建议使用无头结单链表的方式进行逆置。

对于无头结单链表的总结

  1. 新创的指针在逆置完成后,会指向新链表的的第一个结点
  2. 用来遍历原链表的指针,会指向原链表之后的那个结点

分析自我的错误原因:我之前使用的带头结单链表逆置的方式,故把需要逆置的第一个结点的前驱(pre)做为头结点。但是报错,欲使用空指针,原因如下:
在这里插入图片描述

  1. 因为我首先想到可能从第一个结点就开始逆置了,那这是pre=NULL;
  2. 但是在我逆置的时候,需要pre作为头结点,所以这时候就有以上的报错信息了
    所以强烈建议使用无头结单链表的方式进行逆置!!!!
struct ListNode* reverseBetween(struct ListNode* head, int m, int n){
    int len = n - m + 1;//计算出需要逆置的个数
    struct ListNode *pre = NULL;
    struct ListNode *res = head;
    while(--m && head){
        pre = head;
        head = head->next;//将head向前移动到需要逆置的位置
    }
    struct ListNode *mod = head;
    struct ListNode *new = NULL;
    while(head && len){
        struct ListNode *next = head->next;
        head->next = new;//无头结点的单链表逆置
        new = head;
        head = next;
        len--;//每完成一个,需要的个数减1
    }
    mod->next = head;//连接逆置段的尾部与原链表不需要逆置尾部
    if(pre){
        pre->next = new;//如果pre不为空,说明不是从第一个开始的,则将前半段不逆置的与逆置的链接起来
    }else{
        res = new;//说明从第一个开始,直接链头
    }
    return res;
}

面试题 02.02. 返回倒数第 k 个节点

不得不说的一句是,leetcode上给的单链表是 没有头结点的,没有头结点!!!没有头结点!!!我刚直接认为是有头结点的,一直报错(欲使用空指针)
然后解决此问,我用到了链表逆置,单链表有无头结点,操作方法不怎么一样哈。
我去参考了下别人怎么做的,是造一个结点来用
下面是我自己用图形来增强记忆
在这里插入图片描述

int kthToLast(struct ListNode* head, int k){//先头插,变倒数为正数
   struct ListNode* p,*q,*pre=NULL;//pre为造的头结点
   p=head;
   while(p){
       q=p->next;
       p->next=pre;//注意此处为pre,和本来就带有头结点的单链表不同
       pre=p;
       p=q;
   }
   q=pre;
   int count=1;
   while(q){
       if(count==k)
            return q->val;
       q=q->next;
       count++;
   }
   return -1;
}

2. 两数相加

一遍AC的感觉有点爽,因为之前遇到过类似的问题,所以这次,每种情况都有考虑到哦。开森

int calculate(struct ListNode* p){
    int length=0;
    while(p){
        length++;
        p=p->next;
    }
    return length;
}

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){//在两数和用数组实现的基础上,用链表实现
    //若有进位,则还需要申请新的结点挂在链表尾部
    int carry=0,sum,length1=0,length2=0;
    struct ListNode* p,*q;
    //分别计算下这两个链表的长度,从而决定把最终结果存在哪个链表中
    length1=calculate(l1);
    length2=calculate(l2);
    if(length1>length2){
        p=l1,q=l2;
    }else{
        p=l2,q=l1;
    }
    struct ListNode* pre;
    while(p&&q){
        sum=p->val+q->val+carry;
        carry=0;
        if(sum>=10){
            carry=1;
            sum-=10;
        }  
        p->val=sum;
        pre=p;
        p=p->next;
        q=q->next;
    }
    if(carry==1&&p==NULL&&q==NULL){//进位挂尾结点
        struct ListNode* t=(struct ListNode*)malloc(sizeof(struct ListNode));
        t->val=1;
        t->next=NULL;//尾结点的next记得赋值为空
        pre->next=t;
    }else if(p!=NULL){//长度不同的时候
        while(p){
            p->val+=carry;
            carry=0;
            if(p->val>=10){
                carry=1;
                p->val-=10;
            }
            pre=p;
            p=p->next;
        }
        if(carry==1){
            struct ListNode* t=(struct ListNode*)malloc(sizeof(struct ListNode));
            t->val=1;
            t->next=NULL;//尾结点的next记得赋值为空
            pre->next=t;
        }
    } 
    return length1>length2?l1:l2;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值