LeetCode初级算法之字符串:验证回文串和字符串转换函数

这篇博客也是整理LeetCode字符串的两个题目。

验证字符串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:
输入: “race a car”
输出: false

这个题思路好想的一个就是,我先遍历一遍字符串,把那些什么空格啥的全都不要,只保留数字字符和字母,存入一个新的字符串。 然后在判断这个新的字符串是不是回文串。 所谓回文,就是正着和反着一样。用双指针,一个往前,一个往后对比即可。

class Solution {
public:
    bool isPalindrome(string s) {

        if (s.size()==0)
            return true;

        string s1="";

        for (int i=0; i<s.size(); i++)
        {
            if (isalnum(s[i]))
            {
                if (isupper(s[i]))
                    s[i] = tolower(s[i]);

                s1 += s[i];
            }
        }

        // 判断是不是回文字符串
        for (int i=0, j=s1.length()-1; i<=j; i++, j--)
        {
            if (s1[i] != s1[j])
                return false;
        }

        return true;
    }
};

上面可能比较好想,其实也个题也不用那么麻烦,只需要一次遍历即可,也是使用双指针,只不过,指针每一次找的时候,只招数字字符和字母,然后两个比较,移动。 上面的简化版。

class Solution {
public:
    bool isPalindrome(string s) {

        if (s.size()==0)
            return true;

        cout << s << endl;

        int i=0;
        int j=s.size()-1;

        while(i<j)
        {
            while (i<j && !isalnum(s[i])) i++;
            while (i<j && !isalnum(s[j])) j--;

            if (tolower(s[i]) != tolower(s[j]))
                return false;

            i++;
            j--;

        }

        return true;
    }
};

这个题这是比较常规的思路了,主要是通过这个题整理C++的ctype库,有时候判断字符是不是整数或者字母,或者转换字母的大小写,这个库里面的函数比较好用,等说完了下一个题之后,统一整理,见最下面。

字符串转换整数

请你来实现一个 atoi 函数,使其能将字符串转换成整数。

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。

当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0。

说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

示例 1:
输入: “42”
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: “4193 with words”
输出: 4193
解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。
示例 4:
输入: “words and 987”
输出: 0
解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: “-91283472332”
输出: -2147483648
解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。

这个题拿到手之后,思路也不是那么复杂,只是遍历筛选,然后转换,转换的核心之前整数的那篇里面也写过,就是先res=0, 每次遇到一个整数,res=res*10+整数。 这个题比较复杂的就是整数字符串的筛选, 先挂上我的第一遍代码:

思路就是先过滤掉前面的空格,然后对于第一个字符,进行是不是+ - 数字或者其他的判断,如果是其他,那么返回0, 否则,在对+ - 数字进行分类讨论。

这个题需要时刻注意的是整数的越界,在*10那就应该时刻判断。

class Solution
{
public:
    int myAtoi(string str)
    {
        //cout << str << endl;
        int i=0;
        long long int res = 0;

        // 搜索第一个有效字符
        while (i<str.size() && str[i]==' ')
            i++;

        if (i<str.size())
        {
            if (str[i]=='+' || str[i]=='-' || isdigit(str[i]))
            {
                if (str[i]=='+')
                {
                    i++;
                    while(i<str.size() && isdigit(str[i]))
                    {
                        res = res * 10 + (str[i]-'0');
                        if (res > INT_MAX)
                            return INT_MAX;
                        i++;
                    }
                }
                else if (str[i]=='-')
                {
                    i++;
                    while(i<str.size() && isdigit(str[i]))
                    {
                        res = res * 10 + (str[i]-'0');
                        if (res > INT_MAX)
                            return INT_MIN;
                        i++;
                    }
                    if (i<=str.size())
                        res = -res;
                }
                else
                {
                    while(i<str.size() && isdigit(str[i]))
                    {
                        res = res * 10 + (str[i]-'0');
                        if (res > INT_MAX)
                            return INT_MAX;
                        i++;
                    }
                }
            }
            else            // 不能进行有效的转换
                return 0;
        }

        return res;
    }
};

