数组与字符串算法实战:从统计到匹配的五道经典题目解析

79 阅读5分钟

在编程面试和算法学习中,数组和字符串相关的问题出现频率非常高。本文将分享五道经典的数组与字符串算法题目,包含完整的代码实现、测试结果和详细解析。

题目1:找出数组中两个只出现一次的数字

问题描述

给定一个整型数组,其中除了两个数字只出现一次外,其他数字都出现了两次。请找出这两个只出现一次的数字。

代码实现

def find_two(nums):
    if len(nums) <= 0:
        return None
    dc = {} # 空字典,键:值 —— 元素:出现次数
    for num in nums:
        if num not in dc.keys():
            dc[num] = 1 # 数字num第一次出现
        else:
            dc[num] += 1 # 出现次数+1
    result = [] # 存放结果
    for key, value in dc.items():
        if value == 1: # 出现次数==1
            result.append(key)
    return result

# 测试用例
ls1 = [1,4,1,6]
ls2 = [1,2,3,3,2,9]
print(f"数组{ls1}的返回值为:{find_two(ls1)}")
print(f"数组{ls2}的返回值为:{find_two(ls2)}")

运行结果

数组[1, 4, 1, 6]的返回值为:[4, 6]
数组[1, 2, 3, 3, 2, 9]的返回值为:[1, 9]

算法分析

· 时间复杂度:O(n),需要遍历数组两次 · 空间复杂度:O(n),使用字典存储元素出现次数 · 核心思路:利用哈希表统计每个数字的出现次数,然后筛选出出现次数为1的数字

题目2:找出数组中出现次数超过一半的数字

问题描述

给定一个长度为n的数组,如果数组中有一个数字出现的次数超过数组长度的一半,就输出这个数字,否则输出-1。

代码实现

def find_one(nums):
    if len(nums) == 0: # 数组为空
        return -1
    dc = {} # 空字典,键:值 —— 元素:出现次数
    max_num = 0 # 记录最多的次数,初始化为0
    for num in nums:
        if num not in dc.keys():
            dc[num] = 1 # 数字num第一次出现
        else:
            dc[num] += 1 # 出现次数+1
        if dc[num] > max_num:  # 更新最大出现次数
            max_num = dc[num]
        if max_num > len(nums) // 2: # 出现了超过数组长度一半的元素
            return num
    return -1

# 测试用例
ls = [1,2,3,2,2,2,5,4,2]
print(find_one(ls))

运行结果

2

算法分析

· 时间复杂度:O(n),只需遍历数组一次 · 空间复杂度:O(n),使用字典存储元素出现次数 · 优化点:在遍历过程中实时检查是否有数字出现次数超过一半,可以提前结束循环

题目3:找出缺失的最小正整数

问题描述

给定一个无重复元素的整数数组nums,请找出其中没有出现的最小的正整数。

代码实现

def find_min(nums):
    if len(nums) == 0: # 如果数组为空,返回1
        return 1
    sort_nums = sorted(nums) # 升序排序
    sort_nums = [num for num in sort_nums if num > 0]
    item = 1 # 从1开始进行判断
    for num in sort_nums:
        if item != num:
            return item
        item += 1
    return item

# 测试用例
nums1 = [1,0,2]
nums2 = [-2,3,4,1,5]
nums3 = [4,5,6,8,9]
print(find_min(nums1))
print(find_min(nums2))
print(find_min(nums3))

运行结果

3
2
1

算法分析

· 时间复杂度:O(n log n),主要消耗在排序操作 · 空间复杂度:O(n),需要存储过滤后的正数数组 · 核心思路:先过滤出正数并排序,然后从1开始检查哪个正整数缺失

题目4:查找字符串数组的最长公共前缀

问题描述

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串""。

代码实现

def longest_pre(strs):
    if not strs: # 如果数组strs为空
        return ""  # 返回空字符串
    # 以第一个字符串为基准进行判断
    for i in range(len(strs[0])):
        # 比较其它字符串的对应位置
        for s in strs[1:]:
            if i >= len(s) or s[i] != strs[0][i]: # 不匹配
                return strs[0][:i]
    # 所有字符串都匹配第一个字符串
    return strs[0]

# 测试用例
strs1 = ["flower", "flow", "flight"]
strs2 = ["dog", "racecar", "car"]
print(longest_pre(strs1))
print(longest_pre(strs2))

运行结果

fl

算法分析

· 时间复杂度:O(m*n),其中m是字符串平均长度,n是字符串个数 · 空间复杂度:O(1),只使用了常数级别的额外空间 · 核心思路:以第一个字符串为基准,逐个字符比较其他字符串的对应位置

题目5:判断括号字符串是否有效

问题描述

给定一个只包括'(',')','{','}','[',']'的字符串s,判断字符串是否有效。有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合
  2. 左括号必须以正确的顺序闭合

代码实现

def judge(s):
    stack = [] # 栈
    # 定义括号匹配关系
    dc = {
        ')':'(', '}':'{',']':'['
    }
    for char in s:
        if char in dc: # 如果是右括号,检查栈顶元素是否匹配
            top = stack.pop()
            if top != dc[char]: # 不匹配
                return False
        else: # 如果是左括号,入栈
            stack.append(char)
    return not stack

# 测试用例
s1 = "()[]{}"
s2 = "(]"
s3 = "([)]"
s4 = "{[]}"
print(judge(s1))
print(judge(s2))
print(judge(s3))
print(judge(s4))

运行结果

True
False
False
True

算法分析

· 时间复杂度:O(n),只需遍历字符串一次 · 空间复杂度:O(n),最坏情况下栈的大小与字符串长度成正比 · 核心思路:使用栈数据结构,遇到左括号入栈,遇到右括号检查栈顶是否匹配

总结

通过这五道题目,我们学习了多种处理数组和字符串的算法技巧:

  1. 哈希表统计:适用于需要统计元素频率的问题
  2. 排序+遍历:适用于需要有序处理的场景
  3. 逐字符比较:适用于字符串前缀、后缀匹配问题
  4. 栈的应用:适用于需要检查嵌套结构有效性的问题