【C++力扣】917.仅仅反转字母|387.字符串中第一个唯一字符|415.字符串相加


Blog’s 主页: 白乐天_ξ( ✿>◡❛)
🌈 个人Motto:他强任他强,清风拂山冈!
🔥 所属专栏:C++深入学习笔记
💫 欢迎来到我的学习笔记!

一、917.仅仅反转字母

1.1 题目描述

给你一个字符串s,根据下述规则反转字符串:

  • 所有非英文字母保留在原有位置。
  • 所有英文字母(小写或大写)位置反转。

返回反转后的s

示例 1:

输入:s = "ab-cd"
输出:"dc-ba"

示例 2:

输入:s = "a-bC-dEf-ghIj"
输出:"j-Ih-gfE-dCba"

示例 3:

输入:s = "Test1ng-Leet=code-Q!"
输出:"Qedo1ct-eeLg=ntse-T!"

1 <= s.length <= 100
s 仅由 ASCII 值在范围 [33, 122] 的字符组成
s 不含 '\"' '\\'
只反转字母,不反转特殊符号,相当于忽略掉特殊字符,首尾交换。

1.2 分析过程

想法一:使用迭代器:

  1. 一个正向迭代器指向开始位置;
  2. 一个反向迭代器指向结束位置;
  3. 缺点:正向迭代器与反向迭代器不能做比较,因为类型不相同。类型如下:
cout << "string::iterator" << typeid(string::iterator).name() << endl;
cout << "string::reverse_iterator" << typeid(string::reverse_iterator).name() << endl;

//string::iteratorclass std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >
//string::reverse_iteratorclass std::reverse_iterator<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > > >

想法二:使用两个正向迭代器即使用下标;不能使用范围for,因为底层就是迭代器。

  1. 避免一个字母都没有的情况:加上一个left < right条件;
  2. 避免死循环不懂的情况: swap(s[left++], s[right--]);交换以后继续往两边走。

1.3 代码解答

class Solution
{
public:
	// 判断字符是不是字母
	bool isLetter(char ch)
	{
		if (ch >= 'a' && ch <= 'z')
			return true;
		else if (ch >= 'A' && ch <= 'Z')
			return true;
		else
			return false;
	}
	// 使用下标进行遍历:
	string reverseOnlyLetters(string s)
	{
		int left = 0;
		int right = s.size() - 1;// size表示最后一个字符串的下一个位置
		while (left < right)
		{
			while (left < right && !isLetter(s[left]))// left < right条件可以
			{
				++left;// 往右边走
			}
			while (left < right && !isLetter(s[right]))
			{
				--right;// 往左边走
			}
			swap(s[left++], s[right--]);// 交换,为什么++、--?避免死循环,不往后走,因此交换完后,left继续往右、right继续往左!否则他们两个就不动了
		}
		return s;
	}
};

二、387.字符串中第一个唯一字符

7月20日3:02:00

2.1 题目描述

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

示例 1:

输入: s = "leetcode"
输出: 0

示例 2:

输入: s = "loveleetcode"
输出: 2

示例 3:

输入: s = "aabb"
输出: -1

提示:

1 <= s.length <= 105
s 只包含小写字母

2.2 分析过程以及代码实现

  1. 方法一
  • 时间复杂度:O(N<sup>2</sup>);(不优)
  • 每个字符都与其他字符对比一遍。
  1. 方法二:计数排序
  • 时间复杂度:O(N)
  • 统计每个字符出现的次数,返回只第一个只出现一次的字符的索引(即下标)。
  • 实现:
class Solution
{
public:
	int firstUniqChar(string s)
	{
		// 使用相对映射的方法:进行计数排序
		int count[26] = { 0 };
		// 统计次数
		for (auto ch : s)// 使用范围for进行遍历
		{
			count[ch - 'a']++;// ????
			// 这里是要统计字符串s中的字符到26个小写字母里面去,有多少个字符,26个字母中就会出现对应的次数
		}
		// 这里就是用下标访问,而不是范围for
		for (size_t i = 0; i < s.size(); ++i)
		{
			if (count[s[i] - 'a'] == 1)// 说明它只出现了一次,而且是第一个只出现一次的字符
				return i;
		}
		return -1;// 说明s字符串中的都是重复出现的
	}
};

