LeetCode解题记录(6~10)

6.Z字形变换

将字符串 "PAYPALISHIRING" 以Z字形排列成给定的行数:

P      A       H     N
A  P  L   S  I   I   G
Y       I        R

之后从左往右,逐行读取字符:"PAHNAPLSIIGYIR"
实现一个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:
输入: s = "PAYPALISHIRING", numRows = 3
输出: "PAHNAPLSIIGYIR"

示例 2:
输入: s = "PAYPALISHIRING", numRows = 4
输出: "PINALSIGYAHRPI"

分析:根据题目的示例,我们可以用矩阵来保存转换后的结果。通过对图示的观察,我们可以发现字符串的输出顺序是从0开始向下依次显示字符到达预设顶点之后再转向上输出这一重复过程的,所以我们可以定义一个变量row来记录当前行数和一个哨兵direction来记录当前的输出方向,当到达上下的两个顶点时反转方向然后按列的顺序来读取字符串得到最终结果。

   string convert(string s, int numRows) {
    if (numRows > s.length() || numRows == 1) return s;
    vector tran(numRows);
    int row = 0;
    bool direction = false;
    for(int i = 0; i < s.length(); ++i) {
        tran[row] += s[i];
        if(row == 0 || row == numRows - 1) {
            direction = !direction;
        }
        row += direction ? 1 : -1;
    }
    string res = "";
    for(auto &v : tran) {
        res += v;
    }
    return res;
   }

7. 反转整数

给定一个 32 位有符号整数,将整数中的数字进行反转。

示例 1:
输入: 123
输出: 321

示例 2:
输入: -123
输出: -321

示例 3:
输入: 120
输出: 21

注意:
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。

分析:要的到一个数M的逆序,我们需要从个位开始得到每一位上的数字。所以我们可以用一个循环来不断的对M%10,然后用M/10得到。同时,我们用一个变量来保存分解的数字,然后在循环内执行r*10+M%10就可以得到逆序后的数字了。然后我们需要判断该数字是否溢出。这里我们可以根据得到的逆序部分结果来判断。

   int reverse(int x) {
      int reverse = 0;
      while(x != 0) {
        int pop = x % 10;
        x /= 10;
        //判断是否溢出
        if (reverse > INT_MAX / 10 || (reverse == INT_MAX / 10 && pop >7)) return 0;
        if (reverse < INT_MIN / 10 || (reverse == INT_MIN / 10 && pop < -8)) return 0;
        reverse = reverse * 10 + pop;
      }
      return reverse;
   }

8.字符串转整数 (atoi)

实现 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) 。

分析:这个题并不困难,只是麻烦在各种限定条件的判断,我们只需要做好各种判断就可以轻易的做出来了。

    int myAtoi(string str) {
      vector res;
      int i = 0;

      //去除开头的空格
      while(str[i] == ' ') {
        ++i;
      }

      //判断是否符合开头条件 必须以数字或‘-’或‘+’开头
      if(!isdigit(str[i]) && str[i] != '-' && str[i] != '+') {
        cout<<0< 10) {
        if (isPositive) {
            return INT_MAX;
        }else {
            return INT_MIN;
        }
      }
      
      //计算结果
      long m = 0;
      for(int j = 0; j < res.size(); ++j) {
        m = m*10 + res[j];
      }
      //是否是负数
      m = isPositive ? m : -m;
      //是否溢出
      if (m > INT_MAX) m = INT_MAX;
      if (m < INT_MIN) m = INT_MIN;

      return m;
    }

9. 回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:
输入: 121
输出: true

示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。

进阶:

你能不将整数转为字符串来解决这个问题吗?

分析:判断一个数字是否是回文数,我们只需要判断这个数的逆序是否与它本身相等就行了。怎么求数的逆序我们在第七题翻转整数中已经接过了,这里只需要做一些判断就可以了。这里我们不需要将整数转换为字符串。

    bool isPalindrome(int x) {
      if (x < 0) return false;
      int res = 0;
      int n = x;
      while(x) {
        res = res*10 + x%10;
        x /= 10;
      }
      return res == n;
    }

10. 正则表达式匹配

给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符。
'*' 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。

说明:
  • s 可能为空,且只包含从 a-z 的小写字母。
  • p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。

示例 2:
输入:
s = "aa"
p = "a"
输出: true
解释: '
' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 "aa"。

示例 3:
输入:
s = "ab"
p = "."
输出: true
解释: ".
" 表示可匹配零个或多个('*')任意字符('.')。

示例 4:
输入:
s = "aab"
p = "cab"
输出: true
解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 "aab"。

示例 5:
输入:
s = "mississippi"
p = "mis*is*p*."
输出: false

分析:我们可以使用递归来将两个字符串进行匹配。匹配的原则是字符相同,字符为'.'或字符为'*',前面两种情况我们可以直接对两个字符串匹配项向后移动。在遇到‘*’号时,则只移动s串,直到匹配结束。(这段代码借鉴了jkn1234)

 bool isMatch(string s, string p) {
    if(p.empty() && s.empty()) return true;
    if(p.empty() && !s.empty()) return false;

    if(s.empty()) { // 当被匹配字符串不为空时  匹配字符串为形如x*x*x*这样的可以匹配成功
      if(p.length()%2 == 1) return false; //奇数个字符串不可能匹配成功
    
      int i = 0;
      while(i < p.length()) { // 看字符串是否为x*x*x*
        if(i%2 == 0) {
            if(p[i] == '*') return false; //不能出先形如**格式,后一个找不到前驱字符。
            i++;
        }else {
            if(p[i] == '*') i++;
            else return false;
        }
      }
      return true;
    }

    int i = -1;
    if (p.length() >=2 && p[1] == '*') {
      do {
          if (isMatch(s.substr(++i), p.substr(2)))
            return true;
          // 匹配失败且i已经为len了,即p+2匹配到s的最后了任然匹配失败,return false
          else if (i == s.length())
            return false;
        } while (s[i] == p[0] || p[0] == '.');
      return false;
    } else { // p[1]不为*时
      if (s[0] == p[0] || p[0] == '.')
        return isMatch(s.substr(1), p.substr(1));
      else
        return false;
    }
}

你可能感兴趣的:(LeetCode解题记录(6~10))