# 手撕代码

# Python

# 1. 反转一个字符串

def reverse_string(s):
    return s[::-1]

# 测试用例
print(reverse_string("hello"))  # 输出: "olleh"
print(reverse_string(""))       # 输出: ""
1
2
3
4
5
6

答案: 使用切片 [::-1] 是最高效和Pythonic的方式。它从字符串的末尾开始,步长为-1,直到字符串的开头,从而实现反转。

# 2. 判断一个字符串是否是回文

def is_palindrome(s):
    # 处理大小写和空格,例如 "A man a plan a canal Panama"
    s = ''.join(char.lower() for char in s if char.isalnum())
    return s == s[::-1]

# 测试用例
print(is_palindrome("radar"))    # 输出: True
print(is_palindrome("hello"))    # 输出: False
print(is_palindrome("A man a plan a canal Panama")) # 输出: True
1
2
3
4
5
6
7
8
9

答案: 核心思想是处理后的字符串(仅保留字母数字并转为小写)是否与其反转字符串相等。

# 3. 计算斐波那契数列第n项(使用递归和循环两种方法)

方法一:循环(高效,推荐)

def fibonacci_iterative(n):
    if n <= 1:
        return n
    a, b = 0, 1
    for _ in range(2, n + 1):
        a, b = b, a + b
    return b

# 测试用例
print(fibonacci_iterative(10)) # 输出: 55
1
2
3
4
5
6
7
8
9
10

方法二:递归(低效,但考察算法思想)

def fibonacci_recursive(n):
    if n <= 1:
        return n
    return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)

# 测试用例
print(fibonacci_recursive(10)) # 输出: 55
1
2
3
4
5
6
7

答案: 面试中通常希望看到循环方法,因为它的时间复杂度是O(n),而递归是O(2^n)。但可能要求写出递归版本并分析其缺点。

# 4. 找出列表中的重复元素

def find_duplicates(lst):
    seen = set()
    duplicates = set()
    for item in lst:
        if item in seen:
            duplicates.add(item)
        else:
            seen.add(item)
    return list(duplicates)

# 测试用例
print(find_duplicates([1, 2, 3, 2, 1, 5, 6, 5, 5, 5])) # 输出: [1, 2, 5]
1
2
3
4
5
6
7
8
9
10
11
12

答案: 使用一个集合 seen 来跟踪已经遇到过的元素。如果一个元素已经在 seen 中,则将其添加到 duplicates 集合中(使用集合自动去重)。

# 5. 统计列表中每个元素的出现次数

from collections import Counter

def count_frequency(lst):
    return dict(Counter(lst))

# 测试用例
print(count_frequency(['a', 'b', 'a', 'c', 'b', 'a'])) # 输出: {'a': 3, 'b': 2, 'c': 1}
1
2
3
4
5
6
7

答案collections.Counter 是专门为此目的设计的工具,非常高效和简洁。也可以使用字典自己实现:frequency = {}; for item in lst: frequency[item] = frequency.get(item, 0) + 1

# 6. 实现一个装饰器,计算函数的执行时间

import time
import functools

def timer(func):
    @functools.wraps(func) # 保留原函数的元信息
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        print(f"函数 {func.__name__} 运行耗时: {end_time - start_time:.4f} 秒")
        return result
    return wrapper

@timer
def example_function(n):
    time.sleep(n)
    return "Done"

# 测试用例
example_function(2)
# 输出: 函数 example_function 运行耗时: 2.00xx 秒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

答案: 这是一个装饰器的经典用例。@functools.wraps 是一个好习惯,它确保被装饰的函数保留其名称和文档字符串。time.perf_counter() 提供了最高精度的计时。

# 7. 写一个函数,检查传入的文件路径是否存在,如果存在则读取文件内容

import os

def read_file_safely(file_path):
    if not os.path.exists(file_path):
        return f"错误:文件 {file_path} 不存在。"
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            content = file.read()
        return content
    except Exception as e:
        return f"读取文件时发生错误: {e}"

