[LeetCode] 709. To Lower Case
LeetCode 709. To Lower Case (转换成小写字母) Diffculty: Eazy
Question
Implement function ToLowerCase()
that has a string parameter str
, and returns the same string in lowercase.
实现函数 ToLowerCase()
,该函数接收一个字符串参数 str
,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。
Example
Example 1
1 | Input: "Hello" |
Example 2
1 | Input: "here" |
Example 3
1 | Input: "LOVELY" |
Solution
Java
My Solution 1
解题思路
已知 String
实际是 char
类型的字符序列,即可将 String
转换为 char[]
。题目在于将大写字母转换为小写字母,已知 char
这个字符类型,实际是存的 int
,只是通过 ASCII
编码,映射了数字和字符的关系。使用 char
类型,可以数字与字符相互转换,只要找到大写字母与小写字母对应数字之间的关系即可解决该问题。转大写时,同理。
获取大小写字母映射数字的关系,可以通过查询 ASCII
编码表或以下代码:
1 | char A = 'A'; |
即:
A - Z
的范围:[65, 90]
a - z
的范围:[97, 122]
A
与a
之间相差了 32Z
与z
之间相差了 32
解题步骤
- 定义输出变量(
StringBuilder
) ->result
- 字符串
str
转字符数组,循环字符数组 ->s
- 定义临时变量
char a
,a = s
- 判断
a
是否是大写字母,即a > 64 && a < 91
,如是,则a += 32
,如否,则不变 - 将
a
加到result
中
- 定义临时变量
- 循环结束后,返回结果变量 ->
result.toString()
Code
初版
1 | public String toLowerCase(String str) { |
优化版
参考 LeetCode Discuss Solution 1 后:
1 | public String toLowerCase(String str) { |
Complexity Analysis
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
LeetCode Discuss Solution 1
Code
Code 1 @climberig
1 | public String toLowerCase(String str) { |
Code 2 @kevlar_ksb
1 | public String toLowerCase(String str) { |
Complexity Analysis
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
解题思路
与我的解决思路差不多。
需要特别说明的是 Code 2 中,char c = (char) (str.charAt(i) | (char) (32));
。
|
是按位或运算符,其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为 1
时,结果位就为 1
。
可以通过以下代码看出计算过程:
1 | System.out.println(Integer.toBinaryString('A')); // 65 = 01000001 |
这样一看 32
就显的很特别,这个 A
和 a
之间相差 32
是有原因的:
1 | A = 65 = 01000001 |
从上面的等式可以看出,大写与小写之间只有第 6 位是不同的(大写是 0
,小写是 1
)
而 32
= $2^5$ = 00100000
这时再回来看,'A' | 32
,就很明显了,因为大小写之间的二进制位只有第 6 位是不同的。
通过按位或操作,原来位上是 1
的,按位或后还是 1
,原来位上是 0
的,按位或后还是 0
。
只有第 6 位,原来位上是 0
,按位或后变为 1
。就相当于 +32
。
顺便一提,虽然 'A' | 32
相当于 'A' + 32
,但实际上 |
和 +
还是有区别的。
再顺便一提,64
= $2^6$ = 01000000
,因为大小写字母都大于 64
,所以第 7 位都是 1
。
Summary
我看到 LeetCode 上有逗比,在写 return str.toLowerCase()
之类的,直接调用提供的 API,确实是一行就写完了。但是这个算法题就没有意义了。
倒是提醒了我,顺便去看了看 Java 的 java.lang.String#toLowerCase()
的实现。
是通过 Unicode 去转换的,而且还涉及到不同的区域设置的大小写转换规则,
大致逻辑如下:
- 先获取字符串中的第一个需要转小写的字符的索引(
firstUpper
),如果没有,当然就不会继续再执行了,直接return this;
- 然后将第一个需要转小写的字符索引之前的部分复制到
char[] result
中 - 再从
firstUpper
开始循环检查,并按转换规则,将大写字母转换为小写字母,最后赋值到对应的result
的索引中
中间涉及的转换规则,边界检查那一大堆又是另外一回事了。
最近做的这几道题都涉及到位运算。平时用的很少,脑子转不过弯来,不是看别人的代码都想不起来还可以这么玩。抽空还是深入学习一下,写写关于位运算的好了。