leetcode关于链表的两个题目--移除链表里面的元素&&链表的翻转操作

35 阅读5分钟

1.第一个题目:移除链表里面的元素

移除链表里面的指定数值的这个元素,也就是这个输入的数据里面包含了我们需要删除的这个数据;

image-20250723171216323

下面的这个是代码:我说一下这个思路,就是我们搞了一个新的链表,原来的这个链表里面不是val的元素都会插入到我们的这个新的链表里面去,最后返回我们的这个新的链表;下面详细分析一下代码和可能遇到的问题;

1)先定义这个newtail和newhead表示的就是我们的新链表的头结点和尾结点,刚开始设置为null即可;

2)pcur是用来对于我们的原来的链表进行遍历操作的,因此是被head赋值,这个head是我们的函数的形参哈

3)pcur进行遍历,条件就是不为空,遇到不是val的元素进行插入即可;

4)插入也分情况,如果第一次插入,就是尾插,也就是newhead==null,这个时候我们是第一个插入的冤元素,因此这个newhead,newtail指向的都是这个位置;

else里面就是说,当已经存在元素的时候,我们需要把这个pcur传递给我们的新链表的尾结点的下一个位置,然后这个newtail进行挪动即可;

5)if之后,只是进行一次,我们需要这个pcur不断的移动,进行遍历;

6)当我们直接返回的时候,就会报错,因为这个时候我们的新链表的微元素指向的还是原来的节点,因此我们需要置为空值;

7)这个时候还会报错,是因为空链表的情况下我们不可以直接解引用,需要判断是不是空的;

8)我自己犯的错误,就是第二行的函数代码写成了newtail=newtail=NULL,这个时候不断的提示报错,说是这个空指针啥的,修改之后就没有了,可能是这个运算符的优先级的问题,哈哈,注意一下;

typedef struct ListNode listnode;
struct ListNode* removeElements(struct ListNode* head, int val) 
{
    listnode* newhead,*newtail;
    newhead=newtail=NULL;

    listnode* pcur=head;
    while(pcur)
    {
        if(pcur->val!=val)
        {
            if(newhead==NULL)
            {
                newhead=newtail=pcur;
            }
            else{
                newtail->next=pcur;
                newtail=newtail->next;
            }
        }
        pcur=pcur->next;
    }
    if(newtail)
    {
        newtail->next=NULL;
    }
    return newhead;
}

2.第二个题目:翻转链表

image-20250723192944559

下面的这个思路我们简单的介绍一下

下面的这个解法应该是非常简单的一个解决方法,但是不是所有的人都可以想到这个解决的方案,哈哈;

就是定义三个指针,n1,n2,n3通过指针的这个移动和这个指针的指向的变化,就可以解决我们的问题啦;

 typedef struct ListNode listnode;
struct ListNode* reverseList(struct ListNode* head) {
    listnode* n1,*n2,*n3;
    if(head==NULL){
        return head;
    }
    n1=NULL,n2=head,n3=n2->next;
    while(n2){
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
            n3=n3->next;
    }
    return n1;
}

为了方便大家进行理解,我使用作图软件花了这个草图,方便去说明问题:

刚开始的时候,我们的n1指向的事空的,n2指向的事我们的头结点,n3就是n2的下一个节点,然后我们的这个n2指向n1,接下来就是这个指针的移动过程,就是n1挪动到这个n2的位置上面去,n2挪动到这个n3上面的位置去,n3继续向后面进行移动即可,这个时候我们的指针的指向就发生了变化;

image-20250723194701427

接下来实际上就是对于上面的这个过程的重复操作:就是不断的n2指向我们的n1修改这个指针的指向,然后就是全体向后进行移动,n1挪动到这个n2位置,n2挪动到这个n3的位置即可;

image-20250723194931674

然后我们看一下这个结束的条件,大家是可以明显的发现:当我们的这个指针走着走着,一直到这个n2是空的时候,我们的这个过程就结束了,因此我们也就知道了这个循环结束的判断的条件;

image-20250723195040127

接下来结合着看一下这个代码的内容,n1n2n3的定义肯定是没有问题的,while(n2)就是想要说明这个n2不是空值的时候,我们的这个操作是需要一直执行下去的;

因为这个最后结束的时候n3是空的情况下还是多走了一步的,因此这个需要判断一下,当我们的这个n3不是null的时候,这个操作才会执行,否则就会出现这个空指针的解引用的问题;

最后的时候,大家是可以发现,这个n2就是新的这个链表的头结点,我们直接返回即可;

但是这个链表可能是空的,这个时候我们的n2=head也就是说我们的这个n2是空的,这个时候n3=n2->next就会出现空值的解引用的问题,因此这个也是需要处理一下的,也就是说我们的head==null的时候,我们直接返回这个head也就是null直接返回即可;

 typedef struct ListNode listnode;
struct ListNode* reverseList(struct ListNode* head) {
    listnode* n1,*n2,*n3;
    if(head==NULL){
        return head;
    }
    n1=NULL,n2=head,n3=n2->next;
    while(n2){
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
            n3=n3->next;
    }
    return n1;
}