# 测试用例(需要准备一个 test.txt 文件)
print(read_file_safely("test.txt"))
print(read_file_safely("nonexistent_file.txt"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

答案: 这道题考察文件操作和异常处理。先检查路径是否存在是第一步,但使用 with open 并捕获可能的异常(如编码错误)同样重要,这体现了代码的健壮性。

# 8. 对字典列表进行排序(根据某个共同的键)

def sort_dict_list(lst, key):
    return sorted(lst, key=lambda x: x[key])

# 测试用例
data = [
    {'name': 'Alice', 'age': 25},
    {'name': 'Bob', 'age': 30},
    {'name': 'Charlie', 'age': 22}
]
print(sort_dict_list(data, 'age'))
# 输出: [{'name': 'Charlie', 'age': 22}, {'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}]
1
2
3
4
5
6
7
8
9
10
11

答案sorted() 函数的 key 参数非常强大,它接受一个函数来指定排序的依据。这里使用 lambda 函数从每个字典中提取出指定的键的值作为排序键。

# 9. 合并两个字典

def merge_dicts(dict1, dict2):
    # 在Python 3.5+中,可以使用 ** 操作符解包
    return {**dict1, **dict2}

# 另一种方式(更新dict1)
# def merge_dicts(dict1, dict2):
#     dict1.update(dict2)
#     return dict1

# 测试用例
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
print(merge_dicts(d1, d2)) # 输出: {'a': 1, 'b': 3, 'c': 4}
1
2
3
4
5
6
7
8
9
10
11
12
13

答案{**dict1, **dict2} 是Python 3.5+引入的最简洁的方法。如果键有冲突,后者(dict2)的值会覆盖前者(dict1)的值。

# 10. 列表推导式:将一个列表中的整数转换为字符串,并过滤掉偶数

def convert_and_filter(lst):
    return [str(x) for x in lst if x % 2 != 0]

# 测试用例
print(convert_and_filter([1, 2, 3, 4, 5, 6])) # 输出: ['1', '3', '5']
1
2
3
4
5

答案: 列表推导式是Python的核心特性,可以简洁地实现mapfilter操作。if x % 2 != 0 是过滤条件,str(x) 是转换操作。

# 11. 实现一个上下文管理器,用于文件操作

class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode, encoding='utf-8')
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()
        # 如果返回True,则不会抛出异常。返回None或False则会抛出。
        # 这里我们选择不处理异常,让其正常抛出
        return False

# 测试用例
with FileManager('test.txt', 'w') as f:
    f.write("Hello, Context Manager!")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

答案: 上下文管理器通过 __enter____exit__ 两个魔法方法实现。with 语句会自动管理资源的获取和释放(如打开和关闭文件),即使发生异常也能保证 __exit__ 方法被调用,从而避免资源泄漏。

# 12. 使用递归列出目录下的所有文件(考察os.walk)

import os

def list_files_recursively(directory):
    file_list = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            # 连接根目录和文件名,形成完整路径
            file_path = os.path.join(root, file)
            file_list.append(file_path)
    return file_list

# 测试用例
files = list_files_recursively('.') # 列出当前目录下所有文件
for f in files[:5]: # 打印前5个
    print(f)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

答案os.walk(directory) 是遍历目录树的标准方法,它返回一个生成器,每次产生一个三元组 (当前文件夹路径, 子文件夹列表, 文件列表)。这比手动写递归要简单和安全得多。

# 13. 计算一个数的阶乘

def factorial(n):
    if n < 0:
        raise ValueError("阶乘只能计算非负整数。")
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

# 测试用例
print(factorial(5)) # 输出: 120
print(factorial(0)) # 输出: 1
1
2
3
4
5
6
7
8
9
10
11

答案: 使用循环是计算阶乘最有效的方式。注意处理边界情况:n=0 时结果为1,n为负数时应该抛出异常。

# 14. 过滤出列表中的所有偶数

def filter_even_numbers(lst):
    return list(filter(lambda x: x % 2 == 0, lst))
    # 或者使用列表推导式: [x for x in lst if x % 2 == 0]

# 测试用例
print(filter_even_numbers([1, 2, 3, 4, 5, 6, 7, 8])) # 输出: [2, 4, 6, 8]
1
2
3
4
5
6

答案: 展示了 filter 函数的使用,它接受一个函数和一个可迭代对象,并返回一个迭代器,其中包含使函数返回True的所有元素。列表推导式是更Pythonic的替代方案。

# 15. 将两个列表合并为一个字典(一个列表为键,另一个为值)

def lists_to_dict(keys, values):
    return dict(zip(keys, values))

# 测试用例
keys = ['name', 'age', 'city']
values = ['Alice', 25, 'New York']
print(lists_to_dict(keys, values))
# 输出: {'name': 'Alice', 'age': 25, 'city': 'New York'}
1
2
3
4
5
6
7
8

答案zip(keys, values) 将两个列表“压缩”成一个可迭代对象,其中每个元素都是一个 (key, value) 元组。dict() 函数可以直接接受这种元组序列来创建字典。

# 16. 实现一个简单的队列(FIFO)类

class Queue:
    def __init__(self):
        self.items = []

    def is_empty(self):
        return len(self.items) == 0

    def enqueue(self, item):
        self.items.insert(0, item) # 在列表头部插入,尾部就是队首

    def dequeue(self):
        if not self.is_empty():
            return self.items.pop() # 从列表尾部弹出
        else:
            raise IndexError("从空队列中出队")

    def size(self):
        return len(self.items)

# 测试用例
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
print(q.dequeue()) # 输出: 1
print(q.dequeue()) # 输出: 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

答案: 使用列表模拟队列。enqueue(入队)在列表头部(index=0)插入元素,dequeue(出队)从列表尾部弹出元素。注意检查队列是否为空。

# 17. 去除字符串首尾的空格(不能使用str.strip())

def custom_strip(s):
    start = 0
    end = len(s) - 1

    # 找到第一个非空格字符的索引
    while start <= end and s[start] == ' ':
        start += 1

    # 找到最后一个非空格字符的索引
    while end >= start and s[end] == ' ':
        end -= 1

    return s[start:end+1]

# 测试用例
print(custom_strip("   hello world   ")) # 输出: "hello world"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

答案: 手动实现 strip() 功能。通过两个循环分别找到字符串开头和末尾非空格字符的索引,然后使用切片返回中间的部分。

# 18. 计算字符串中元音字母的个数

def count_vowels(s):
    vowels = "aeiouAEIOU"
    count = 0
    for char in s:
        if char in vowels:
            count += 1
    return count

# 测试用例
print(count_vowels("Hello World")) # 输出: 3 (e, o, o)
1
2
3
4
5
6
7
8
9
10

答案: 遍历字符串中的每个字符,检查它是否存在于元音字符串中。注意要同时包含大小写字母。

# 19. 将一段文本拆分成单词,并统计每个单词的出现次数

from collections import Counter
import re

def word_count(text):
    # 使用正则表达式找到所有单词(忽略标点)
    words = re.findall(r'\b\w+\b', text.lower())
    return dict(Counter(words))

# 测试用例
text = "Hello world, hello Python! World of Python."
print(word_count(text))
# 输出: {'hello': 2, 'world': 2, 'python': 2, 'of': 1}
1
2
3
4
5
6
7
8
9
10
11
12

答案: 使用正则表达式 r'\b\w+\b' 可以很好地处理单词边界和标点符号。text.lower() 将所有文本转为小写,确保 "Hello" 和 "hello" 被算作同一个单词。

# 20. 使用生成器实现一个斐波那契数列

def fibonacci_generator():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 测试用例
fib_gen = fibonacci_generator()
for _ in range(10):
    print(next(fib_gen), end=" ")
# 输出: 0 1 1 2 3 5 8 13 21 34
1
2
3
4
5
6
7
8
9
10
11

答案: 生成器使用 yield 关键字,它可以产生一个值并暂停函数执行,下次调用时从暂停处继续。这对于生成无限序列(如斐波那契数列)非常高效,因为它不会一次性计算所有值并存储在内存中。

# Java

好的,以下是20道针对软件测试工程师岗位的Java数组和字符串高频手撕代码面试题及其答案。

# 1. 反转字符串

public String reverseString(String str) {
    if (str == null || str.length() <= 1) {
        return str;
    }
    return new StringBuilder(str).reverse().toString();
}

// 测试用例
// System.out.println(reverseString("hello")); // 输出: "olleh"
// System.out.println(reverseString("")); // 输出: ""
// System.out.println(reverseString(null)); // 输出: null
1
2
3
4
5
6
7
8
9
10
11

# 2. 判断字符串是否是回文

public boolean isPalindrome(String str) {
    if (str == null) return false;
    
    str = str.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
    int left = 0, right = str.length() - 1;
    
    while (left < right) {
        if (str.charAt(left) != str.charAt(right)) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

// 测试用例
// System.out.println(isPalindrome("A man, a plan, a canal: Panama")); // true
// System.out.println(isPalindrome("race a car")); // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3. 找出数组中第二大的数

public int findSecondLargest(int[] arr) {
    if (arr == null || arr.length < 2) {
        throw new IllegalArgumentException("数组长度至少为2");
    }
    
    int first = Integer.MIN_VALUE;
    int second = Integer.MIN_VALUE;
    
    for (int num : arr) {
        if (num > first) {
            second = first;
            first = num;
        } else if (num > second && num != first) {
            second = num;
        }
    }
    
    if (second == Integer.MIN_VALUE) {
        throw new IllegalArgumentException("没有第二大的数");
    }
    
    return second;
}

// 测试用例
// System.out.println(findSecondLargest(new int[]{12, 35, 1, 10, 34, 1})); // 34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 4. 找出数组中缺失的最小正整数

public int firstMissingPositive(int[] nums) {
    int n = nums.length;
    
    // 第一次遍历,将每个正整数放到正确的位置上
    for (int i = 0; i < n; i++) {
        while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
            int temp = nums[nums[i] - 1];
            nums[nums[i] - 1] = nums[i];
            nums[i] = temp;
        }
    }
    
    // 第二次遍历,找到第一个位置不正确的数
    for (int i = 0; i < n; i++) {
        if (nums[i] != i + 1) {
            return i + 1;
        }
    }
    
    return n + 1;
}

// 测试用例
// System.out.println(firstMissingPositive(new int[]{1, 2, 0})); // 3
// System.out.println(firstMissingPositive(new int[]{3, 4, -1, 1})); // 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 5. 合并两个有序数组

public void mergeSortedArrays(int[] nums1, int m, int[] nums2, int n) {
    int i = m - 1, j = n - 1, k = m + n - 1;
    
    while (i >= 0 && j >= 0) {
        if (nums1[i] > nums2[j]) {
            nums1[k--] = nums1[i--];
        } else {
            nums1[k--] = nums2[j--];
        }
    }
    
    while (j >= 0) {
        nums1[k--] = nums2[j--];
    }
}

// 测试用例
// int[] nums1 = new int[]{1, 2, 3, 0, 0, 0};
// int[] nums2 = new int[]{2, 5, 6};
// mergeSortedArrays(nums1, 3, nums2, 3);
// System.out.println(Arrays.toString(nums1)); // [1, 2, 2, 3, 5, 6]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 6. 字符串转换为整数 (atoi)

public int myAtoi(String s) {
    if (s == null || s.length() == 0) return 0;
    
    int index = 0, sign = 1, total = 0;
    
    // 去除前导空格
    while (index < s.length() && s.charAt(index) == ' ') {
        index++;
    }
    
    if (index == s.length()) return 0;
    
    // 处理符号
    if (s.charAt(index) == '+' || s.charAt(index) == '-') {
        sign = s.charAt(index) == '+' ? 1 : -1;
        index++;
    }
    
    // 转换数字
    while (index < s.length()) {
        int digit = s.charAt(index) - '0';
        if (digit < 0 || digit > 9) break;
        
        // 检查溢出
        if (Integer.MAX_VALUE / 10 < total || 
            (Integer.MAX_VALUE / 10 == total && Integer.MAX_VALUE % 10 < digit)) {
            return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
        }
        
        total = total * 10 + digit;
        index++;
    }
    
    return total * sign;
}

// 测试用例
// System.out.println(myAtoi("42")); // 42
// System.out.println(myAtoi("   -42")); // -42
// System.out.println(myAtoi("4193 with words")); // 4193
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 7. 找出数组中重复的数字

public int findDuplicate(int[] nums) {
    // 使用龟兔赛跑算法(Floyd循环检测)
    int slow = nums[0];
    int fast = nums[0];
    
    do {
        slow = nums[slow];
        fast = nums[nums[fast]];
    } while (slow != fast);
    
    // 找到循环的入口点
    slow = nums[0];
    while (slow != fast) {
        slow = nums[slow];
        fast = nums[fast];
    }
    
    return slow;
}

// 测试用例
// System.out.println(findDuplicate(new int[]{1, 3, 4, 2, 2})); // 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 8. 无重复字符的最长子串

public int lengthOfLongestSubstring(String s) {
    if (s == null || s.length() == 0) return 0;
    
    int maxLength = 0;
    Map<Character, Integer> map = new HashMap<>();
    
    for (int left = 0, right = 0; right < s.length(); right++) {
        char currentChar = s.charAt(right);
        
        if (map.containsKey(currentChar)) {
            left = Math.max(left, map.get(currentChar) + 1);
        }
        
        map.put(currentChar, right);
        maxLength = Math.max(maxLength, right - left + 1);
    }
    
    return maxLength;
}

// 测试用例
// System.out.println(lengthOfLongestSubstring("abcabcbb")); // 3
// System.out.println(lengthOfLongestSubstring("bbbbb")); // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 9. 两数之和

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        
        if (map.containsKey(complement)) {
            return new int[]{map.get(complement), i};
        }
        
        map.put(nums[i], i);
    }
    
    throw new IllegalArgumentException("No two sum solution");
}

