【c++5道练习题】①

目录

一、有限制的累加

二、计算日期到天数转换

三、仅仅反转字母

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

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


一、有限制的累加

 题述:

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

 题中已给: 

class Solution
{
public:
	int Sum_Solution(int n){
	}
};

知识点考察:

类的构造函数+ static修饰

先给代码再说思路:

代码如下:

#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),这个方法简单,本题采用此方法  

代码如下:

#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”

题中已给:

class Solution{
public:
	string reverseOnlyLetters(string s) {

	}
};

思路:

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

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

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

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)

注意事项:

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

题中已给:

class Solution {
public:
	int firstUniqChar(string s) {
    }
};

思路:

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

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

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,相当于直接求出长度,所以无需格外考虑 

典型的错误代码:

#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的使用说明如下:

 正确代码:

#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;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值