【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘

在这里插入图片描述

​个人主页:@Sherry的成长之路
学习社区:Sherry的成长之路(个人社区)
专栏链接:C++初阶
长路漫漫浩浩,万事皆有期待

上一篇博客:C++初阶】string类常见题目详解(一)—— 仅仅反转字母、字符串中的第一个唯一字母、字符串最后一个单词的长度、验证回文串、字符串相加

文章目录

  • 题目六:把字符串转换成整数
  • 题目七:反转字符串
  • 题目八:反转字符串 II
  • 题目九:反转字符串中的单词 III
  • 题目十: 字符串相乘
  • 总结:

题目六:把字符串转换成整数

链接:把字符串转换成整数
题目描述:
 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。数值为0或者字符串不是一个合法的数值则返回0。输入的字符串包括数字字母符号,可以为空。

示例:
 输入:“+2147483647”
 输出:“2147483647”

分析:
 字符串当中可能包含数字、字母和其他符号,正数可以在前面放上正号,由此可以确定的是,一个字符串一个合法的数值,则除了其第一个字符可能是正号或负号以外,其他字符都应该是数字字符。

解题思路:
 1、先判断除第一个字符以外的字符,若是其中出现了非数字字符的字符,则该字符串非法,否则我们计算出其转换为整数后的数值。
 2、再判断第一个字符,若是正号,则当前整数的正值;若是负号,则返回当前整数的负值;若还是数字字符,则再次更新当前整数的数值并返回;若第一个字符不属于这三种情况,则说明该字符串还是非法的。

代码:

class Solution {
public:
	int StrToInt(string str) {
        if (str.size() == 0) //空字符串,返回0
			return 0;
		int start = 0; //头指针指向第一个字符
		int end = str.size() - 1; //尾指针指向最后一个字符
		int ret = 0; //字符串转换为整数后的结果
		int i = 1; //标识十进制当前位的权重(当前为个位,权重为1)
		while (start < end) //判断第一个字符之后的字符
		{
			if (str[end] < '0' || str[end] > '9') //若不是数字,则非法
			{
				return 0;
			}
			ret += i*(str[end] - '0'); //ret更新
			i *= 10; //下一位权重增大十倍
			end--; //继续判断
		}
		//判断第一个字符
		if (str[end] >= '0' && str[end] <= '9') //是数字
			return ret + i*(str[end] - '0'); //再次更新ret并返回正值
		if (str[end] == '+') //标识正数
			return ret; //返回正值
		if (str[end] == '-') //标识负数
			return -ret; //返回负值
		return 0; //第一个字符不是数字、+、-当中的一个,则还是非法
	}
};

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第1张图片

题目七:反转字符串

链接:344. 反转字符串
题目描述:
 编写一个函数,其作用是将输入的字符串反转过来,你必须原地修改字符串,即使用O(1)的额外空间解决这一问题。你可以假设数组中的所有字符都是ASCII码表中的可打印字符。

示例:
 输入:[ ‘h’, ‘e’, ‘l’, ‘l’, ‘o’ ]
 输出:[ ‘o’, ‘l’, ‘l’, ‘e’, ‘h’ ]

思路:
 这是一道比较简单的题目,尤其是用C++来做,我们可以使用下标的方式交换vector容器当中的数据,也可以使用逆置函数reverse对指定迭代器区间的数据进行逆置。

代码:
1.使用下标进行交换:

class Solution {
public:
	void reverseString(vector<char>& s) {
		//使用下标进行交换
		int left = 0, right = s.size() - 1;
		while (left < right)
		{
			swap(s[left], s[right]);
			left++;
			right--;
		}
	}
};

2.使用逆置函数进行逆置:

class Solution {
public:
	void reverseString(vector<char>& s) {
		//使用逆置函数进行逆置
		reverse(s.begin(), s.end()); 
	}
};

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第2张图片

题目八:反转字符串 II

链接:541. 反转字符串 II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 :
输入:s = “abcdefg”, k = 2
输出:“bacdfeg”

思路:
这道题是反转字符串的进阶版,看题目可能有点难理解,我们来分析一下。

我们以如下字符串为例,假设 k = 3,如下:
【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第3张图片

其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。因为要找的也就是每 2 * k 区间的起点,这样写,程序会高效很多。

所以当需要固定规律一段一段去处理字符串的时候,可以在 for 循环的表达式上进行尝试。

这里反转的逻辑可以直接使用 reverse 来实现反转。

代码:

class Solution {
public:
    string reverseStr(string s, int k) {
        for (int i = 0; i < s.size(); i += (2 * k)) {
            // 1. 每隔 2k 个字符的前 k 个字符进行反转
            // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
            if (i + k <= s.size()) {
                reverse(s.begin() + i, s.begin() + i + k);
            }
            else {
                // 3. 剩余字符少于 k 个,则将剩余字符全部反转。
                reverse(s.begin() + i, s.end());
            }
        }
        return s;
    }
};

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第4张图片