三、415.字符串相加

7月20日3:10:00

3.1 题目描述

给定两个字符串形式的非负整数 num1num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

示例 1:

输入:num1 = "11", num2 = "123"
输出:"134"

示例 2:

输入:num1 = "456", num2 = "77"
输出:"533"

示例 3:

输入:num1 = "0", num2 = "0"
输出:"0"

提示:
● 1 <= num1.length, num2.length <= 104
● num1 和num2 都只包含数字 0-9
● num1 和num2 都不包含任何前导零

3.2 分析过程

想法一:error

  • 当整型数据很大时,即使是long long类型也可能存储不下,就会使用字符串进行存储、运算。然后使用字符串模拟四则运算,这就是所谓的“大数运算”。本题模拟的是加法运算。
  • 字符串转换成整型:stoi;各种类型转换成字符串:to_string
  • 但是这种方法不行,转换后数据不仅超出表示范围,而且还会丢失!

想法二:right

  • 字符串中的字符倒着取,从末尾开始进行运算;
  • 只要内存足够,字符串存储在内存中是一定能存储下的;(例如:整数长度100万,也就是内存空间大约1MB)
  • 字符串要两个都结束了才是结束,短字符串结束时长字符串是需要继续的,例如:"9999999999999999" + "1",它不断地都有进位的,不能直接将前几位字符数据拷贝下来。
class Solution {
public:
	string addStrings(string num1, string num2) 
	{
		string str;// 得到的最终结果存储在这里
		int end1 = num1.size() - 1, end2 = num2.size() - 1;
		// 进位
		int next = 0;
		while (end1 >= 0 || end2 >= 0)// 两个都要结束
		{
			int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
			int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
			end1--;
			end2--;
			int ret = val1 + val2 + next;// 加上进位
			next = ret / 10;// 记下进位数:ret大于10,记下1;ret小于10,记下0
			ret = ret % 10; 
			// 将最终的结果进行头插到str中:(不太好)
            // 不断头插n次时,时间复杂度就已经O(N)了
			str.insert(str.begin(), '0' + ret);
		}
		if (next == 1)
			str.insert(str.begin(), '1');
		return str;
	}
};

3.3 代码实现

写法一:使用头插

class Solution {
public:
	string addStrings(string num1, string num2) 
	{
		string str;// 得到的最终结果存储在这里
		int end1 = num1.size() - 1, end2 = num2.size() - 1;
		// 进位
		int next = 0;
		while (end1 >= 0 || end2 >= 0)// 两个都要结束
		{
			int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
			int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
			end1--;
			end2--;
			int ret = val1 + val2 + next;// 加上进位
			next = ret / 10;// 记下进位数:ret大于10,记下1;ret小于10,记下0
			ret = ret % 10; 
			// 将最终的结果进行头插到str中:(不太好)
            // 不断头插n次时,时间复杂度就已经O(N)了
			str.insert(str.begin(), '0' + ret);
		}
		if (next == 1)
			str.insert(str.begin(), '1');
		return str;
	}
};

写法二:使用尾插

class Solution {
public:
	string addStrings(string num1, string num2)
	{
		string str;// 得到的最终结果存储在这里
		int end1 = num1.size() - 1, end2 = num2.size() - 1;
		// 进位
		int next = 0;
		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 + next;// 加上进位
			next = ret / 10;// 记下进位数:ret大于10,记下1;ret小于10,记下0
			ret = ret % 10;

			str += ('0' + ret);// 尾插,这里是operator+=的一种用法,O(N)
		}
		if (next == 1)
			str += '1';// 结果是倒着的,就需要进行逆置:即使用算法库里面的reverse,但是要求是双向迭代器
		reverse(str.begin(), str.end());

		return str;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值