【c++5道练习题】①

目录

一、有限制的累加

二、计算日期到天数转换

三、仅仅反转字母

[四、 字符串的第一个唯一字符](#四、 字符串的第一个唯一字符)

五、字符串最后一个单词的长度


一、有限制的累加

题述:

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)

题中已给:

cpp 复制代码
class Solution
{
public:
	int Sum_Solution(int n){
	}
};

知识点考察:

类的构造 函数+ static修饰

先给代码再说思路:

代码如下:

cpp 复制代码
#include<iostream>
using namespace std;

class Sum
{
public:
	Sum()//构造函数
	{
		_sum += _i;
		++_i;
	}

	static void Init()
	{//静态成员函数可以访问静态成员变量
		_i = 1;
		_sum = 0;
	}

	static int GetSum()//静态成员函数可访问静态成员变量
	{
		return _sum;
	}
private:
	static int _i;//静态成员变量类内声明
	static int _sum;
};
int Sum::_i = 1;//静态成员变量类外定义(定义的同时初始化)
int Sum::_sum = 0;

class Solution
{
public:
	int Sum_Solution(int n)
	{
		Sum::Init();//每调用一次Sum_Solution函数都要初始化一次,不然会一直累加
		Sum* p = new Sum[n];//创建的同时,会调用n次构造函数
		//Sum a[n];//c99下才支持的变长数组

		return Sum::GetSum();//静态成员函数可通过类名直接访问
	}
};

int main()
{
	Solution st;//实例化一个对象
	cout << st.Sum_Solution(5) << endl;//累加
	cout << st.Sum_Solution(5) << endl;
    
	system("pause");
	return 0;
}

思路:

自定义类型 都要调用构造函数 初始化,比如Date a[10] -》10个对象就要调用10次构造函数

那么n个对象就会调用n次构造函数,就像一个变相的循环

问题:

为什么要用GetSum函数?

因为成员变量_i和_sum都是private权限下的,故在类外无法直接访问, 所以用GetSum进行返回
为什么要用static修饰?

因为static是属于类的,每个对象都可以修改静态变量,那就可以实现一个累加效果,那用全局变量不可以吗,当然可用,但是c++中不推荐用全局变量,因为c++强调封装的意义,如果是全局变量谁都可以修改了。

成员函数用static修饰是因为

①、static成员函数才可访问成员变量

②、静态成员函数可通过类名加::的方式直接访问

成员变量用static修饰是因为

①、所有对象调用时都会对同一个static变量上运算
要特别注意一个问题:

求一次累加和 ,都要初始化一次 ,因为OJ 上有多个测试用例 ,需要多次测试的,你在自己编译器下可能就运行一次就跑出来了,但OJ上还是不通过,对于本题,这可能就因为连续累加,每调用一次Sum_Solution 函数都在之前基础上累加,为了避免这个问题,我们再每一次调用Sum_Solution 函数时都初始化一次(Init函数)。

二、计算日期到天数转换

题述:

根据输入的日期(某年某月某日),计算是这一年的第几天。

输入描述:

输入三行,分别是年、月、日

输出描述:

返回计算后的第几天

输入:

2012

12

31

输出:

366

思路:

①、 创建一个日期类 ,并写一个运算符相减的重载 ,用这个日期减去本年的1月1号即可,但是对于这道题复杂化

②、 从1月累加 到本月的前一月,计算天数,时间复杂度:O(1) ,这个方法简单,本题采用此方法

代码如下:

cpp 复制代码
#include<iostream>
using namespace std;

