2022-02-27Leetcode训练营_双指针

天池训练营链接

天池leetcode训练营

删除链表中的重复元素

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head==nullptr || head->next ==nullptr) return head;
        int v=head->val;
        ListNode* cur=head->next;
        ListNode* pre=head;
        while(cur){
            if(cur->val > v){
                v=cur->val;
                cur=cur->next;
                pre=pre->next;
            }
            else{//删除cur
                pre->next=cur->next;
                cur=pre->next;
            }
        }
        return head;
    }
};

环形链表

思路1:题目给的最大节点数10000,所以遍历10000次,里面出现null就是无,否则有
思路2:unordered_set,把节点存进去,每扫一个,判断有没有在集合里出现过
思路3:两个节点都从head出发,快节点每次前进2个,慢节点每次前进1个,中间有交汇就是有环,快节点出null就是无环。

  • 这个代码写的不好看,有时间改一下。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        //unordered_set可以处理,但有空间复杂度。
        if(!head) return false;
        //if(!head->next)
        ListNode* cur=head;
        while(cur){
            if(!cur->next) return false;
            if(!cur->next->next) return false;
            cur = cur->next->next;
            head=head->next;
            if(cur==head) return true;
        }
        return false;
    }
};

排序链表

官方题解文字部分不错,但代码不太好懂,
题解链接
要再回顾。加上自顶向下的解法
这个是自底向上解法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==nullptr || head->next==nullptr) return head;
        ListNode* dummyHead = new ListNode(0, head);
        int length=0;
        ListNode* node=head;
        while(node!=nullptr){
            ++length;
            node=node->next;
        }
        //算长度
        //ListNode* pre=dummyHead, *cur=head;
        for(int subLength=1; subLength<length; subLength<<=1){
            //归并,从1开始,每次长度翻倍
            ListNode* pre=dummyHead, *cur=dummyHead->next;
            //这里,不能用head,head可能会排序换位,循环里面用dummy->next
            while(cur!=nullptr){
                //找归并的第一个链表
                ListNode* head1=cur;
                for(int i=1; i<subLength && cur->next!=nullptr; ++i){
                    cur=cur->next;
                }
                ListNode* head2=cur->next;
                cur->next=nullptr;
                cur=head2;
                for(int i=1; i<subLength && cur!=nullptr &&cur->next!=nullptr; ++i){
                    cur=cur->next;
                }
                //归并的第二个链表头
                ListNode* next=nullptr;
                if(cur!=nullptr){
                    next=cur->next;//记录归并完的链表后面的下一个位置
                    cur->next=nullptr;//已归并的链表断掉尾
                }
                //后面还有要归并的,用cur记录一下位置,下一轮while处理
                pre->next=merge(head1, head2);
                //pre赋给已经归并的链表的末尾
                while(pre->next != nullptr){
                    pre=pre->next;
                }
                cur=next;//cur更新到最新的头
            }           
        }
         return dummyHead->next;
    }

    ListNode* merge(ListNode* head1, ListNode* head2){
        ListNode* dummyHead=new ListNode(0);
        ListNode* temp=dummyHead, *temp1=head1, *temp2=head2;
        //不用head往后走,用temp1,temp2比较好
        //dummyHead固定头
        while(temp1 != nullptr && temp2 != nullptr){
            if(temp1->val <= temp2->val){
                temp->next=temp1;
                temp1=temp1->next;
                temp=temp->next;
            }
            else{
                temp->next=temp2;
                temp2=temp2->next;
                temp=temp->next;
            }
        }
        if(temp1 == nullptr){
            temp->next=temp2;
        }
        else if(temp2 == nullptr){
            temp->next=temp1;
        }
        return dummyHead->next;
    }
};

反转链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==nullptr || head->next==nullptr) return head;
        ListNode* pre=nullptr, *cur=head;
        ListNode* ans=new ListNode(0);
        while(cur!=nullptr){
            ans=cur;
            ListNode* temp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=temp;
        }
        return ans;//直接返回pre也可以
    }
};

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

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //一趟扫描实现就不能先扫描看长度
        //双指针一个指0,一个指n,然后两个同步往后移动
        ListNode* dummyHead=new ListNode(0,head);
        ListNode* first=dummyHead, *second=dummyHead;
        while(n>0){
            second=second->next;
            n--;
        }
        while(second->next!=nullptr){
            first=first->next;
            second=second->next;
        }
        //删除first后面的
        first->next=first->next->next;
        return dummyHead->next;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值