// 测试用例
// System.out.println(Arrays.toString(twoSum(new int[]{2, 7, 11, 15}, 9))); // [0, 1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 10. 旋转数组

public void rotate(int[] nums, int k) {
    if (nums == null || nums.length == 0) return;
    
    k = k % nums.length;
    reverse(nums, 0, nums.length - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, nums.length - 1);
}

private void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

// 测试用例
// int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7};
// rotate(nums, 3);
// System.out.println(Arrays.toString(nums)); // [5, 6, 7, 1, 2, 3, 4]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 11. 验证括号有效性

public boolean isValid(String s) {
    if (s == null || s.length() % 2 != 0) return false;
    
    Stack<Character> stack = new Stack<>();
    
    for (char c : s.toCharArray()) {
        if (c == '(') {
            stack.push(')');
        } else if (c == '[') {
            stack.push(']');
        } else if (c == '{') {
            stack.push('}');
        } else if (stack.isEmpty() || stack.pop() != c) {
            return false;
        }
    }
    
    return stack.isEmpty();
}

// 测试用例
// System.out.println(isValid("()[]{}")); // true
// System.out.println(isValid("([)]")); // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 12. 寻找数组中的峰值

public int findPeakElement(int[] nums) {
    int left = 0, right = nums.length - 1;
    
    while (left < right) {
        int mid = left + (right - left) / 2;
        
        if (nums[mid] < nums[mid + 1]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    
    return left;
}

// 测试用例
// System.out.println(findPeakElement(new int[]{1, 2, 3, 1})); // 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 13. 最长公共前缀

public String longestCommonPrefix(String[] strs) {
    if (strs == null || strs.length == 0) return "";
    
    String prefix = strs[0];
    
    for (int i = 1; i < strs.length; i++) {
        while (strs[i].indexOf(prefix) != 0) {
            prefix = prefix.substring(0, prefix.length() - 1);
            if (prefix.isEmpty()) return "";
        }
    }
    
    return prefix;
}

// 测试用例
// System.out.println(longestCommonPrefix(new String[]{"flower", "flow", "flight"})); // "fl"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 14. 移动零到数组末尾

public void moveZeroes(int[] nums) {
    if (nums == null || nums.length == 0) return;
    
    int nonZeroIndex = 0;
    
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] != 0) {
            nums[nonZeroIndex++] = nums[i];
        }
    }
    
    for (int i = nonZeroIndex; i < nums.length; i++) {
        nums[i] = 0;
    }
}