int main()
{
	static int monthDays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int year, month, day;
	//这样可不断接收输入,直到按ctrl+z就结束
	while (cin >> year >> month >> day)
	{
		int n = 0;
		//从1月累加到month的前一月的天数
		for (int i = 1; i < month; i++)
		{
			n += monthDays[i];
		}
		n += day;
		//如果是闰年,且>2月的前提下
		if (month > 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
			n += 1;
		cout << n << endl;
	}

	return 0;
}

注意:

一定要加个while ,因为OJ 上有多个测试用例 ,不加while的话一个测试用例是能过,但是OJ上会连续输入,那OJ上也要手动按Ctrl+z 结束吗?不是,是OJ把测试用例写入文件 中了,然后运行时读文件,读完给后台发个信号就完成了。

三、仅仅反转字母

**题述:**给定一个字符串 s ,返回"反转后的"字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。

示例1:

输入:"ab-cd"

输出:"dc-ba"

示例2:

输入:"a-bc-dEf-ghIj"

输出:"j-Ih-jfE-dcba"

题中已给:

cpp 复制代码
class Solution{
public:
	string reverseOnlyLetters(string s) {

	}
};

思路:

遍历方法用下标访问 方便,不采用迭代器遍历字符串。

本质思路类似于快速排序 实现的单趟排序的左右指针法

仅仅交换字母,那就定义两个下标begin=0,end=字符串大小-1begin从左向右走,end从右向左走 ,两者直到找到对应的值为字母才会停下并交换,那整个大前提 就是begin<end才会继续,在begin和end找的过程中也要要求begin<end,不然若字符串全不是字母,begin会一直走,然后越界。

cpp 复制代码
class Solution{
public:
	//判断一个字符是不是字母
	bool Ischar(char ch)
	{
		if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	//仅仅交换字母
	string reverseOnlyLetters(string s) {
		int begin = 0;
		int end = s.size() - 1;//算出s的大小,求出最后一个数的下标
		while (begin < end)//大前提是begin < end循环才继续
		{
			while (begin < end && Ischar(s[begin]) == false)
			{//在走的过程中begin < end才能继续往下走,直到找到s[begin]是字母为止
				begin++;
			}
			while (begin < end && Ischar(s[end]) == false)
			{//在走的过程中begin < end才能继续往下走,直到找到s[end]是字母为止
				end--;
			}
			swap(s[begin], s[end]);//c++自动提供swap交换函数
			//交换完后begin还要++,end还要--
			begin++;
			end--;
		}
		return s;//返回字符串
	}
};

四、 字符串的第一个唯一字符

题述:

给定一个字符串,找到他的第一个不重复的字符,并返回它的索引。若不存在,则返回-1.

案例:

s = "leetcode"

返回 0

s = "loveleetcode"

返回 2

要求:

时间复杂度:O(N)

空间复杂度:O(1)

注意事项:

您可假定该字符串只包含小写字母

题中已给:

cpp 复制代码
class Solution {
public:
	int firstUniqChar(string s) {
    }
};

思路:

利用计数排序 的思路**,计数排序** 的本质就是哈希, 若用暴力求解法时间复杂度:O(N*N)

**和计数排序思路一样,**不会计数排序就看我写的八大排序的文章

cpp 复制代码
class Solution {
public:
	int firstUniqChar(string s) {
		//使用映射的方式统计次数
		int count[26] = { 0 };//26个小写字母
		for (auto ch : s)
		{//范围for遍历s
			count[ch - 'a']++;//'a'-'a'就变为0
		}
		for (size_t i = 0; i < s.size(); ++i)
		{
			if (count[s[i] - 'a'] == 1)
				return i;//出现一次则返回对应索引
		}
		return -1;//没有出现一次的则返回-1
	}
};

五、字符串最后一个单词的长度

题述:

计算字符串最后一个单词的长度,单词以空格隔开

输入描述:

一行字符串,非空,长度<5000

输出描述:

整数N,最后一个单词的长度

输入:

hello world

输出:

5

思路:

因为每个单词都以空格分隔 ,求长度简单,但怎么找最后一个单词,找最后一个空格 即可,那就可用到rfind() ,若找到对应字符返回其下标,若没找到返回**-1** ,它会从后往前找,找到第一次的即可。

那**一个单词也没有空格怎么办?**rfind()没找到会返回-1,而代码中s.size() - 1 - pos,pos=-1,相当于直接求出长度,所以无需格外考虑

典型的错误代码:

cpp 复制代码
#include<iostream>
using namespace std;

int main()
{
	string s;
	cin >> s;//输入字符串

	//从字符串后面往前找第一次出现的' ',并返回其下标给pos
	size_t pos = s.rfind(' ');
	//利用下标计算最后一个单词的长度
	cout << s.size() - 1 - pos << endl;

	return 0;
}

注意:

当输入的有空格、制表符、换行符时cin就不读了 和scanf一样,但本题以空格为分隔,故用getline才行,getline只有遇到换行才结束

getline的使用说明如下:

正确代码:

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

int main()
{
	string s;
	//cin >> s;//遇到空格、制表符、换行就结束了
	
	getline(cin, s);//遇到换行才结束

	//从字符串后面往前找第一次出现的' ',并返回其下标给pos
	size_t pos = s.rfind(' ');
	//利用下标计算最后一个单词的长度
	cout << s.size() - 1 - pos << endl;

	return 0;
}
相关推荐
刚入门的大一新生9 分钟前
C++初阶-string类的模拟实现1
开发语言·c++
LabVIEW开发20 分钟前
LabVIEW中算法开发的系统化解决方案与优化
算法·labview
梁下轻语的秋缘24 分钟前
每日c/c++题 备战蓝桥杯(洛谷P1115 最大子段和)
c语言·c++·蓝桥杯
wen__xvn26 分钟前
每日一题洛谷P8662 [蓝桥杯 2018 省 AB] 全球变暖c++
c++·职场和发展·蓝桥杯
chenyuhao202426 分钟前
链表面试题7之相交链表
数据结构·算法·链表·面试·c#
Pluchon38 分钟前
硅基计划2.0 学习总结 壹 Java初阶
java·开发语言·学习·算法
筏.k1 小时前
智能指针入门:深入理解 C++ 的 shared_ptr
开发语言·c++·c#11.0
仙人掌_lz1 小时前
理解多智能体深度确定性策略梯度MADDPG算法:基于python从零实现
python·算法·强化学习·策略梯度·rl
陌尘(MoCheeen)1 小时前
技术书籍推荐(002)
java·javascript·c++·python·go
是代码侠呀1 小时前
从前端视角看网络协议的演进
leetcode·开源·github·github star·github 加星