【C++练习】leetcode刷题训练(中等难度)

news2024/11/19 2:21:30

【C++练习】leetcode刷题训练(中等难度)

  • 1.数组中的第K个最大元素
  • 2.前K个高频单词
  • 3.单词识别
  • 4.字符串相乘
  • 5.只出现1次的数字Ⅱ
  • 6.栈的弹出压入序列

1.数组中的第K个最大元素

在这里插入图片描述

解题思路
1.典型的TOP-K问题(用堆来解决)
2.要求实现时间复杂度为O(N),而我们的优先级队列的时间复杂度为O(n*logN)差不多
3.正常应该是首先从序列中拿出k个元素放入队列中,然后将剩下的序列与堆顶比较,当大于堆顶就删除堆顶元素,将该元素入队列。但这里可以直接将全部数据都放入优先级队列中,然后直接获取第K大的元素, 因为放入优先级队列后自动排序了。默认是小堆,从小到大。
4.注意题目只要求获取第K大个元素,而不是获取前K个元素直接pop k-1次即可。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        
       priority_queue<int> pq(nums.begin(),nums.end());
       
       while(--k)
       {
           pq.pop();
       }
       return pq.top();
    }
};

2.前K个高频单词

在这里插入图片描述

解题思路①:用sort排序
1.统计出现的次数我们可以利用map来统计。
2.再对根据出现的次数进行排序。选出前K个单词
3.不过这里的问题是当次数相同时,如何按照字典序再排序?
4.我们想map统计完后,单词的顺序是排序好的,每个单词的个数可能相同也可能不同。但如果当单词个数不相同时,对出现的个数排序就可以完成任务,因为没有出现相同的频率,但如果单词个数出现相同时,排序完后,如果它们的相对顺序没有被改变,那么也可以完成任务,因为相对顺序就是按照字典序排的,所以这个排序得要求是稳定的。
5.还有如何进行比较排序呢?我们需要使用仿函数来修改比较规则。根据次数进行比较,并且进行降序排序。

class Solution {
public:

  //要求先按照频率由高到低排序也就是出现的次数,如何统计出现的次数呢?用map统计次数


    struct Greater//仿函数重构比较方式,利用出现的次数进行比较,并且降序排,大的在前面,小的在后面
    {
    bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
    {
          return kv1.second>kv2.second;
    }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countmap;
        for(auto &e:words)
        {
            countmap[e]++;
        }
        //已经统计完次数了接下来就要按照出现的频率来排序,不过map其实已经按照字典序的排序方法将数据排好
        //只要要按照频率排序后稳定性不变,相对顺序不变就可以了,但sort稳定性不行
        //注意sort无法对map排序,所以我们可以将map里的数据放进vector里

        vector<pair<string,int>> v; 
        v(countmap.begin(),countmap.end());
        stable_sort(v.begin(),v.end(),Greater());
        //stable_sort排序比较稳定
        vector<string> vs;
       for(int i=0;i<k;i++)
       {
         vs.push_back(v[i].first);//选取前k个单词
       }
      return vs;
    }
};

解决思路②:用priority_queue排序
1.经典的TOP-K问题,利用优先级队列筛选出前K个
2.首先利用map计算出各个单词出现的次数。
3.这里我们要重写一个比较器:因为我们想要用priority_queue来比较出现最多的前K个单次,但priority_queue里面存的是单词和它对应的值对键也就是次数,无法正常比较,所以我们要改写priority_queue的比较规则,通过仿函数可以将比较规则改变成自己想要的:根据单词出现的次数进行比较,当次数相同时,根据字典序进行比较。
4.从map中放入k个元素到priority_queue,当priority_queue的大小超过K时,就要pop掉一个(pop掉的是K+1中最小的那一个,不影响K结果),然后再push进入一个。知道map中元素放光。
5.这时,优先级队列中存的就是出现次数最多的前K个单词和值对键了(将priority_queue中的单词存到vector<.string>中)。但要注意优先级队列默认是小堆。是从小到大的。所以最后我们还需要逆转一下。

class Solution {
public:

  //要求先按照频率由高到低排序也就是出现的次数,如何统计出现的次数呢?用map统计次数


    struct Greater//仿函数重构比较方式:比较器
    {

    bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
    {
          return kv1.second>kv2.second||(kv1.second==kv2.second&&kv1.first<kv2.first);
          //大于就是降序前面大,后面小
    }

    };

    //典型的TOP-K问题
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countmap;
        priority_queue<pair<string,int>,vector<pair<string,int>>,Greater> pq;
        for(auto &e:words)
        {
            countmap[e]++;
        }
        //已经统计完次数了接下来就要按照出现的频率来排序,不过map其实已经按照字典序的排序方法将数据排好
        
