LeetCode刷题笔记(Valid Palindrome)

最近由于感冒了,几天都没有刷题了,刚刚刷了一道不算很难的题,但是与之前的数值型问题相比明显有些生疏,所以后期仍需加强这方面的练习。

具体题目如下:

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.

Note: For the purpose of this problem, we define empty string as valid palindrome.

Example 1:

Input: "A man, a plan, a canal: Panama"
Output: true
Example 2:

Input: "race a car"
Output: false

 

题意分析:

给定一个字符串,判断它是不是一个回文序列,仅考虑数字与字母,并忽略其他情况。注意:该题目中空字符串也算是回文序列。

解答如下:

方法一(对撞指针法)

先用两个指针r指向字符串的右端,l指向字符串的左端,让这两个指针齐头并进,跳过一切非数字与字母的情况,当两指针均指向数字或字母,然后通过转换大小写后判断两者是否相等,如果不相等则直接返回False,否则等到l=r时,返回True。

这里有几点需要注意:① 前面的 for (int l = 0; l < r; r--,l++) 中有 l < r,while(isalnum(s[r]) == false && l < r)依然需要 l < r,因为当while满足条件时r--,若不用l < r限制中,则有可能出现l > r的情况。②while(isalnum(s[l]) == false && l < r)中的isalnum(s[l])的返回值为非0或0,所以直接用while(!isalnum(s[l]))进行判断也是可以的,如while(!isalnum(s[l]) && l<r)完全等价于while(isalnum(s[l]) == false && l < r)。③toupper()函数将小写字母转化为大写字母,得到的其实是ASCII码,所以如果是数字就直接比较ASCII码,如果是小写字母先把它转为大写,然后在比较ASCII码。很显然toupper()函数可以用+32来替换,因为大写字母+32=小写字母。

class Solution {
public:
    bool isPalindrome(string s) {
        int r = s.size()-1;
        int l = 0;
        int n = s.size();
        if (n == 1)    //将字符串长度为1的直接判定为回文序列
            return true;
        for (int l = 0; l < r; r--,l++) {

            while(isalnum(s[r]) == false && l < r)//判断当前元素是不是字母或数字,是的就结束循环,否则右端指针向左边移动 对于isalnum()函数,如果s[r]在0 ~ 9  a ~ z  A ~ Z 中则返回值为非 0,否则返回 0
                   r--;
            while(isalnum(s[l]) == false && l < r) //判断当前元素是不是字母或数字,是的就结束循环,否则左端指针向右边移动。
                   l++;
            if(toupper(s[r]) != toupper(s[l]))  //toupper()函数将小写字母转化为大写字母;tolower()函数是把字符串都转化为小写字母
                return false;
        }
        return true;
        }

};

提交后的结果如下:

 

方法二(子函数法)

分别建立两个子函数,next_zmorsz函数用于从字符串的左端开始找数字或字母,并返回下标;prev_zmorsz函数用于从字符串的右端开始找数字或字母,并返回下标。在主函数中依据返回来的下标找到数字或字母进行对比,若不相等则返回Fasle,否则继续调用两子函数继续查找,直到满足l=r时,则返回True。

这里有几点需要注意:① 当发现for(; l < r; )这种情况时,可以直接将其等价成while(l < r)。②这里的三句 int n = (int)s.size();
        if (n == 1)  return true; 其实可以等价于将for循环的判断条件改成 l <= r。③笔者发现,向子函数传递参数时,如果形参为int prev_zmorsz(const string& s, int id)比int prev_zmorsz(const string s, int id)要快很多倍,说明本题中参数传递更适合地址传递。

class Solution {
public:
    bool isPalindrome(string s) {
        int l = next_zmorsz(s, 0);
        int r = prev_zmorsz(s, (int)s.size()-1);
        int n = (int)s.size();
        if (n == 1)
            return true;
/*        for(; l < r; ) {
            if (toupper(s[r]) != toupper(s[l]))
                return false;
            l = next_zmorsz(s, l + 1);
            r = prev_zmorsz(s, r - 1);
        }
        return true;*/ 
        while(l < r) {
            if (toupper(s[r]) != toupper(s[l]))
                return false;
            l = next_zmorsz(s, l + 1);
            r = prev_zmorsz(s, r - 1);
        }
        return true;
    }
private:

    int next_zmorsz(const string& s, int id){
        for (int i = id; i < s.size(); i++) {
            if (isalnum(s[i]))
                return i;}
        return  (int)s.size();
    }


    int prev_zmorsz(const string& s, int id){
        for (int i = id; i >= 0; i--) {
            if (isalnum(s[i]))
                return i;}
        return  -1;
    }
};

 提交后的结果如下:

 

方法三(不用库函数法)

将方法一中用的库函数均改写掉,唯有toupper()函数改写行不通。即if (toupper(s[l]) != toupper(s[r])) return false;并不等价于 if ((s[l] != s[r]) && (s[l] != s[r] - 32) && (s[r] != s[l] - 32)) return false;

class Solution {
public:
    bool isPalindrome(string s) {
        int n = s.size();
        if (n == 1) return true;
        int l = 0, r = n - 1;
        while (l < r) { 
            while ((l < r) && (!is_zmsz(s[l]))) l ++;
            while ((l < r) && (!is_zmsz(s[r]))) r --;
            if (toupper(s[l]) != toupper(s[r])) return false;
            l ++;
            r --;
        }
        return true;
    }
    inline bool is_zmsz(char a) {
        return ((a >= 'a') && (a <= 'z')) ||
               ((a >= 'A') && (a <= 'Z')) ||
               ((a >= '0') && (a <= '9')) ;
    }
};

 提交后的结果如下:

日积月累,与君共进,增增小结,未完待续。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值