// 测试用例
// int[] nums = new int[]{0, 1, 0, 3, 12};
// moveZeroes(nums);
// System.out.println(Arrays.toString(nums)); // [1, 3, 12, 0, 0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 15. 字符串的排列检查

public boolean checkInclusion(String s1, String s2) {
    if (s1.length() > s2.length()) return false;
    
    int[] s1Count = new int[26];
    int[] s2Count = new int[26];
    
    for (int i = 0; i < s1.length(); i++) {
        s1Count[s1.charAt(i) - 'a']++;
        s2Count[s2.charAt(i) - 'a']++;
    }
    
    for (int i = 0; i < s2.length() - s1.length(); i++) {
        if (matches(s1Count, s2Count)) return true;
        
        s2Count[s2.charAt(i) - 'a']--;
        s2Count[s2.charAt(i + s1.length()) - 'a']++;
    }
    
    return matches(s1Count, s2Count);
}

private boolean matches(int[] s1Count, int[] s2Count) {
    for (int i = 0; i < 26; i++) {
        if (s1Count[i] != s2Count[i]) return false;
    }
    return true;
}

// 测试用例
// System.out.println(checkInclusion("ab", "eidbaooo")); // true
// System.out.println(checkInclusion("ab", "eidboaoo")); // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 16. 最大子数组和

