力扣刷题链表篇

141. Linked List Cycle

题目地址
解题思路:

  1. 快慢指针,创建指针p每次前进一格,创建指针q每次前进二格,步长过大会增加pq相遇的时间。
  2. p, q的初始位置不同,原因是当只存在一个节点时,while循环会因为q的下一节点为NULL跳出循环,返回true值(当然也可以在while中做判断)
  3. whlie中 q != NULL && q->next != NULL 条件是为了防止q指向空指针。
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head == NULL) return false;
        ListNode *p = head, *q = head->next;
        while(q != NULL && q->next != NULL && q != p){
            p = p->next;
            q = q->next->next;
        }
        return q==p;
    }
};   

142. Linked List Cycle II

题目地址
解题思路:
基于快慢指针的思想,假设当q的步长是p的两倍时,head节点到 循环链表起点 距离为a个节点:

  1. 如下图所示,当p到达循环起点时,q已经在循环链表中走了a个节点,设q到p的距离为x,则循环链表周长为 a+x
    在这里插入图片描述
  2. 当p走了x,q就走了2x,此时两节点相遇,注意此时p和q到循环起点的距离为a,等于head到链表起点的距离。
    在这里插入图片描述
  3. 如图所示,重新让q指向head节点,当p, q再次相遇时,就会位于循环起始点。
    在这里插入图片描述
    代码实现:
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == NULL) return NULL;
        ListNode *p = head, *q = head;
        while(q && q->next){
            p = p->next;
            q = q->next->next;
            //if判断语句放在循环内仍然是为了考虑单个节点
            if(q == p){
	            q = head;
	            while(q != p){
	                q = q->next;
	                p = p->next;
	            }
	            return p;
        	}
        }
        return NULL;
    }
};

202. Happy Number

题目地址
解题思路:
如图所示,快乐数的推导过程可以看作是由自身节点推出下一个节点,最后输出相同的值时即为进入循环链表(快乐数会进入1循环,数字2会进入20循环)。所以仍然可以使用快慢指针判断。
在这里插入图片描述

class Solution {
public:
    
    int getNext(int x){
        int sum = 0;
        while(n){
            sum += (n % 10)*(n % 10);
            n = n/10;
        }
    }
    
    bool isHappy(int n) {
        int p = n, q = n;
        do{
            p = getNext(p);
            q = getNext(getNext(q)); 
        }while(q != p && q != 1)
        return q == 1;   
    }
};

206.reverse linked list

题目地址
解题思路:
创建三个指针:pre, cur, next
指针操作步骤:

  1. 定义 pre 为空指针
  2. cur 指向 pre 指向的节点
  3. pre 指向 cur 指向的节点
  4. cur 指向 next 指向的节点
  5. next 指向 next 的下一个节点
  6. 重复 2~6 直到 cur 指向最后的空节点

下图显示了上面描述的指针操作过程
在这里插入图片描述
上图的代码实现

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr || head-> next == nullptr) return head;
        ListNode *pre = nullptr, *cur = head, *p = head -> next;
        while(cur){
            cur -> next = pre;
            pre = cur;
            //这里是为了防止最后 p节点为空,会出现错误
            (cur = p) && (p = p -> next);
        }
        return pre;
    }
};

另一种思路是使用递归
如下图所示,交换 head节点 和 tail节点 的位置

代码实现为

head -> next = tail -> next;
tail -> next = head;

将上述思路通过递归的方式,从最后的节点开始逐对反转

代码实现:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr || head->next == nullptr) return head;
        ListNode *tail = head -> next, *p = reverseList(head -> next);//p 是最后的结点,也就是反转后的头结点
        head -> next = tail -> next;
        tail -> next = head;
        return p;
    }
};

92.reverse linked list II

解法1:使用上面的常规的三指针操作,记录起始反转位置(left)的前一个结点 head 和终止反转位置(rigtht)的后一个结点 pre。
在这里使用了 ret结点 作为头结点的前置结点,目的是便于找到反转链表的起始点。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        if(head == nullptr || head -> next == nullptr || left == right) return head;
        ListNode ret(0,head), *hair = &ret, *pre = head;
        int m = left, n = right, cnt = n - m + 1;
        while(--m) hair = hair -> next;
        
        while(n){
            pre = pre -> next;
            n--;
        }
        
        ListNode *cur = hair -> next, *p = hair -> next -> next;
        while(cnt){
           cur -> next = pre;
            pre = cur;
            (cur = p) && (p = p -> next); 
            cnt--;
        } 
        hair -> next = pre;
        return ret.next;
    }
};

解法2:只需要调用上面的递归函数,并稍作修改。原函数的递归最底层为最后一个结点,现在为反转链表范围的最后结点

