leetcode200题之链表(一)

1.删除链表中的节点

我们无法访问我们想要删除的节点 之前 的节点,我们始终不能修改该节点的 next 指针。相反,我们必须将想要删除的节点的值替换为它后面节点中的值,然后删除它之后的节点。

class Solution {
public:
    void deleteNode(ListNode* node) {
        node->val=node->next->val;  //将想要删除的节点的值替换为它后面节点中的值
        node->next=node->next->next; //删除next节点
    }
};

2. 分隔链表

思路:如果我们在分割点将改后链表拆分,我们会得到两个更小的链表,其中一个包括全部值小于x的元素,另一个包括全部值大于x的元素。两个指针可以用于分别创建两个链表,然后将这两个链表连接即可获得所需的链表

  1. 初始化两个指针 front 和 back。在实现中,我们将两个指针初始化为哑 ListNode。这有助于减少条件判断。
  2. 利用head指针遍历原链表。
  3. head 指针指向的元素值 小于 x,该节点应当是 front 链表的一部分。因此我们将其移到 front 中
  4. 否则,该节点应当是back 链表的一部分。因此我们将其移到 back 中
  5. 遍历完原有链表的全部元素之后,我们得到了两个链表 front 和 back。原有链表的元素或者在front 中或者在 back 中,这取决于它们的值。
  6. 现在,可以将 front 和 back 连接,组成所求的链表。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode* front=new ListNode(0);
        ListNode* back=new ListNode(0);
        ListNode* p1=front,*p2=back;
        while(head!=nullptr){
            if(head->val<x){
                p1->next=head;
                p1=p1->next;
                head=head->next;
            }
            else{
                p2->next=head;
                p2=p2->next;
                head=head->next;
            }
        }
        p2->next=nullptr;
        p1->next=back->next;
        return front->next;
    }
};

3. 环形链表Ⅰ

思路:用快慢指针方法,快指针走两步慢指针走一步。如果有闭环,那么快慢指针一定会相遇;如果没有闭环,那么快指针一定会先走到头,直接return false就好了。 

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast!=nullptr && fast->next!=nullptr){
            slow=slow->next;
            fast=fast->next->next;
            if(slow==fast)  return true;
        }
        return false;
    }
};

4. 环形链表Ⅱ

双指针第一次相遇: 设两指针 fastslow 指向链表头部 headfast 每轮走 2 步,slow 每轮走 1 步;

  1. 第一种结果: fast 指针走过链表末端,说明链表无环,直接返回 null;

    TIPS: 若有环,两指针一定会相遇。因为每走 1 轮,fast 与 slow 的间距 +1,fast 终会追上 slow;

  2. 第二种结果: 当fast == slow时, 两指针在环中 第一次相遇 。下面分析此时fast 与 slow走过的 步数关系

追上时:   快指针=慢指针+n*圈,   快指针=2*慢指针      ——>  慢指针走了n*圈

那么假设到环节点入口处有k个节点,那么所有走到环节点入口的步数为:k+n*圈(每经一圈回到入口点);所以可以让一个指针从链表头节点处和此时的慢指针一起走k步,那么相遇点即为入口点。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head==nullptr)  return nullptr;
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast != nullptr && fast->next != nullptr){
            fast=fast->next->next;
            slow=slow->next;
            if(slow==fast) break;
        }
        if(fast==nullptr||fast->next==nullptr)  return nullptr;
        else{
            fast=head;
            while(fast!=slow){
                fast=fast->next;
                slow=slow->next;
            }
            return fast;
        }
        return nullptr;
    }
};

5. 反转链表

递归:解法直接看代码理解

迭代:在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用!

//递归
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==nullptr|| head->next==nullptr)  return head;
        ListNode* node=reverseList(head->next);
        head->next->next=head;
        head->next=nullptr;
        return node;
    }
};

//迭代
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre=nullptr;
        ListNode* cur=head;
        while(cur!=nullptr){
            ListNode* tmp = cur->next;
            cur->next=pre;
            pre=cur;
            cur=tmp;
        }
        return pre;
    }
};

6.反转链表Ⅱ 

思路:和反转整个链表类似。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode* pre=nullptr;
        int count=1;
        ListNode* cur=head;
        ListNode*  pre0,*cur0;
        while(cur!=nullptr && count<=n){
            //当cur为m时,记录一下当前cur和pre,留作最后的连接
            if(count==m){
                pre0=pre;
                cur0=cur;
                pre=cur;
                cur=cur->next;
            }
            else if(count > m && count<=n){  反转链表4步骤
                ListNode* tmp=cur->next;
                cur->next=pre;
                pre=cur;
                cur=tmp;
            }
            else{   //不在[m,n]范围内,迭代前行
                pre=cur;
                cur=cur->next;
            }
            count++;
        }
        if(pre0==nullptr)  head=pre; //头节点便开始反转
        else pre0->next=pre;   //连接
        cur0->next=cur;
        return head;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值