但是这个题也不用这么多if语句,这么复杂的判断,所以下面给出一个改进版本,简化代码

思路就是我先遍历,定一个flag初始化为1,找到第一个合适的处理位置,需要下面四个判断

  • 如果是其他字符,跳过
  • 如果是+, i++,然后跳出循环
  • 如果是-, flag=-1, i++, 跳出循环
  • 如果是数字字符, 直接跳出循环

接下来就开始处理, 在i的这个位置,继续往后遍历,把字符串转换成整数即可

下面上代码:

class Solution
{
public:
    int myAtoi(string str)
    {
        int i=0;
        int flag = 1;
        long long int res = 0;

        for (; i<str.size(); i++)
        {
            if (str[i] == ' ')
                continue;
            else if (str[i] == '-')
            {
                flag = -1;
                i++;
                break;
            }
            else if (str[i] == '+')
            {
                i++;
                break;
            }
            else if (isdigit(str[i]))
            {
                break;
            }
            else
                return 0;
        }

        while (i<str.size() && isdigit(str[i]))
        {
            res = res * 10 + (str[i]-'0');
            if (res * flag> INT_MAX)
                return INT_MAX;
            else if (res * flag < INT_MIN)
                return INT_MIN;
            i++;
        }

        return res * flag;
    }
};

这个的效率应该更高一些。

总结

通过这两个题,让我意识到两个问题,编代码的时候,一定要注意越界的问题

  • 数组下标的越界,从而访问了非法内存(这个在写循环的时候一定要特别注意)
  • 第二个是超出了数的表示范围的越界, 这个在循环中连乘运算一定要注意,声明类型的时候也要考虑到。

所以,写代码一定要时刻考虑着自己的代码是不是有什么越界bug,因为这个自己的测试样例不好测出来,所以得时刻提醒着自己点。 上面这两个题好几次都是越界bug。

下面是整理的ctype中常用的函数:

int isalpha(int ch) 若ch是字母(‘A’-‘Z’,‘a’-‘z’)返回非0值,否则返回0
int isalnum(int ch) 若ch是字母(‘A’-‘Z’,‘a’-‘z’)或数字(‘0’-‘9’)返回非0值,否则返回0
int isascii(int ch) 若ch是字符(ASCII码中的0-127)返回非0值,否则返回0
int iscntrl(int ch) 若ch是作废字符(0x7F)或普通控制字符(0x00-0x1F)返回非0值,否则返回0。
int isdigit(int ch) 若ch是数字(‘0’-‘9’)返回非0值,否则返回0
int isgraph(int ch) 若ch是可打印字符(不含空格)(0x21-0x7E)返回非0值,否则返回0
int islower(int ch) 若ch是小写字母(‘a’-‘z’)返回非0值,否则返回0
int isprint(int ch) 若ch是可打印字符(含空格)(0x20-0x7E)返回非0值,否则返回0
int ispunct(int ch) 若ch是标点字符(0x00-0x1F)返回非0值,否则返回0
int isspace(int ch) 若ch是空格(’ ‘),水平制表符(’\t’),回车符(’\r’),走纸换行(’\f’)垂直制表符(’\v’),换行符(’\n’)返回非0值,否则返回0
int isupper(int ch) 若ch是大写字母(‘A’-‘Z’)返回非0值,否则返回0
int isxdigit(int ch) 若ch是16进制数(‘0’-‘9’,‘A’-‘F’,‘a’-‘f’)返回非0值,否则返回0
int tolower(int ch) 若ch是大写字母(‘A’-‘Z’)返回相应的小写字母(‘a’-‘z’)
int toupper(int ch) 若ch是小写字母(‘a’-‘z’)返回相应的大写字母(‘A’-‘Z’)

另外,因为都是每个题都是自己写main函数进行测试,这次用到了getline输入,所以顺便整理了C++的诸多输入的方式如下:
C++基础:各种输入方法总结,cin、cin.get()、cin.getline()、getline()、gets()、getchar()

发布了66 篇原创文章 · 获赞 67 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wuzhongqiang/article/details/103293457
今日推荐