class Solution {
public:
    ListNode* reverseList(ListNode* head, int n) {
        if(n == 1) return head;
        ListNode *tail = head -> next, *p = reverseList(head -> next, --n);
        head -> next = tail -> next;
        tail -> next = head;
        return p;
    }
    
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        if(head == nullptr || head -> next == nullptr || left == right) return head;
        ListNode ret(0,head), *hair = &ret;
        int m = left, n = right, cnt = n - m + 1;
        while(--m) hair = hair -> next;
        hair -> next = reverseList(hair -> next, cnt);
        
        return ret.next;
    }
};

25. Reverse Nodes in K-Group

题目地址
完全是基于上边已有的代码,非常简单
reverseK() 函数中有一个小技巧,如果传入的链表长度小于规定的长度,直接返回原链表,然后 reverseKGroup()中通过判断返回的链表头结点是否为原来的结点来决定是否跳出循环

class Solution {
public:
    ListNode* reverseList(ListNode* head, int n) {
        if(n == 1) return head;
        ListNode *tail = head -> next, *p = reverseList(head -> next, --n);
        head -> next = tail -> next;
        tail -> next = head;
        return p;
    }
    
    ListNode* reverseK(ListNode* head, int k) {
        ListNode *p = head;
        int cnt = k;
        while(--k && p) p = p -> next;
        if(p == nullptr) return head;
        return reverseList(head, cnt);
    }
    
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode ret(0, head), *p = &ret, *q = p -> next;
        while((p -> next = reverseK(q, k)) != q) {
            p = q;
            q = q -> next;
        }    
        return ret.next;
    }
};

61. Rotate List

题目地址
解题思路:
将链表首尾连接,寻找断点并断开

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == nullptr || head->next == nullptr) return head;
        int n = 1;
        ListNode*p = head;
        while(p->next){
            p = p->next, n++;
        }
        p->next = head;
        
        k %= n, k = n - k;
        while(k--) p = p->next;
        head = p->next;
        p->next = nullptr;
        return head;
    }
};

19. Remove Nth Node From End of List

地址

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode ret(0, head), *p = &ret, *q = head;
        while(n--) q = q->next;
        while(q != nullptr) p = p->next, q = q->next;
        p->next = p->next->next;
        return ret.next;
    }
};

83. Remove Duplicates from Sorted List

题目地址

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == nullptr) return nullptr;
        ListNode *p = head;
        while(p->next){
            if(p->val == p->next->val){
                p->next = p->next->next;
            }else{
                p = p->next;
            }
        }
        return head;
    }
};

82. Remove Duplicates from Sorted List II

题目地址

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        
        if(head == nullptr || head->next == nullptr) return head;
        ListNode ret(0,head), *p = &ret, *q;
        while(p->next){
            if(p->next->next && p->next->val == p->next->next->val){
                q = p->next->next;
                while(q && q->val == p->next->val) q = q->next;
                p->next = q;
            }else{
                p = p->next;
            }
        }
        
        return ret.next;
    }
};

24. Swap Nodes in Pairs

地址

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head->next == nullptr) return head;
        ListNode ret(0, head), *q = &ret, *p = head;
        while(p && p->next){
            q->next = p->next;
            p->next = p->next->next;           
            q->next->next = p;
            q = q->next->next;
            p = p->next;
        }
        return ret.next;
    }
};

86. Partition List

地址

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        if(head == nullptr || head->next == nullptr) return head;
        ListNode ret(0, head), *p = &ret, *q = head, *m;
        while(q->next && p->next){
            while(p->next && p->next->val < x) p = p->next;
            q = p;
            while(q->next && q->next->val >= x) q = q->next;
            if(p->next && q->next){
                m = q->next;
                q->next = m->next;
                m->next = p->next;
                p->next = m;  
            }    
        }
        return ret.next;
    }
};

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode h1, h2, *p1 = &h1, *p2 = &h2;
        for(ListNode *p = head, *q; p != nullptr; p = q){
            q = p->next;
            p->next = nullptr;
            if(p->val < x){
                p1->next = p;
                p1 = p;
            }else{
                p2->next = p;
                p2 = p;
            }
        }
        p1->next = h2.next;
        return h1.next;
    }
};

138. Copy List with Random Pointer

地址
复制原链表,将原链表的random赋给random

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head == nullptr) return head;
        Node *p = head, *q, *new_head;
        while(p){
            q = new Node(p->val);
            q->next = p->next;
            q->random = p->random;
            p->next = q;
            p = q->next;
        }
        p = head->next;
        while(p){
            if(p->random != NULL){
                p->random = p->random->next;
            }
            p = p->next;
            if(p) p = p->next;
        }
        new_head = head->next;
        p = head;
        while(p){
            q = p->next;
            p->next = q->next;
            if(p->next) q->next = p->next->next;
            p = p->next;
        }
        return new_head;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值