备战蓝桥杯第三节

下面是我做的一些题,用到了不同的方法和知识点

方法:快慢指针、双指针、栈、枚举等等

知识点:

stack()的常用方法:
头文件#include <stack>
定义:stack<typename> name
栈是一种后进先出的数据结构、在STL中可以通过top()来方位栈顶元素:
例如:
#include <bits/stdc++.h>
#include <stack>
using namespace std;
int main(){
    stack<int> st;//定义一个int型的stack,名字为st;
    for(int i = 0; i < 5; i++){
        st.push(i);
    }//给栈依次赋值为01234;
    cout<<st.top()<<endl;//输出top元素:4
    return 0;

stack常用函数:
stack.push(x);//放入元素x
stack.top();//返回栈顶元素
stack.pop();//弹出栈顶元素
stack.empty();//检查stack是否为空,是则返回true,反之,则False
stack.size();//返回大小
stack 用来模拟实现一些递归,防止程序对栈内存的限制而导致程序运行出错。

第一题:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 

1.枚举

class Solution {

public:

    ListNode* deleteDuplicates(ListNode* head) {

        if(!head){

            return head;

        }

        ListNode* end = head;//定义一个end指向head在的位置

        while(end->next)//保证end有下一位,直到删除所用重复元素,

        {

            //判断当前end的值和end下一个节点的值,是否相同,如果相同就删除当前的节点

            if(end->val==end->next->val){

                end->next = end->next->next;

            }

            else end = end->next;

        }

        return head;

    }

};

//思路:定义一个指针,它不断前进,如果它在前进的情况下,当前值等于下一位的值,那么就把当前的下一位指向下一位的后一位,这样就删除了相同的元素,但是这样只能一次性删除一个。最后在指针的不断前进下,最后删除了所用相同元素。

2.双指针:

class Solution {

public:

    ListNode* deleteDuplicates(ListNode* head) {

        if(!head){

            return head;

        }

        ListNode* end = head,*end1 = head->next;;//定义一个end指向head在的位置

        while(end1)

        {

             if(end->val != end1->val){

                end->next = end1;

                 end = end->next;

             }

             end1 = end1->next;

        }

        end->next = end1;

        return head;

    }

};

//思路:定义两个指针,一个在前,一个在后,它们不断以相同的速度前进。我们的解题思路就是把一片一样的元素弄成一个,保证前一个和后一个的值一直是不同的,就解决了重复的问题。那么我们怎么保证一片重复元素是一个呢?(滑动窗口)假设后一个已经移动到了一片重复元素,前一个在元素相同的情况下,不移动后一个元素,只移动前一个,直到前一个指向不同元素,那么就把后一个的下一位指向前一个就可以了。,这样我们就在前指针和后指针不断前进的条件下,删除相同元素了。最后前指针一定会变成空指针,因此我们要把后指针的下一位指向前指针(null)。

第二题: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* end = nullptr;//定义一个末尾节点end
        ListNode*  l= head;//定义一个l,用于边遍历数组
        while(l){//保证star存在的前提下,向前移动一位
            //把star指向的下一位和值赋值到我们新建的链表上:
            ListNode*  r = l->next;//r指向l的下一位
            l->next = end;//把l的下一位指向后面新建的end
            //移动end和l,使得循环不断前进,形成反转链表;
            end = l;
            l = r;
            
        }
        return end;
        //思路:在原来的链表的第一位的左边建立一个链表节点end(值为null),在定义一个指针为l指向头结点,在循环中保证l存在的前提下,然后定义一个r指针为l的下一位,使得l的下一位指向我们建立的end指针,用于反转指针,最后根据循环移动end、l、r(r只有满足循环才会继续移动),这样我们就得到了一个反转链表;最后end指向原来链表的最后一个,r和l为空指针。因此返回end就是反转链表的头结点了;
    }
};
//形象表达:原链表:12345(1-》2-》3-》4-》5-》null); 改变它们的指向方式,在最左边建立一个null: null,12345null;  null1,2345null;  null12,345null;  null123,45null;  null1234,5null;  null12345,null;现在是5-》4-》3-》2-》1-》null
 

第三题:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 

1.常规方法:

class Solution {
public:
    int getLength(ListNode* head) {//得到链表的长度
        int length = 0;
        while (head) {
            ++length;
            head = head->next;
        }
        return length;
    }

    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);//在head指针前面定义一个指针,防止在删除第一个链表时的特殊情况
        int length = getLength(head);
        ListNode* cur = dummy;//定义一个指针cur遍历要删除的链表的前一个
        for (int i = 1; i < length - n + 1; ++i) {
            cur = cur->next;
        }//从cur开始、遍历到要删除的链表的前一个
        cur->next = cur->next->next;//删除链表
        ListNode* ans = dummy->next;//定义一个ans指针指向dummy现在的下一位,如果删除的是第一位则dummy的下一位指向的是第二位,反之则是head。
        delete dummy;//删除定义的dummy
        return ans;
    }
};

//思路:遍历一遍链表,得到链表的个数length,然后遍历到要删除元素的前一位,把它的的下一位指向下一位的下一位,但是为了防止删除头结点的特殊情况,我们在头结点前面定义一个dummy,这样以dummy开始遍历,就可以把删除头结点和其他节点看成一种情况了,最后删除dummy,返回ans;


//核心片段:
for (int i = 1; i < length - n + 1; ++i) {
            cur = cur->next;
        }//从cur开始、遍历到要删除的链表的前一个
        cur->next = cur->next->next;//删除链表

2.栈
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);//在head前定义一个节点dummy
        stack<ListNode*> stk;//定义一个栈
        ListNode* cur = dummy;//定义一个指针cur指向dummy,cur用于遍历
        while (cur) {
            stk.push(cur);
            cur = cur->next;
        }//把链表的指针信息放入栈中,从cur指针开始
        for (int i = 0; i < n; ++i) {
            stk.pop();
        }//根据先进后出的原则,弹出我们要删除的元素包含它后面的元素,此时top为删除元素的前一位
        ListNode* prev = stk.top();//定义一个指针prev指向现在top的指针信息
        prev->next = prev->next->next;//删除我们要删除的节点
        ListNode* ans = dummy->next;//定义ans指针由于返回最终结果
        delete dummy;
        return ans;//删除之前定义的dummy,返回结果
    }
};

//思路:定义一个栈由于记录链表每个节点的地址,由于我们是删除倒数第几个元素,结合栈的性质就可以很容易的得到要删除元素的前一个的地址,最后删除链表元素就可以了;

//核心片段:
for (int i = 0; i < n; ++i) {
            stk.pop();
        }//根据先进后出的原则,弹出我们要删除的元素包含它后面的元素,此时top为删除元素的前一位
        ListNode* prev = stk.top();//定义一个指针prev指向现在top的指针信息
        prev->next = prev->next->next;//删除我们要删除的节点

3.快慢指针

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);
        ListNode* first = head;
        ListNode* second = dummy;
        for (int i = 0; i < n; ++i) {
            first = first->next;
        }
        while (first) {
            first = first->next;
            second = second->next;
        }
        second->next = second->next->next;
        ListNode* ans = dummy->next;
        delete dummy;
        return ans;
    }
};
//利用快慢指针:删除倒数第n个元素,由于快指针比慢指针快n,因此当first与second都以一步步的速度前进时,first到达了null时,second的就会到达删除元素的前一位,然后删除元素就可以了

//核心片段:
ffor (int i = 0; i < n; ++i) {
            first = first->next;
        }
        while (first) {
            first = first->next;
            second = second->next;
        }
        second->next = second->next->next;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

years_GG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值