Leetcode 58. 最后一个单词的长度

今天我们开始 Leetcode 刷题,从简单的题开始,因为是随机抽到的第 58 题,那 Leetcode 刷题路就从第 58 题开始,个人能力有限,可能有些地方讲的不是很清楚,欢迎在评论区中指出,后续会做出修改。

58. 最后一个单词的长度

题目

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

示例 1:

输入:s = "Hello World"
输出:5
解释:最后一个单词是“World”,长度为5

示例 2:

输入:s = "   fly me   to   the moon  "
输出:4
解释:最后一个单词是“moon”,长度为4

示例 3:

输入:s = "luffy is still joyboy"
输出:6
解释:最后一个单词是长度为6的“joyboy”。

提示:

  • 1 <= s.length <= 104
  • s 仅有英文字母和空格 ' ' 组成
  • s 中至少存在一个单词

题解

一下属于个人的解题方法:

方式一:

根据题目中所描述:我们需要求解字符串中最后一个单词的长度,直接将整个字符串拆分为一个单词数组,然后求解最后一个单词的长度。

class Solution {
    public int lengthOfLastWord(String s) {
        String[] split = s.split("\\s+");	// @1
        return split[split.length - 1].length();
    }
}

这是最为简单的求解方式,也是大家最容易想到的。因为在多个单词之间可能存在多个空格,@1处就不能简单的以' '作为分隔符,此处正则表达式匹配1个或多个空格,这样在@1处取得的就是一个个单词,而且单词两边都是没有空格的。

提交代码:
Leetcode 58. 最后一个单词的长度_第1张图片可以看到使用这种方式求得的结果并不理想,那咱们可以换个思路。

方式二:

换一种方式,将将字符串转为字符数组,从头开始遍历,使用两个索引(i 和 j)记录最后一个单词的开始和结束位置。

class Solution {
    public int lengthOfLastWord(String s) {
        // 单词的开始索引的前一个位置
        int i = -1;
        // 单词的结束索引,最后一个有效字符的位置
        int j = 0;
        char[] chars = s.toCharArray();
        for (int index = 0; index < chars.length; index++) {
            char aChar = chars[index];
            if (aChar == ' ') {
                continue;
            }
            // 当前字符不为空,判断前一个字符是为空,遍历到了下一个单词【这是下一个单词的开始】 @
            if (index - 1 >= 0 && chars[index - 1] == ' ') {
                // 将下一个单词的开始索引的前一个位置赋值给 i
                i = index - 1;
            }
            // 单词的结束位置向后移动
            j = index;
        }
        // 遍历完后使用 结束位置 - 开始位置 得到最后一个词的长度
        return j - i;
    }
}

@1:判断当前字符是否是' '【空格】,是空格的话就跳过当前字符。
@2:当前字符的前一个字符是空格,此时遍历到了下一个单词的第一个字符,下一个也有可能是第一个单词的第一个有效字符,将单词的前后位置【i 和 j】后移。

当循环结束之后得到的就是最后一个单词的开始位置和结束位置。

提交代码,查看结果:
Leetcode 58. 最后一个单词的长度_第2张图片从结果中可以看到确实比第一次有了很多的进步。

方式三:

刚才我们从头开始遍历,但是题目中所要的是最后一个单词的长度,如果最后一个单词是 hello ... worle 中间省略了 n 个字符。要求的结果就在最后,但是我们却要遍历整个字符串才能得到结果,那为什么不从尾部开始向前遍历呢?

class Solution {
    public int lengthOfLastWord(String s) {
        char[] chars = s.toCharArray();
        int length = chars.length;
        int i = length; // @1
        int j = length;
        for (int index = length - 1; index >= 0; index--) {
            char aChar = chars[index];
            if (aChar == ' ') { // @2
                if (j != length) { // @3
                    break;
                }
                continue;
            }
            if (i == length) { // @4
                i = index;
            }
            j = index; // @5
        }
        return i - j + 1; // @6
    }
}

@1:同样定义两个变量用于保存单词的前后位置,都给他赋初值为字符串的长度。
@2:如果字符是空格,在这就有两个可能:

  • 比如字符串 s = "hello ... worle"【中间省略n个字符 】,当我们从后遍历遇见了空格,此时说明已经遍历完最后一个单词,此时就可以跳出循环。
  • 比如字符串 s = "hello ... worle ..."【中间和后面省略n个字符 ,因为这里的多个空格博客上并不会都显示出来,所以我就用...代替】。我们从后开始遍历遇见的第一个字符就是空格,此时推出循环显然并不合适,此时需要判断我们是不是遍历完了一个单词。

@3:j 标注最后一个词的开始位置,当 j == length是显然还没遍历到第一个词,跳过当前字符。
@4i == length 为 true,此时遇见了第一个有效字符,记录第一个【对于整个字符串来说应该是最后一个】有效字符的位置,i 指向的就是最后一个字符。
@5:将词的开始位置前移,j 指向的是第一个有效字符。
@6:此处 +1 的作用,这里 i 和 j 和方式二不同有些不同,j 直接指向的是第一个字符,i 指向组后一个字符,要想得到词的长度还需要 +1。

提交代码,查看结果:
Leetcode 58. 最后一个单词的长度_第3张图片从提交的结果中可以看到,无论是耗时和资源消耗方面,方式三都表现得非常优秀。

此题难度较简单,但是想要写得很好也并不容易,同样的问题不同的求解效果有千差万别,算法之美就体现得淋漓尽致。算法之路需要厚积薄发,要长时间的积累,我个人也是菜鸡中的一员,我后面也会时常提醒自己刷刷题,尽量把刷过的题都写出来。

个人能力有很多不足之处,我能写出代码但是并不一定能讲清除,请大家多多包含,无论是大家有更好的解题方法还是更好的解题过程的描述,欢迎大家在评论区中发表出来。

写到最后: 路漫漫其修远兮,吾将上下而求索。

你可能感兴趣的:(Leetcode,leetcode,算法,数据结构)