【Leetcode】ASCII转换成小写字母

给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。

示例 1:
输入:s = “Hello”
输出:“hello”

示例 2:
输入:s = “here”
输出:“here”

示例 3:
输入:s = “LOVELY”
输出:“lovely”

提示:1 <= s.length <= 100s
由 ASCII 字符集中的可打印字符组成

ASCII 码中大小写字母的规律

在 ASCII 编码中:

  • 大写字母 A-Z 的范围是 65 ('A')90 ('Z')
  • 小写字母 a-z 的范围是 97 ('a')122 ('z')

观察它们的二进制表示:

  • 'A'(65)→ 01000001
  • 'a'(97)→ 01100001
  • 区别仅在于 第 5 位(从 0 开始算的第 5 位,即 0x20
    • 大写字母的第 5 位是 0
    • 小写字母的第 5 位是 1

因此,我们可以通过 位运算 来快速转换大小写。


1. 大写变小写、小写变大写:^=32(异或 32)
32 的二进制是 00100000,即 0x20
异或(XOR)运算 的特点是:

  • 如果某位是 0,异或 1 会翻转它(0 ^ 1 = 1)。
  • 如果某位是 1,异或 1 也会翻转它(1 ^ 1 = 0)。

所以:

  • 大写字母(第 5 位是 0
    • 'A' ^ 3201000001 ^ 00100000 = 01100001'a'(相当于 +32
  • 小写字母(第 5 位是 1
    • 'a' ^ 3201100001 ^ 00100000 = 01000001'A'(相当于 -32

示例:

char c = 'A';
c ^= 32;  // 'A' → 'a'
printf("%c\n", c);  // 输出 'a'

c = 'z';
c ^= 32;  // 'z' → 'Z'
printf("%c\n", c);  // 输出 'Z'

2. 大写变小写、小写保持不变:|=32(或 32)
|=32(即 | 0x20)会强制把第 5 位设为 1

  • 大写字母(第 5 位是 0
    • 'A' | 3201000001 | 00100000 = 01100001'a'(相当于 +32
  • 小写字母(第 5 位已经是 1
    • 'a' | 3201100001 | 00100000 = 01100001'a'(不变)

示例:

char c = 'B';
c |= 32;  // 'B' → 'b'
printf("%c\n", c);  // 输出 'b'

c = 'm';
c |= 32;  // 'm' → 'm'(不变)
printf("%c\n", c);  // 输出 'm'

3. 大写保持不变、小写变大写:&= ~33(即 &= 0xDF
~33 的二进制是 11011111(因为 3300100001,取反后是 11011111)。
&= ~33 会强制把第 5 位设为 0

  • 大写字母(第 5 位已经是 0
    • 'A' & ~3301000001 & 11011111 = 01000001'A'(不变)
  • 小写字母(第 5 位是 1
    • 'a' & ~3301100001 & 11011111 = 01000001'A'(相当于 -32

示例:

char c = 'C';
c &= ~33;  // 'C' → 'C'(不变)
printf("%c\n", c);  // 输出 'C'

c = 'n';
c &= ~33;  // 'n' → 'N'
printf("%c\n", c);  // 输出 'N'

代码示例:

class Solution {
    public String toLowerCase(String s) {
        StringBuilder sb=new StringBuilder();
    for(int i=0;i<s.length();i++){
        char ch=s.charAt(i);
        if(ch>=65&&ch<=90){
            ch|=32;
        }
        sb.append(ch);
    }    
    return sb.toString();
    }
    
}

说明:
1. append() 的作用

  • 功能:将数据(字符串、数字、字符等)追加到可变字符串的末尾。
  • 优势:比直接用 + 拼接字符串更高效(尤其适合循环或大量操作),因为不会反复创建新对象。

2. 主要使用场景

(1) StringBuilder(非线程安全,性能更高)

StringBuilder sb = new StringBuilder();sb.append("Hello");  // 追加字符串sb.append(" ");      
// 追加空格sb.append(123);      
// 追加数字
System.out.println(sb.toString()); 
// 输出: "Hello 123"

(2) StringBuffer(线程安全,性能稍低)

StringBuffer sb = new StringBuffer();
sb.append("线程安全");
sb.append("的拼接");
System.out.println(sb.toString()); 
// 输出: "线程安全的拼接"

3. 为什么不用 String 直接拼接?

  • String 不可变:每次 + 拼接都会生成新对象,浪费内存。
    • StringBuilder/Buffer 可变
  • 直接在原对象上修改,适合频繁操作。
    4. 常见用法示例
    (1) 链式调用
String result = new StringBuilder().
append("姓名: ").append(name).
append(", 年龄: ").append(age)
.toString();

(2) 循环中高效拼接

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {    
sb.append(i).append(" ");
}
System.out.println(sb.toString());

5. 注意事项

  • StringBuilder vs StringBuffer
    单线程用 StringBuilder(更快)。
    多线程用 StringBuffer(线程安全)。
  • 初始化容量:若已知最终大小,可指定初始容量避免扩容开销:
StringBuilder sb = new StringBuilder(100); // 初始容量100 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值