题目九:反转字符串中的单词 III

链接:557. 反转字符串中的单词 III
给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例 1:
输入:s = “Let’s take LeetCode contest”
输出:“s’teL ekat edoCteeL tsetnoc”

解题思路
此题也可以直接在原字符串上进行操作,避免额外的空间开销。

当找到一个单词的时候,我们交换字符串第一个字符与倒数第一个字符,随后交换第二个字符与倒数第二个字符……如此反复,就可以在原空间上翻转单词。

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第5张图片

这样,我们就完成了对一个单词的反转,我们用个 while 循环完成对整个句子里面单词的反转,而循环结束的条件就是 i < s.length()

代码:

class Solution {
public:
    string reverseWords(string s) {
        int len = s.length();
        int i = 0;
        while (i < len) {
            int start = i;
            // 1.找到第一个单词,遇到空格就停止
            while (i < len && s[i] != ' ') {
                i++;
            }
            
            // 2.反转单词的顺序
            int left = start;
            int right = i - 1;
            while (left < right) {
                swap(s[left], s[right]);
                left++;
                right--;
            }

            // 3.此时i还是指向空格的,所以继续让i++,指向下一个单词
            while (i < len && s[i] == ' ') {
                i++;
            }
        }
        return s;
    }
};

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第6张图片

题目十: 字符串相乘

43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例 1:

输入: num1 = “2”, num2 = “3”
输出: “6”

解题思路
假设 num1 = 1234,num2 = 567,则把 num1 的每一个数乘以 num2 的每一个数的结果直接写出来(不用考虑进位)

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第7张图片

因为我们只是进行了单纯的数学运算,没有涉及任何字符串有关的操作,所以我们可以建立一个数组 ansArr 用来保存每一列相加的总和。

那么这个 ansArr 应该开多大空间呢?

两个数相乘的乘积最长是两个数长度之和,比如
999 ∗ 999 = 998001 ,为3+3=6位数

而两个数相乘的乘积最短是两个数长度之和再减1,比如
100 ∗ 100 = 10000 ,为3+3-1=5位数

我们默认开最长的空间。然后开辟数组把每一列的数都存起来,在实现代码的时候,应该怎么写才能把每列的数放到数组中正确的位置呢?

我们把 num1 的某一位称为第 i 位,把 num2 的某一位称为第 j 位,它们相乘的结果应该是位于数组的 i+j+1 的位置:
【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第8张图片
这里有一个特殊情况,比如上面的 ansArr 数组开了 7 个空间,但是第一个位置是没有值的,所以我们往 ans 里面插入数据的时候,要判断一下,假设第一个位置是 0 的话,那么就从第二个位置开始插入数据。

int index = ansArr[0] == 0 ? 1 : 0;

然后我们只需要从 ansArr 数组的最后一个位置开始,往前遍历,依次进位。

比如ansArr[6] %10= 8,此时 ansArr[6] = 8 ,然后 ,然后ansArr[5] = ansArr[5] + ansArr[6] / 10,因为ansArr[6] / 10=2,向前进 2 位,所以 ansArr[5] = 45+2=47

最后再定义一个字符串 ans,把 ansArr 的数字存进去就好了
注意:记得要把数字转换成字符

这种方法是比较优的一种,时间复杂度分析为 O ( n ∗ m ) O(n*m)O(n∗m),n 和 m 分别是 num1 和 num2 的长度。

class Solution {
public:
    string multiply(string num1, string num2) {
        if (num1 == "0" || num2 == "0") {
            return "0";
        }
        int len1 = num1.size();
        int len2 = num2.size();

        //两个数相乘的乘积最长是两个数长度之和,比如 999 * 999 = 998001
        //两个数相乘的乘积最短是两个数长度之和再减1,比如 100 * 100 = 10000
        //默认开最长
        vector<int> ansArr(len1 + len2);

        for (int i = len1 - 1; i >= 0; i--) {
            int x = num1[i] - '0'; //把num1的字符转换为数字
            for (int j = len2 - 1; j >= 0; j--) {
                int y = num2[j] - '0'; //把num2的字符转换为数字
                ansArr[i + j + 1] += x * y;
            }
        }

        //进位
        for (int i = len1 + len2 - 1; i > 0; i--) {
            ansArr[i - 1] += ansArr[i] / 10; //前一位=后一位的进位值+自己
            ansArr[i] %= 10;
        }

        //拼接(判断前导0的情况)
        //[0] [] [] []
        string ans;
        int index = ansArr[0] == 0 ? 1 : 0;
        while (index < len1 + len2) {
            ans += (ansArr[index] + '0');
            index++;
        }
        return ans;
    }
};

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘_第9张图片

总结:

今天我们比较详细地完成了string类的其他五道常见的题目。接下来,我们将进行STL中vector类的学习。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

你可能感兴趣的:(C++初阶,c++,开发语言)