        //利用优先级队列,将map中先入k个元素,当超过k个元素时,就删除一个,插入一个。等将全部将map元素插入栈里后,队列里的K个元素就是前K个
        int i=0;
        for(auto& e:countmap)
        {
            pq.push(e);
            i++;
            //先入K个元素
            if(i>k)
            {
                pq.pop();
                //当大于K个元素时,就pop掉堆顶的元素,反正是K+1中最小的pop掉没有影响
            }
        }
        vector<string> v;
        //队列不能使用迭代器访问遍历,只能pop出掉
        while(!pq.empty())
        {
            v.push_back(pq.top().first);
            pq.pop();
        }
        reverse(v.begin(),v.end());
        return v;
    }
};

3.单词识别

在这里插入图片描述

解题思路:其实本质就是上一题的解决思路,只不过多了一步。
1.首先我们需要将这句子中的单词全部分割出来。要注意输出流遇到空格和换行结束的特性,这里必须使用getline()获取一整行句子。
2.如何分割出单词呢?我们可以利用string的substr函数来切割字符串。当遇到空格或者句号,就将上次出现的位置(默认第一次是0)到这次空格或句号之前的位置上的字符剪切下来。(还有这里要注意,大小写是不区分的,这就要求我们在遍历句子时,一开始可以将遍历到的字符全部统一成小写字母),这里可以直接放入map里,一遍分割单词,一旦单词被分割出来就放入map里计数,也可以放入一个字符串数组里面,当全部单词被分割,再放入map里计数。
3.放入map里计数后,接下来的操作就和上面是一样的了,可以使用sort来排序,也可以使用priority_queue来比较,但都需要重写一个比较器,因为pair<string,int>这个值对键无法正常比较,需要我们根据需求改写比较规则。

#include <iostream>
using namespace std;
#include <vector>
#include<string>
#include<map>
#include<algorithm>
//写一个仿函数,用来控制排序的比较规则
struct Greater
{
	bool operator()(pair<string, int>& kv1, pair<string, int>& kv2)
	{
		return kv1.second > kv2.second||(kv1.second==kv2.second&&kv1.first<kv2.first);
	}
};
int main()
{
	//首先第一步将字母分割出来,放入数组里
	string ch;
	vector<string> v;
	map<string, int>countmap;
	while (getline(cin, ch))
	{

		int i = 0;
		int pos = 0;
		for (i = 0; i < ch.size(); i++)
		{
			ch[i]=tolower(ch[i]);//要求不区分大小写, 那我们就统一都弄成小写。
			
			if (ch[i] == ' '||ch[i]=='.')
			{
				string tmp = ch.substr(pos, i-pos);//这里要注意很容易出错!
				pos = i + 1;
				v.push_back(tmp);
				//也可以一遍分割一般放入map里计数
			}
		}
		

     }
	//第二利用map计算出现的次数

	for (auto& e :v)
	{
		countmap[e]++;
	}
	//map无法使用sort排序放进vector中排序
	vector<pair<string, int>> copy(countmap.begin(), countmap.end());

	sort(copy.begin(), copy.end(), Greater());

	for (auto& e : copy)
	{
		cout << e.first << ":" << e.second << endl;
	}
	
}

4.字符串相乘

在这里插入图片描述

解题思路:本质是字符串相加的进阶
1.两个数相乘,我们通常喜欢用竖式乘法,所以这里我们只要模拟竖式乘法就可以,从右到左遍历乘数,然后每个乘数都乘上被乘数得到结果,最后再将这些结果相加就是最终的结果。
2.要注意的是当乘数不是最低阶时,后面要补成0的。
3.还有我通常喜欢让长度长的数放在上面,长度短的数放在下面。也就是让长度短的数字的每个数乘长度长的数字。也就是在短的数字里面遍历。但一开始我们不知道哪个数字谁长度长,谁长度短,所以需要比较一下。反正我就是想让在短的数字里遍历。这样符合我的习惯。这样就转化为n个单词相加了。
4.这里有很多细节要注意,当两个数其中一个为0那么最终结果肯定为0。
5.怎么控制不是低价的数后面要自动补0呢?我们没有必要在阶数上搞,我们可以直接在最后的结果上直接加0,阶数为十位那就加一个0,阶数为百位,就加两个0。

在这里插入图片描述>

class Solution {
public:


