在编程面试和算法学习中,数组和字符串相关的问题出现频率非常高。本文将分享五道经典的数组与字符串算法题目,包含完整的代码实现、测试结果和详细解析。
题目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,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合
- 左括号必须以正确的顺序闭合
代码实现
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),最坏情况下栈的大小与字符串长度成正比 · 核心思路:使用栈数据结构,遇到左括号入栈,遇到右括号检查栈顶是否匹配
总结
通过这五道题目,我们学习了多种处理数组和字符串的算法技巧:
- 哈希表统计:适用于需要统计元素频率的问题
- 排序+遍历:适用于需要有序处理的场景
- 逐字符比较:适用于字符串前缀、后缀匹配问题
- 栈的应用:适用于需要检查嵌套结构有效性的问题