【2022.12.23每天四个简单题之简单题大智慧系列12】( 反转链表 ,两个链表的第一个公共结点, 用两个栈实现队列,和为S的两个数字)

反转链表

定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。
数据范围
链表长度 [0,30]。

样例
输入: 1->2->3->4->5->NULL

输出: 5->4->3->2->1->NULL
我们利用双指针,一个指针指向第一个,另一个指向后一个,然后让后面的指向前面的(本来是前面的指向后面的),之后让两个指针都向后移一位,然后重复上述行为即可
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(!head||!head->next){
            return head;
        }
        auto p=head,q=head->next;
        while(q){
            auto o=q->next;
            q->next=p;
            p=q,q=o;
        }
        head->next=NULL;
        return p;
    }
};

两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

当不存在公共节点时,返回空节点。

数据范围
链表长度 [1,2000]。
保证两个链表不完全相同,即两链表的头结点不相同。

样例
给出两个链表如下所示:
在这里插入图片描述

输出第一个公共节点c1

如果有公共结点肯定是在后面重叠,且后面部分都是共同的。
方法1:先计算出两个链表的长度,可以让比较长的先走两个链表长度之差的步数,两个再一起走。
方法2:不同部分为a, 和b,公共部分为c;a + c + b = b + c + a;让两个一起走,a走到头就转向b, b走到头转向a,则在公共部分相遇。

设A链表的非公共部分长度为LA,B链表的非公共部分长度为LB,公共部分长度为C。

A链表总长度为LA + C,B链表总长度为LB + C。
当指针按照题解方式走下去,p1第二次走到公共节点的时候,走过的长度为LA + C + LB,p2第二次走到公共节点的时候,走过的长度为LB + C + LA。p1 p2走过的长度相等,p1 p2 相遇。
所以,当p1 p2 相遇(相等)的时候,指向的节点就是公共节点。
在这里插入图片描述

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p1 = headA;
        ListNode *p2 = headB;

        while (p1 != p2) {
            if(p1 != NULL)//p1没有走到结尾
                p1 = p1->next;//p1指向下一个节点
            else//p1走到结尾
                p1 = headB;//p1指向另一个链表头
            if(p2 != NULL)//p2没有走到结尾
                p2 = p2->next;//p2指向下一个节点
            else  //p2走到结尾 
                p2 = headA;//p2指向另一个链表头
        }
        return p1;
    }
};

用两个栈实现队列

请用栈实现一个队列,支持如下四种操作:

push(x) – 将元素x插到队尾;
pop() – 将队首的元素弹出,并返回该元素;
peek() – 返回队首元素;
empty() – 返回队列是否为空;
注意:

你只能使用栈的标准操作:push to top,peek/pop from top, size 和 is empty;
如果你选择的编程语言没有栈的标准库,你可以使用list或者deque等模拟栈的操作;
输入数据保证合法,例如,在队列为空时,不会进行pop或者peek等操作;
数据范围
每组数据操作命令数量 [0,100]。

样例
MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek(); // returns 1
queue.pop(); // returns 1
queue.empty(); // returns false

我们可以用两个栈来实现,一个栈来缓冲,当我们插入时插入至第一个栈,弹出时先将剩余元素放置缓冲栈中,就可以将第一个元素弹出来了

我们用两个栈来做,一个主栈,用来存储数据;一个辅助栈,用来当缓存。

push(x),我们直接将x插入主栈中即可。
pop(),此时我们需要弹出最先进入栈的元素,也就是栈底元素。我们可以先将所有元素从主栈中弹出,压入辅助栈中。则辅助栈的栈顶元素就是我们要弹出的元素,将其弹出即可。然后再将辅助栈中的元素全部弹出,压入主栈中。
peek(),可以用和pop()操作类似的方式,得到最先压入栈的元素。
empty(),直接判断主栈是否为空即可。
时间复杂度分析
push():O(1);
pop(): 每次需要将主栈元素全部弹出,再压入,所以需要 O(n) 的时间;
peek():类似于pop(),需要 O(n) 的时间;
empty():O(1);

class MyQueue {
public:
    /** Initialize your data structure here. */
    stack<int>s1,s2;
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        s1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        while(s1.size()>1)s2.push(s1.top()),s1.pop();
        int t=s1.top();
        s1.pop();
        while(s2.size())s1.push(s2.top()),s2.pop();
        return t;
    }
    
    /** Get the front element. */
    int peek() {
        while(s1.size()>1)s2.push(s1.top()),s1.pop();
        int t=s1.top();
        while(s2.size())s1.push(s2.top()),s2.pop();
        return t;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return s1.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * bool param_4 = obj.empty();
 */

和为S的两个数字

输入一个数组和一个数字 s,在数组中查找两个数,使得它们的和正好是 s。

如果有多对数字的和等于 s,输出任意一对即可。

你可以认为每组输入中都至少含有一组满足条件的输出。

数据范围
数组长度 [1,1002]。

样例
输入: [1,2,3,4] , sum=7

输出: [3,4]

我们可以用哈希表来做,扫描到每个数时我们看一下这个数前面有没有可以和它一起和为s的数,看下一个的时候将先看的那个放入哈希表里面便于查找

class Solution {
public:
    vector<int> findNumbersWithSum(vector<int>& nums, int target) {
        unordered_set<int>s;
        for(auto x:nums){
            if(s.count(target-x))return {x,target-x};//判断存不存在用count函数
            s.insert(x);
        }
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想进步的22级本科生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值