    string addStrings(string num1, string num2) {
     int end1=num1.size()-1,end2=num2.size()-1;
     int carry=0;
     string strRet;
     while(end1>=0||end2>=0)
     {
        int val1=end1>=0?(num1[end1]-'0'):0;
        int val2=end2>=0?(num2[end2]-'0'):0;

        int ret=val1+val2+carry;
        carry=ret/10;
        ret%=10;

       strRet+=ret+'0';
      
       --end1;
       --end2;
     }
     if(carry==1)
     {
         strRet+='1';
     }
     reverse(strRet.begin(),strRet.end());
     return strRet;
    }
    string multiply(string num1, string num2) {
       if((num1[0]-'0')==0||(num2[0]-'0')==0)//如果其中一个数为0,那么最后结果就为0
       return "0";   
       
      if(num1.size()<num2.size())//这里我相比较哪个数比较长,我想遍历长度短的数
       {
           swap(num1,num2);
       }
         
         string ans="0";
        for (int i = num2.size()-1; i >= 0; i--)//在长度短的数里遍历
        {
            string s;
            int ret2 = num2[i] - '0';
            int binary = 0;
            for (int j = num1.size()-1; j >= 0; j--)//每个数字都乘长度长的数
            {
                int ret1 = num1[j] - '0';
                s += ((ret1 * ret2) + binary) % 10 + '0';
                 binary = ((ret1 * ret2) + binary) / 10;//进位
            }
         if(binary>0)//特性情况,当两个个数相乘,最后如果不加上这句,最后答案就只是个位上的数,十位数上的数没有加上。因为只会进入循环一次,最后的进位没有加上去。
         {
             s+=binary+'0';
         }
            reverse(s.begin(), s.end());//最后要逆转回来
            int k = i;//最后可以依据在哪个位置加上几个0.
            while (k <num2.size() - 1)
            {
                s += '0';
                k++;
            }
            ans=addStrings(ans,s);//调用加法函数每次叠加即可。
        }
   
       return ans;
    
    }
};

5.只出现1次的数字Ⅱ

在这里插入图片描述

解题思路
1.只有一个数出现一次,其他的数字都出现三次。我们从二进制位的角度来思考:整数一共有32位。二进制表示只有1或0,将相同的数的同一个二进制数全部加起来后,这个数肯定是3的整数倍的(0或者3N),即可以整除3的。
2.而这时如果再加上这个只出现一次的数的该二进制上的数,当结果模3不等于0时,就说明这个二进制位置上的数是1!
3.我们就可以通过这样的方法来确定这个只出现一次的数的每个二进制位置上是不是1。
4.通过(n>>i)&1来获取第i个二进制位上数是几(&:只有两个1&1最后等于1,其他都为0)
5.通过ans|(1<<i)来将ans第i个二进制上变成1.

class Solution {
public:
    int singleNumber(vector<int>& nums) {
    
    
    int single=0;
    for(int i=0;i<32;i++)
    {
        int ret=0;
        //每次循环下下来要更新为0
        for(auto& e:nums)
        {
            ret+=(e>>i)&1;
            //获取nums中每个数的第i个二进制位上的数,然后全部相加起来
        }
            //因为三个相同的数,要么是全是0,要么全是1,相加起来要么是0,要么是3N,所以当只出现一次的数第i二进制位置是1时,
            //最后的结果模3就不为0,当只出现一次的第i位置是0时,最后结果模完还是0
         if(ret%3!=0)
            {
                //表明只出现一个数的第i位置是1
                single=single|(1<<i);
                //(1<<i)表示让第i位置上数字为1
            }
    }
    return single;
    }
};

6.栈的弹出压入序列

在这里插入图片描述