public int maxSubArray(int[] nums) {
    if (nums == null || nums.length == 0) return 0;
    
    int maxSoFar = nums[0];
    int maxEndingHere = nums[0];
    
    for (int i = 1; i < nums.length; i++) {
        maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }
    
    return maxSoFar;
}

// 测试用例
// System.out.println(maxSubArray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4})); // 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 17. 寻找旋转排序数组中的最小值

public int findMin(int[] nums) {
    int left = 0, right = nums.length - 1;
    
    while (left < right) {
        int mid = left + (right - left) / 2;
        
        if (nums[mid] > nums[right]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    
    return nums[left];
}

// 测试用例
// System.out.println(findMin(new int[]{3, 4, 5, 1, 2})); // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 18. 有效的字母异位词

public boolean isAnagram(String s, String t) {
    if (s.length() != t.length()) return false;
    
    int[] counter = new int[26];
    
    for (int i = 0; i < s.length(); i++) {
        counter[s.charAt(i) - 'a']++;
        counter[t.charAt(i) - 'a']--;
    }
    
    for (int count : counter) {
        if (count != 0) return false;
    }
    
    return true;
}

// 测试用例
// System.out.println(isAnagram("anagram", "nagaram")); // true
// System.out.println(isAnagram("rat", "car")); // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 19. 矩阵置零

public void setZeroes(int[][] matrix) {
    if (matrix == null || matrix.length == 0) return;
    
    boolean firstRowZero = false;
    boolean firstColZero = false;
    
    // 检查第一行是否有零
    for (int j = 0; j < matrix[0].length; j++) {
        if (matrix[0][j] == 0) {
            firstRowZero = true;
            break;
        }
    }
    
    // 检查第一列是否有零
    for (int i = 0; i < matrix.length; i++) {
        if (matrix[i][0] == 0) {
            firstColZero = true;
            break;
        }
    }
    
    // 使用第一行和第一列标记零的位置
    for (int i = 1; i < matrix.length; i++) {
        for (int j = 1; j < matrix[0].length; j++) {
            if (matrix[i][j] == 0) {
                matrix[i][0] = 0;
                matrix[0][j] = 0;
            }
        }
    }
    
    // 根据标记设置零
    for (int i = 1; i < matrix.length; i++) {
        for (int j = 1; j < matrix[0].length; j++) {
            if (matrix[i][0] == 0 || matrix[0][j] == 0) {
                matrix[i][j] = 0;
            }
        }
    }
    
    // 处理第一行
    if (firstRowZero) {
        for (int j = 0; j < matrix[0].length; j++) {
            matrix[0][j] = 0;
        }
    }
    
    // 处理第一列
    if (firstColZero) {
        for (int i = 0; i < matrix.length; i++) {
            matrix[i][0] = 0;
        }
    }
}

// 测试用例
// int[][] matrix = {{1, 1, 1}, {1, 0, 1}, {1, 1, 1}};
// setZeroes(matrix);
// System.out.println(Arrays.deepToString(matrix)); // [[1, 0, 1], [0, 0, 0], [1, 0, 1]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# 20. 字符串相乘

public String multiply(String num1, String num2) {
    if (num1.equals("0") || num2.equals("0")) return "0";
    
    int m = num1.length(), n = num2.length();
    int[] result = new int[m + n];
    
    for (int i = m - 1; i >= 0; i--) {
        for (int j = n - 1; j >= 0; j--) {
            int product = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
            int sum = product + result[i + j + 1];
            
            result[i + j + 1] = sum % 10;
            result[i + j] += sum / 10;
        }
    }
    
    StringBuilder sb = new StringBuilder();
    for (int digit : result) {
        if (!(sb.length() == 0 && digit == 0)) {
            sb.append(digit);
        }
    }
    
    return sb.length() == 0 ? "0" : sb.toString();
}

// 测试用例
// System.out.println(multiply("2", "3")); // "6"
// System.out.println(multiply("123", "456")); // "56088"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29