算法训练(1)-数字统计-两个数组的交集-点击消除

本文介绍了三个编程问题:通过循环和数据拆分计算数字统计,利用哈希和数组下标映射找出两个数组的交集,以及使用栈实现点击消除。每个问题都涉及到时间复杂度和空间复杂度分析。
摘要由CSDN通过智能技术生成

第一题:数字统计

在这里插入图片描述
拿到这个题目首先的思路就是输入L和R作为左右边界,然后通过for循环遍历[L, R]之间的值,并且将每一个值都拷贝一份进行数据拆分操作
如何数据拆分呢?数据拆分就是两步:1)用10取模,取模能取到个位数;2)除10,能干掉个位数。
代码示例:

#include <iostream>
using namespace std;

int main()
{
    int L, R;
    cin >> L >> R;

    int ret = 0;
    // 遍历范围[L, R]的所有整数
    for(int i = L; i <= R; ++i)
    {
        int tmp = i;
        // 对每个数做拆分
        while(tmp)
        {
            if(tmp % 10 == 2) ret++;
            tmp /= 10;
        }
    }
    cout << ret;
}

第二题:两个数组的交集

在这里插入图片描述
从一个数组中的元素是否存在于另一个数组中这样的一一映射问题我们首先要想到的就是哈希

首先先将nums1放入到哈希中,再遍历nums2中的每一个元素,如果这个元素在哈希中存在,则我们将这个元素插入到要返回的数组ret中。

细节问题:1)我们是要用unordered_map呢?还是数组的下标映射呢?仔细审题,由于我们的数组长度是0~1000不是特别大,我们就用数组下标映射。2)万一我们的nums2中有两个元素在哈希中都能找到怎么办呢?很简单,只要想到第一个元素映射之后,哈希表就将这个元素“删掉”就可以了!这里的删掉对于哈希而言只是一种标记(如有true变为false,由1变为0)

#include <vector>
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> result;
        bool hash[1010] = {0};
        // 将nums1的元素添加到hash中
        for(auto& ch1 : nums1)
        {
            hash[ch1] = true;
        }
        // 遍历nums2,和hash比较
        for(auto& ch2 : nums2)
        {
            // ch2在hash中存在
            if(hash[ch2] == true)
            {
                result.push_back(ch2);
                hash[ch2] = false;
            }
        }
        return result;
    }
};

时间空间复杂度分析

时间复杂度:O(N)。因为要遍历数组nums1和nums2,所以时间复杂度为O(N)
空间复杂度:O(N)。因为要建立hash将nums1对应下标中的元素置为true,所以空间复杂度为O(N)

第三题:点击消除

在这里插入图片描述
这题的思想类似于我们之前做的括号匹配。
通过栈的后进先出,如果我在数组遍历的过程中遇到和栈顶元素相同的就出栈,因为相同时,栈顶元素和数组里的元素是相邻的,这就达到了连续相同的两个字符消除的目的。
以下是具体实现步骤:
在这里插入图片描述

在这里插入图片描述
注意细节:最后依次从栈顶取出元素插入到新的string容器中,别忘了还要逆序哦!

#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
using namespace std;

int main() {
    stack<char> st;
    string str;
    cin >> str;
    
    int begin = 0;
    while(str[begin] != '\0')
    {
    	// 刚开始栈为空,插入str的第一个元素
        if(st.empty())
        {
            st.push(str[begin++]);
            // begin++之后一定要判断一下,判断begin是否到了str的末尾
            if(str[begin] == '\0') break;
        }
		// 取栈顶元素去和str元素比较
        char tmp = st.top();
        if(str[begin] != tmp) // 不相等就插入
        {
            st.push(str[begin++]);
            if(str[begin] == '\0') break;
        }
        else // 相等就出栈
        {
            st.pop();
            begin++;
            if(str[begin] == '\0') break;
        }
    }
    // 栈为空
    if(st.empty()) cout << 0;
    // 栈不为空
    string ret;
    while(!st.empty())
    {
        char top = st.top();
        ret.push_back(top);
        st.pop();
    }
    reverse(ret.begin(), ret.end());
    cout << ret;
}

我们也可以不关系string容器如何遍历,直接运用范围for(底层封装了迭代器),我们不需要控制循环结束条件,因为STL已经帮我们封装好了。

#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
using namespace std;

int main() {
    stack<char> st;
    string str;
    cin >> str;
    
    for(auto& ch : str)
    {
        // 刚开始栈为空,插入str的第一个元素
        if(st.empty()) 
        {
            st.push(ch);
            continue;
        }

        // 取栈顶元素去和str元素比较
        char tmp = st.top();
        // 不相等就插入
        if(ch != tmp) st.push(ch);
        // 相等就出栈
        else st.pop();
    }

    // 栈为空
    if(st.empty()) cout << 0;
    // 栈不为空
    string ret;
    while(!st.empty())
    {
        char top = st.top();
        ret.push_back(top);
        st.pop();
    }
    reverse(ret.begin(), ret.end());
    cout << ret;
}

当然这题还有第二种解法:运用数组去模拟栈,这样最后就不用逆序了

int main() {
    // 数组st模拟栈
    string str, st;
    cin >> str;
    for(auto& ch : str)
    {
        if(st.size() != 0 && st.back() == ch) st.pop_back();
        else st += ch;
    }

    cout << (st.size() == 0 ? "0" : st) << endl;
}

时间空间复杂度分析

时间复杂度:O(N)。因为要遍历数组,所以时间复杂度为O(N)
空间复杂度:O(N)。因为要建立栈存储数组中的元素,所以空间复杂度为O(N)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值