解题思路
1.给了入栈序列,和出栈序列,要求判断出栈序列是否合法。
2.那么我们可以模拟一下出栈,就是利用栈,根据出栈序列,来将元素入栈,比较一下,看最后是否能将栈里出空。
3.首先先入栈一个元素,然后和出栈序列中的第一个相比较,当不相同时,就继续入栈。
4.当入栈的元素和出栈序列相同时,那么就可以将栈顶元素删掉,并且对比下一个出栈序列。不过这里会存在着持续出栈的可能,就是当栈顶元素删除掉后,发现现在的栈顶元素与下一个出栈序列相同,那么就继续删除栈顶,再比较下一个出栈序列。这里会存在会将栈里元素出空,或者出栈序列与栈顶元素不相同,这时候就又要回去重写入栈。
5.也就是会存在两种情况:一种是持续出一种是不匹配。而持续出有可能会导致栈被出空,而出现这两种种情况都需要重新回去继续入栈。

 bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        
        int pushi=0,popi=0;
        stack<int> st;
        //当根据入栈元素没有了,就结束了。如果这时,根据正确的出栈顺序最后栈里是空的
        while(pushi<pushV.size())
        {
            //首先先入栈一个
           st.push(pushV[pushi++]);

           //然后与出栈顺序比较

           if(st.top()!=popV[popi])//如果不匹配就继续入
           {
             continue;
           }
           else//匹配可能会持续出
           {
                //因为可以能不一定只出一个可能持续出,所以要写一个循环
                //但前提是栈里不为空,要是栈里被持续出空了就不要再进行下去了,再回去入栈.也有可能出完一个后,下面一个不匹配了,也要回去继续入栈。
            while(!st.empty()&&st.top()==popV[popi])//持续出的要求就是top()要和出栈序列相同,并且栈不为空
            {
                st.pop();
                popi++;
            }

           }
        }
        return st.empty();
    }
    //根据出栈结果模拟入栈过程,如果最后入栈序列到头,出栈还未完成则就不正常
    //不匹配还不入了就说明结束了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/956004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【附安装包】Alias AutoStudio2023安装教程

软件下载 软件&#xff1a;AutoStudio版本&#xff1a;2023语言&#xff1a;英文大小&#xff1a;4.81G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu.c…

《Flink学习笔记》——第十一章 Flink Table API和 Flink SQL

Table API和SQL是最上层的API&#xff0c;在Flink中这两种API被集成在一起&#xff0c;SQL执行的对象也是Flink中的表&#xff08;Table&#xff09;&#xff0c;所以我们一般会认为它们是一体的。Flink是批流统一的处理框架&#xff0c;无论是批处理&#xff08;DataSet API&a…

2023年人工景点行业研究报告

第一章 行业概况 1.1 定义及分类 人工景点行业通常指的是设计和构建的为提供娱乐、教育或文化体验的景点。这些景点可能包括主题公园&#xff0c;博物馆&#xff0c;动物园&#xff0c;水族馆&#xff0c;科学中心&#xff0c;历史遗迹&#xff0c;艺术展览等。这个行业通常包…

rpm打包

文章目录 rpm打包 1. rpm打包步骤0&#xff09;安装打包工具rpm-build和rpmdevtools1&#xff09;创建初始化目录2&#xff09;准备打包内容3&#xff09;编写打包脚本 spec文件4&#xff09;打包5&#xff09;安装 rpm打包 1. rpm打包步骤 0&#xff09;安装打包工具rpm-buil…

python把txt变成list,并且写入xslx文件

需求&#xff1a; 1、把txt文件的内容变成list 2、然后写入excel中 txt文件内容 IP.txt 192.168.199.201,4C8G,200G 192.168.199.202,4C8G,200G 192.168.199.203,4C8G,200G 192.168.199.204,4C8G,200G 192.168.199.205,4C8G,200G192.168.199.206,4C8G,200G 192.168.199.207…

2023年7月京东笔记本电脑行业品牌销售排行榜(京东数据平台)

随着智能手机、平板电脑等移动互联设备的普及&#xff0c;人们对于个人电脑的依赖减轻&#xff0c;加之电脑的更换率较低&#xff0c;因此当前PC端消费市场整体出现疲态&#xff0c;笔记本电脑的出货量不断下降&#xff0c;今年7月份也同样呈现这一趋势。 根据鲸参谋电商数据分…

不使用 ERP有3个隐藏业务风险,一定要知道!

不少中小型企业出于种种原因&#xff0c;推迟了对ERP系统的投资。也许是因为没有一大笔钱购买软件&#xff1b;也许是听说实施项目可能需要几个月甚至几年的时间&#xff0c;而企业没有时间去做这种令人头疼的事情。 因此&#xff0c;中小企业并没有转向ERP系统&#xff0c;而…

运维Shell脚本小试牛刀(四): 多层嵌套if...elif...elif....else fi

