链表常见题型(1)

1.反转链表

1.1反转链表

链表常见题型(1)_第1张图片

      如果我们想要反转链表,那应该有head的next指针指向空,其余结点的next指针反过来,指向它的上一个结点,那我们在执行该操作的时候就需要定义变量cur(current)表示我们当前遍历到的结点,变量pre(previous)表示上一个结点,对于第一个结点来说,它的上一个结点为空,我们需要把当前的next指针指向上一个结点,但两个变量够吗?当我们修改当前结点的next指针时,它的下一个结点就丢失了,所以在修改之前还需要再定义一个变量nxt(next)记录cur的下一个结点,之后我们就可以把cur的next指针指向pre,pre=cur,cur=nxt,如此循环,当反转结束后,pre指向反转这一段的末尾,cur指向反转这一段末尾的下一个结点,所以反转结束时,cur指向NULL,如图所示

链表常见题型(1)_第2张图片

 ListNode* reverseList(ListNode* head){
      ListNode* nxt;
      ListNode* pre=NULL;
      ListNode* cur=head;
      while(cur){
          nxt=cur->next;
          cur->next=pre;
          pre=cur;
          cur=nxt;
      }
      return pre;
    }

 1.2反转链表||

链表常见题型(1)_第3张图片

     做这道题我们要用到上一道题的性质:当反转结束后,pre指向反转这一段的末尾,cur指向反转这一段末尾的下一个结点。所以当翻转结束后cur指向5,pre指向4,所以我们要把2指向cur,1指向pre,这样就组成了14325,我们需要记录反转这一段的上一个结点p,所以就是把p的next指向cur,p指向pre,但是当left等于1时是没有p的,所以此时我们要建立一个虚拟头结点,代码如下

ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* dummyhead=new ListNode(0,head);
        ListNode* p=dummyhead;
         for (int i = 0; i < left - 1; ++i)
            p = p->next;

        ListNode *pre = NULL, *cur = p->next;
        for (int i = 0; i < right - left + 1; ++i) {
            ListNode *nxt = cur->next;
            cur->next = pre; 
            pre = cur;
            cur = nxt;
        }
        p->next->next = cur;
        p->next = pre;
        return dummyhead->next;
    }

1.3K个一组翻转链表

链表常见题型(1)_第4张图片

      这个要求我们k个结点一组进行翻转,所以我们要先求出来链表的长度,如果大于等于k时,我们要判断剩余结点的个数,小于k是无法翻转的,翻转的过程和上一题是一样的,需要注意的是我们额外要在翻转之后把p更新成下一段要翻转的链表的上一个结点,但是由于最后我们修改了p的next指针,所以我们需要在修改之前额外创建一个临时变量nxt=p->next,翻转结束后令p=nxt开始下一段循环,不断循环,最后返回dummyhead->next,代码如下:

 ListNode* reverseKGroup(ListNode* head, int k) {
         ListNode* head1=head;
         int len=0;
         while(head1)
         {
             len++;
             head1=head1->next;
         }
        ListNode* dummyhead=new ListNode(0,head);
        ListNode* p=dummyhead;
        ListNode *pre = NULL, *cur = p->next;
        for (; len>=k;len-=k ) {
            for(int i=0;inext;
            cur->next = pre; 
            pre = cur;
            cur = nxt;
            }
        
        ListNode* nxt=p->next;
        p->next->next = cur;
        p->next = pre;
        p=nxt;
}
        return dummyhead->next;
    }

2.链表删除

    我们要想删除链表的某个结点,需要利用上一个结点的next指针指向删除结点的下一个结点

2.1删除链表中的节点

链表常见题型(1)_第5张图片

链表常见题型(1)_第6张图片 

     之前我们在基础数据结构讲过如何删除一个结点,但这个它不给我头结点,我怎么删除啊,这题就很秒,它说node不是链表的最后一个结点,也就是说我们可以把node结点的下一个结点的值复制过来,然后删除下一个结点,这可太妙了!

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

2.2 删除链表的倒数第N个结点

链表常见题型(1)_第7张图片

     第一种做法就是遍历求出链表长度,这样我们就知道要删除的倒数第N个结点是正数的第几个了,我们再遍历到这个结点的上一个结点执行删除操作,同时因为n可能等于链表长度,所以我们需要建立虚拟头结点,这样就OK了。

    第二种做法是快慢指针,我们需要找到倒数第N+1个结点,初始化右指针指向虚拟头结点,先让右指针走N步,然后初始化左指针指向虚拟头结点,左右指针一起向右移动,这样两个指针的距离始终为N,当右指针走向倒数第一个结点,左指针就恰好走到了倒数第N+1个结点,这时候就可以执行删除操作了!

ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead=new ListNode(0);
        dummyhead->next=head;
        ListNode* slow=dummyhead;
        ListNode* fast=dummyhead;
        while(n--&&fast!=NULL){
            fast=fast->next;
        }
        
        while(fast->next!=NULL){
            slow=slow->next;
            fast=fast->next;
        }
        slow->next=slow->next->next;
        return dummyhead->next;
    }

2.3删除排序链表中的重复元素

链表常见题型(1)_第8张图片

     这个题还是比较简单的,首先并不需要虚拟头结点,因为就算头结点的值和下一个结点的值相等,也会保留头结点,我们只需要遍历链表,如果cur的下一个结点的val值和cur的val值相等,我们就删除cur的下一个结点,需要注意的是循环条件是cur->next,当cur遍历到最后一个结点时,cur的下一个结点就不存在是NULL,此时应该退出循环,如果是cur则会继续进入循环造成NULL指针的解引用,会报错

    ListNode* deleteDuplicates(ListNode* head) {
        if(head==NULL)return NULL;
        ListNode* cur=head;
        while(cur->next)
        {
            if(cur->next->val==cur->val)
            {
                cur->next=cur->next->next;
            }
            else
            {
            cur=cur->next;
            }
        }
        return head;
    }

 2.4 删除排序链表中的重复元素||

链表常见题型(1)_第9张图片

     首先这个题需要建立虚拟头结点,因为如果开头就有几个重复的结点,那么头结点会被删除,所以我们先创建一个虚拟头结点,然后初始化cur指针指向虚拟头结点,然后遍历链表,每次遍历时,先取出cur的next的值val,如果cur的next的next的值和val相等,再进入循环判断cur的next的值是否等于val,相等就删除,否则移动到下一个结点,最后返回头结点

 ListNode* deleteDuplicates(ListNode* head) {
         ListNode* dummyhead=new ListNode(0);
         dummyhead->next=head;
         ListNode* cur=dummyhead;
         while(cur->next&&cur->next->next)
         {
            int val=cur->next->val;
            if(cur->next->next->val==val)
            {
                while(cur->next&&cur->next->val==val)
                {
                    cur->next=cur->next->next;
                }
            }
            else
            {
                cur=cur->next;
            }
         }
         return dummyhead->next;
    }

 

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