目录

  • ​​一、概念​​
  • ​​二、模板​​
  • ​​三、例题​​
  • ​​题:58. 最后一个单词的长度​​
  • ​​解:​​
  • ​​题:434. 字符串中的单词数​​
  • ​​解:​​
  • ​​题:2042. 检查句子中的数字是否递增​​
  • ​​解:​​
  • ​​题:2047. 句子中的有效单词数​​
  • ​​解:​​
  • ​​题:1816. 截断句子​​
  • ​​解:​​
  • ​​题:1784. 检查二进制字符串字段​​
  • ​​解:​​
  • ​​题:468. 验证IP地址​​
  • ​​解:​​

一、概念

Java方法:

​split(Sting regex,int limit)​

limit 参数控制模式应用的次数,因此影响所得数组的长度。如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n ,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。​​如果 n 为非正,那么模式将被应用尽可能多的次数,而且数组可以是任何长度​​​。如果 n 为 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且​​结尾空字符串将被丢弃​​。

以​​“boo:and:foo”​​字符串为例:

Regex

Limit

Result

:

2

“boo”, “and:foo”

:

5

“boo”, “and”, “foo”

:

-2

“boo”, “and”, “foo”

o

5

“b”, “”, “:and:f”, “”, “”

o

-2

“b”, “”, “:and:f”, “”, “”

o

0

“b”, “”, “:and:f”

split源码:

public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
//这里是一堆的正则校验,大致是,传入的分割符是单符号位的,才进行下面的分割,否则,return Pattern.compile(regex).split(this, limit)调用另一个分割方法进行字符串分割位分割,文末会PO出此方法
if (((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
//从这里开始,进行limit值的入参及split逻辑
//当传进来的值是正数的时候,limit > 0 == true
boolean limited = limit > 0;
//声明一个list集合对返回值结果进行存储,用于最后给String[]赋值
ArrayList<String> list = new ArrayList<>();
//当没有按照指定的字符分割到最后一位的时候,执行while循环进行判断,然后使用substring(off, next)方法进行分割
while ((next = indexOf(ch, off)) != -1) {
//判断limited 为FALSE,即limit<0,或者,list.size() < limit - 1是否成立
if (!limited || list.size() < limit - 1) {
//若成立则使用substring(off, next)方法进行分割,并且加入到list中
list.add(substring(off, next));
//此时的初始标识符off为next+1
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
//不成立的话调用substring(off, value.length),此时value.length值为1
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// 如果不符合,则返回 this
if (off == 0)
return new String[]{this};

// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length));

// Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--;
}
}
//将所得到的list集合进行截取,使用toArray()方法赋值到String[] result中,所以这么看来,split方法的效率,是略差的
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}

二、模板

三、例题

题:58. 最后一个单词的长度

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

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

示例 1:

输入:s = "Hello World"
输出:5

示例 2:

输入:s = "   fly me   to   the moon  "
输出:4

示例 3:

输入:s = "luffy is still joyboy"
输出:6

提示:

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

解:

解题思路:​​逆向遍历​

AC代码:

class Solution {
public int lengthOfLastWord(String s) {
// 逆向遍历
int len = s.length();
int i = len - 1;
while(i >= 0 && s.charAt(i) == ' ') i --;
if(i < 0) return 0;
int j = i;
while(j >= 0 && s.charAt(j) != ' ') j --;
return i - j;
}
}

题:434. 字符串中的单词数

统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。

请注意,你可以假定字符串里不包括任何不可打印的字符。

示例:

输入: "Hello, my name is John"
输出: 5
解释: 这里的单词是指连续的不是空格的字符,所以 "Hello," 算作 1 个单词。

解:

解题思路:​​统计每一个单词的最后一个下标​

AC代码:

class Solution {
public int countSegments(String s) {
s += " ";
int ans = 0;
for(int i = 1; i < s.length(); i ++) {
if(s.charAt(i) == ' ' && s.charAt(i-1) != ' ')
ans ++;
}
return ans;
}
}

题:2042. 检查句子中的数字是否递增

句子是由若干 token 组成的一个列表,token 间用 单个 空格分隔,句子没有前导或尾随空格。每个 token 要么是一个由数字 0-9 组成的不含前导零的 正整数 ,要么是一个由小写英文字母组成的 单词 。

  • 示例,“a puppy has 2 eyes 4 legs” 是一个由 7 个 token 组成的句子:“2” 和 “4” 是数字,其他像 “puppy” 这样的 tokens 属于单词。

给你一个表示句子的字符串 s ,你需要检查 s 中的 全部 数字是否从左到右严格递增(即,除了最后一个数字,s 中的 每个 数字都严格小于它 右侧 的数字)。

如果满足题目要求,返回 true ,否则,返回 false 。

示例 1:

输入:s = "1 box has 3 blue 4 red 6 green and 12 yellow marbles"
输出:true
解释:句子中的数字是:1, 3, 4, 6, 12 。
这些数字是按从左到右严格递增的 1 < 3 < 4 < 6 < 12 。

示例 2:

输入:s = "hello world 5 x 5"
输出:false
解释:句子中的数字是:5, 5 。这些数字不是严格递增的。

示例 3:

输入:s = "sunset is at 7 51 pm overnight lows will be in the low 50 and 60 s"
输出:false
解释:s 中的数字是:7, 51, 50, 60 。这些数字不是严格递增的。

示例 4:

输入:s = "4 5 11 26"
输出:true
解释:s 中的数字是:4, 5, 11, 26 。
这些数字是按从左到右严格递增的:4 < 5 < 11 < 26 。

提示:

3 <= s.length <= 200
s 由小写英文字母、空格和数字 0 到 9 组成(包含 0 和 9)
s 中数字 token 的数目在 2 和 100 之间(包含 2 和 100)
s 中的 token 之间由单个空格分隔
s 中至少有 两个 数字
s 中的每个数字都是一个 小于 100 的 正 数,且不含前导零
s 不含前导或尾随空格

解:

解题思路:​​遍历+找到单词比大小​

AC代码:

class Solution {
public boolean areNumbersAscending(String s) {
int x = 0;
for(int i = 0; i < s.length(); i ++) {
if(s.charAt(i) == ' ' || s.charAt(i) > '9' || s.charAt(i) < '0') continue;
int num = 0;
while(i < s.length() && s.charAt(i) <= '9' && s.charAt(i) >= '0') {
num = num * 10 + (int)s.charAt(i);
i ++;
}
if(num <= x) return false;
x = num;
}
return true;
}
}

题:2047. 句子中的有效单词数

句子仅由小写字母(‘a’ 到 ‘z’)、数字(‘0’ 到 ‘9’)、连字符(’-’)、标点符号(’!’、’.’ 和 ‘,’)以及空格(’ ')组成。每个句子可以根据空格分解成 一个或者多个 token ,这些 token 之间由一个或者多个空格 ’ ’ 分隔。

如果一个 token 同时满足下述条件,则认为这个 token 是一个有效单词:

  • 仅由小写字母、连字符和/或标点(不含数字)组成。
  • 至多一个 连字符 ‘-’ 。如果存在,连字符两侧应当都存在小写字母(“a-b” 是一个有效单词,但 “-ab” 和 “ab-” 不是有效单词)。
  • 至多一个 标点符号。如果存在,标点符号应当位于 token 的 末尾 。

这里给出几个有效单词的例子:“a-b.”、“afad”、“ba-c”、“a!” 和 “!” 。

给你一个字符串 sentence ,请你找出并返回 sentence 中 有效单词的数目 。

示例 1:

输入:sentence = "cat and  dog"
输出:3
解释:句子中的有效单词是 "cat"、"and" 和 "dog"

示例 2:

输入:sentence = "!this  1-s b8d!"
输出:0
解释:句子中没有有效单词
"!this" 不是有效单词,因为它以一个标点开头
"1-s" 和 "b8d" 也不是有效单词,因为它们都包含数字

示例 3:

输入:sentence = "alice and  bob are playing stone-game10"
输出:5
解释:句子中的有效单词是 "alice"、"and"、"bob"、"are" 和 "playing"
"stone-game10" 不是有效单词,因为它含有数字

示例 4:

输入:sentence = "he bought 2 pencils, 3 erasers, and 1  pencil-sharpener."
输出:6
解释:句子中的有效单词是 "he"、"bought"、"pencils,"、"erasers,"、"and" 和 "pencil-sharpener."

提示:

1 <= sentence.length <= 1000
sentence 由小写英文字母、数字(0-9)、以及字符(' '、'-'、'!'、'.' 和 ',')组成
句子中至少有 1 个 token

解:

解题思路:​​双指针​

AC代码:

class Solution {
public int countValidWords(String s) {
int len = s.length();
int res = 0;
for(int i = 0; i < len;) {
if(s.charAt(i) == ' ' && ++ i >= 0) continue;
int j = i + 1;
while(j < len && s.charAt(j) != ' ') j ++;
if(isValid(s.substring(i, j))) res ++;
i = j + 1;
}
return res;
}
boolean isValid(String str) {
int len = str.length();
// hyphen -个数 dot .个数
for(int i = 0, hyphen = 0, dot = 0; i < len; i ++) {
char c = str.charAt(i);
if(Character.isDigit(c)) return false; // 不存在数字
if(c == '-' && ++ hyphen >= 0) {
if(hyphen > 1 || i == 0 || i == len - 1) return false;
if(!Character.isLetter(str.charAt(i-1)) || !Character.isLetter(str.charAt(i+1))) return false;
}
// 标点符号位于末尾
if((c == '!' || c == '.' || c == ',' ) && ++ dot >= 0) {
if(dot > 1 || i != len - 1) return false;
}
}
return true;
}
}

题:1816. 截断句子

句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)。

  • 例如,“Hello World”、“HELLO” 和 “hello world hello world” 都是句子。

给你一个句子 s 和一个整数 k ,请你将 s 截断 ,使截断后的句子仅含 前 k 个单词。返回 截断 s 后得到的句子。

示例 1:

输入:s = "Hello how are you Contestant", k = 4
输出:"Hello how are you"
解释:
s 中的单词为 ["Hello", "how" "are", "you", "Contestant"]
前 4 个单词为 ["Hello", "how", "are", "you"]
因此,应当返回 "Hello how are you"

示例 2:

输入:s = "What is the solution to this problem", k = 4
输出:"What is the solution"
解释:
s 中的单词为 ["What", "is" "the", "solution", "to", "this", "problem"]
前 4 个单词为 ["What", "is", "the", "solution"]
因此,应当返回 "What is the solution"

示例 3:

输入:s = "chopper is not a tanuki", k = 5
输出:"chopper is not a tanuki"

提示:

1 <= s.length <= 500
k 的取值范围是 [1, s 中单词的数目]
s 仅由大小写英文字母和空格组成
s 中的单词之间由单个空格隔开
不存在前导或尾随空格

解:

解题思路:​​空格计数​

AC代码:

class Solution {
public String truncateSentence(String s, int k) {
int n = s.length(), idx = 0;
while(idx < n) {
if(s.charAt(idx) == ' ' && -- k == 0) break;
++ idx;
}
return s.substring(0, idx);
}
}

题:1784. 检查二进制字符串字段

给你一个二进制字符串 s ,该字符串 不含前导零 。

如果 s 包含 零个或一个由连续的 ‘1’ 组成的字段 ,返回 true 。否则,返回 false 。

示例 1:

输入:s = "1001"
输出:false
解释:字符串中的 1 没有形成一个连续字段。

示例 2:

输入:s = "110"
输出:true

提示:

1 <= s.length <= 100
s[i] 为 '0' 或 '1'
s[0] 为 '1'

解:

解题思路:​​题有毛病​

AC代码:

class Solution {
public boolean checkOnesSegment(String s) {
return !s.contains("01");
}
}

题:468. 验证IP地址

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。

  • 如果是有效的 IPv4 地址,返回 “IPv4” ;
  • 如果是有效的 IPv6 地址,返回 “IPv6” ;
  • 如果不是上述类型的 IP 地址,返回 “Neither” 。

IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,​​172.16.254.1​​;

同时,IPv4 地址内的数不会以 0 开头。比如,地址 ​​172.16.254.01​​ 是不合法的。

IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如, ​​2001:0db8:85a3:0000:0000:8a2e:0370:7334​​​是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, ​​2001:db8:85a3:0:0:8A2E:0370:7334​​ 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。

然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (:😃 的情况。 比如, ​​2001:0db8:85a3::8A2E:0370:7334​​ 是无效的 IPv6 地址。

同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, ​​02001:0db8:85a3:0000:0000:8a2e:0370:7334​​ 是无效的。

示例 1:

输入:IP = "172.16.254.1"
输出:"IPv4"
解释:有效的 IPv4 地址,返回 "IPv4"

示例 2:

输入:IP = "2001:0db8:85a3:0:0:8A2E:0370:7334"
输出:"IPv6"
解释:有效的 IPv6 地址,返回 "IPv6"

示例 3:

输入:IP = "256.256.256.256"
输出:"Neither"
解释:既不是 IPv4 地址,又不是 IPv6 地址

示例 4:

输入:IP = "2001:0db8:85a3:0:0:8A2E:0370:7334:"
输出:"Neither"

示例 5:

输入:IP = "1e1.4.5.6"
输出:"Neither"

提示:

IP 仅由英文字母,数字,字符 '.' 和 ':' 组成。

解:

解题思路:​​模拟​

AC代码:

class Solution {
public String validIPAddress(String queryIP) {
if(queryIP.chars().filter(ch ->
ch == '.'
).count() == 3) return validIPV4(queryIP);
if(queryIP.chars().filter(ch ->
ch == ':'
).count() == 7) return validIPV6(queryIP);
return "Neither";
}
public String validIPV4(String queryIP) {
String[] nums = queryIP.split("\\.", -1); // 不丢弃结尾空字符串
for(String num : nums) {
// 判断长度
if(num.length() <= 0 || num.length() > 3) return "Neither";
// 没有前导0
if(num.charAt(0) == '0' && num.length() > 1) return "Neither";
// 判断是否都为数字
for(Character c : num.toCharArray()) {
if(!Character.isDigit(c)) return "Neither";
}
// 判断数字大小
if(Integer.parseInt(num) > 255) return "Neither";
}
return "IPv4";
}
public String validIPV6(String queryIP) {
String[] nums = queryIP.split(":", -1); // 不丢弃结尾空字符串
String hexdigits = "0123456789ABCDEFabcdef";
for(String num : nums) {
// 判断长度
if(num.length() <= 0 || num.length() > 4) return "Neither";
for(Character c : num.toCharArray()) {
if(hexdigits.indexOf(c) == -1) return "Neither";
}
}
return "IPv6";
}
}