运维Shell脚本小试牛刀(一) 运维Shell脚本小试牛刀(二) 运维Shell脚本小试牛刀(三)::$(cd $(dirname $0)&#xff1b; pwd)命令详解 运维Shell脚本小试牛刀(四): 多层嵌套if...elif...elif....else fi_蜗牛杨哥的博客-CSDN博客 一&#xff1a; if...elif...elif..else fi多层…

软件测试—测试用例的设计

软件测试—测试用例的设计 测试用例是什么&#xff1f; 首先&#xff0c;测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试系统提供的一组集合。这组集合包括&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 好的测试用例的特征 一个好的测试…

ChatGPT 总结数据分析的所有知识点

ChatGPT功能非常多,特别是对某个行业,某个方向,某个技术进行总结那是相当专业的。 如下图。 直接用一个指令便总结出来数据分析当中的所有知识点内容。 AIGC ChatGPT ,BI商业智能, 可视化Tableau, PowerBI, FineReport, 数据库Mysql Oracle, Office, Python ,ETL Ex…

【python爬虫案例】用python爬豆瓣读书TOP250排行榜!

文章目录 一、爬虫对象-豆瓣读书TOP250二、python爬虫代码讲解三、讲解视频四、完整源码 一、爬虫对象-豆瓣读书TOP250 您好&#xff0c;我是 马哥python说 &#xff0c;一名10年程序猿。 今天我们分享一期python爬虫案例讲解。爬取对象是&#xff0c;豆瓣读书TOP250排行榜数…

2023-08-31 LeetCode每日一题(一个图中连通三元组的最小度数)

2023-08-31每日一题 一、题目编号 1761. 一个图中连通三元组的最小度数二、题目链接 点击跳转到题目位置 三、题目描述 给你一个无向图&#xff0c;整数 n 表示图中节点的数目&#xff0c;edges 数组表示图中的边&#xff0c;其中 edges[i] [ui, vi] &#xff0c;表示 ui…

暴力递归转动态规划(三)

前两篇暴力递归转动态规划的文章中&#xff0c;都是通过从上到下的一种思路来解决的问题&#xff0c;这篇文章会通过数组从左向右遍历的方式&#xff0c;来将暴力递归转成动态规划。 题目 有两个等长的数组 w[] 和 v[]&#xff0c;w[i] 和 v[i] 分别表示 i 号物品的重量和价值…

全球十大安全好用的黄金交易app软件最新排名(综合评测)

随着金融市场的不断发展&#xff0c;黄金交易app软件日益成为投资者不可或缺的工具。然而&#xff0c;面对众多的黄金交易软件&#xff0c;投资者往往感到困惑和难以抉择。本文将根据最新排名&#xff0c;对全球十大安全好用的黄金交易软件进行综合评测&#xff0c;帮助投资者找…

记一次Zip Slip任意文件写漏洞 以及一些参考文章

记一次Zip Slip任意文件写漏洞以及参考文章们 记一次Zip Slip任意文件写漏洞漏洞复现漏洞原理分析扩展延申 参考文章一&#xff1a;Java之解压流&#xff08;ZipInputStream&#xff09;参考文章二&#xff1a;Zip Slip VulnerabilityExploitable Application FlowAre you Vuln…

13.10 语义分割 全卷积网络

语义分割是对图像的每个像素分类 全卷积网络采用卷积神经网络实现从图像像素到像素类别的转换&#xff0c;全卷积网络将中间层特征的高和宽转换回输入图像的尺寸&#xff08;引入转置卷积实现的&#xff09;。 最终的类别预测与输入图像在像素上一一对应。 全卷积网络模型模型…

day 31 面向对象 成员方法

class 类名称&#xff1a; 类的属类(定义在类中的变量&#xff0c;成员变量) 类的行为(定义在类中的函数&#xff0c;成员方法) # 设计一个类&#xff08;类比生活中&#xff1a;设计一张等级表&#xff09; class Student:name Nonegender Nonenatio…

农产品小程序商城搭建宝典

在当今的电子商务时代&#xff0c;农产品小程序商城已经成为了一种新型的电商模式&#xff0c;为许多农产品的生产和销售带来了新的机遇。但是&#xff0c;如何搭建一个功能完善、用户体验优秀的农产品小程序商城呢&#xff1f;下面&#xff0c;我们就来探讨一下。 首先&#x…

抖音电商店铺运营教程,新手开店常见问题解答,醒醒团队分享

我是王路飞。 做抖音小店不可避免会遇到一些问题&#xff0c;尤其是新手&#xff0c;之前没接触过电商&#xff0c;更别说在抖音做电商开店了。 以至于很多新手在抖音开的店铺&#xff0c;类型不太对&#xff0c;类目不太对&#xff0c;不清楚怎么操作和运营&#xff0c;哪哪…

Redis一主一从Docker方式部署通过keepalived和 sentinel哨兵模式实现高可用

有两台服务器一台是主&#xff0c;master : 172.24.69.180 另外一台是从&#xff0c; slave :172.24.69.181 vip 地址&#xff1a; 172.24.69.185 1、关闭防火墙 两台服务器都关闭防火墙 systemctl disable --now firewalld firewall-cmd --state关闭SELinux setenforce 0 …