人工智能 – python算法之 字符串“相减”:Hash字典法的实战运用
1. 引子
我们知道字符串可以相加
s1 = 'abc'
s2 = 'def'
s = s1 + s2
print(s) # 结果:abcdef
但是直接相减 s1-s2是不允许的,那么如何进行字符串相减呢?
比如下面两个问题:
- 1.输入s1 = ‘abcdefghijk’, s2 = ‘aceac’, 找出s1中不包含s2的所有值
- 2.已知字符串列表li, 每个元素存放的是用户名、手机号、邮箱号、编程语言。
如:li = [‘令狐冲 +8618812345678 linghu@163.com Java’, ‘任盈盈 +8617712345678 renying@163.com Python’, ‘风清扬 16612345678’, ‘东方不败 java’]
要求将元素里:空格' '
全替换为分号;
,+86
去掉,@163.com
替换为@qq.com
,Java
替换为Python
怎么做?类似这种的怎么找思路?看完下面我写的博文全就会了,慢慢来:
2. 知识点:
replace()用法 | 解释 |
s.replace(str1, str2) | 将字符串s中的str1部分, 全替换成str2 |
s.replace(str1, str2, count) | 将字符串s中的str1部分, 替换成str2, count表最大替换数量 |
3. 例题:
输入str1 = ‘abcdefghijk’, str2 = ‘aceac’, 找出s1中不包含s2的所有值
分析:
- return str1。----- 利用str2搞str1。
- 注意:str2有重值,故为了提高效率和避免出错,一定要先对str2进行去重处理。
思路:
(1)【核心代码】设计:
- 法1:replace()替换空格法
- 法2:[:] 冒号截取法。":"语法实现删除下标为i的元素
(2)【去重】设计:
- 法1:set()法 ------- 注意:此法去重会打乱原来顺序,视情况而sort()
- 法2:遍历元素法。----- 最简单的思路,代码思想很重要!但是代码看起来不太高大尚~
代码:
(1) 【去重】:str2去重
str1 = 'abcdefghijk'
str2 = 'aceac'
# 去重(法1):---- set()法
li = list(set(str2)) # ['e', 'c', 'a']这个值是变化的,顺序不一定
li.sort(key=str2.index) # ['a', 'c', 'e']
"""
## 注:
# (1)set()可以去重,但结果不会保持保持原来的顺序。故有时候需要sort()
# (2)li = set(str2) # 结果:{'e', 'c', 'a'} 会改变原顺序。
# (3)set()操作是生成copy(),故不会改变原str2的顺序。
"""
# 去重(法2):------遍历元素法(简单但很重要)
li = []
for c in str2:
if c not in li:
li.append(c)
# test
print(li) # ['a', 'c', 'e']
(2) 【核心代码】:删减
# 删减(法1)------ replace()替换空格法
for c in li:
str1 = str1.replace(c, "")
# 删减(法2)------ 冒号截取法。
for c in li:
if c in str1:
str1= str1[:str1.index(c)] + str1[str1.index(c)+1:] # str1.index(c) 是返回c在str1中的下标。如下标是5,这里str1 = str1[:5] + str1[6:]实现了冒号截取再拼接,即:删除了元素str[5]
# test
print(str1) # bdfghijk
注1:有的去重之前可进行排序,视情况而定!
排序:
# 排序
str2 = 'aceac'
li = list(str2) # ['a', 'c', 'e', 'a', 'c']
li = sorted(li) # ['a', 'a', 'c', 'c', 'e']
注2:若没有重值,可直接删减,如:找出s1中不包含s2的所有元素
s1 = 'sfdad'
s2 = 'sfd'
s = s1.replace(s2, "")
print() # 结果 ad
for c in s2:
if c in s1:
s1= s1[:s1.index(c)] + s1[s1.index(c)+1:]
4. 补充知识点:
1、strip()
函数 | 功能 |
strip() | 去除两端的某字符。如strip(’ '),去除两端空格。 类似php:trim() |
lstrip() | 只删除左端。 类似php:ltrim() |
rstrip() | 只删除右端。 类似php:rtrim() |
s1 = 'aaabcdaaa'
s1 = s1.strip('a') # 等价 php中 trim
print(s1) # bcd
s1 = s1.lstrip('a') # 等价 php中 ltrim
print(s1) # bcdaaa
s1 = s1.rstrip('a') # 等价 php中 rtrim
print(s1) # aaabcd
str2 = " Hello World ";
str2 = str2.strip() # 去除首尾空格
print str2; # Hello World
2、ord() ----- 仅针对 ‘字符’。即ord(char) 将字符转成ASCII码进行计算
char1 = 'c'
char2 = 'd'
c = ord(char1) - ord(char2)
print(c) # # 结果:-1
print(ord('d') - ord('c')) # 结果:1
实战(自编)
已知字符串列表li, 每个元素存放的是用户名、手机号、邮箱号、编程语言。
如:li = [‘令狐冲 +8618812345678 linghu@163.com Java’, ‘任盈盈 +8617712345678 renying@163.com Python’, ‘风清扬 16612345678’, ‘东方不败 java’]
要求将元素里:空格' '
全替换为分号;
,+86
去掉,@163.com
替换为@qq.com
,Java
替换为Python
思路:
- 先考虑一个string怎么处理;
- 之后,因为看到字符串列表了,要马上想到用字典,会利用Hash!
代码:
li = ['令狐冲 +8618812345678 linghu@163.com Java', '任盈盈 +8617712345678 renying@163.com Python', '风清扬 16612345678', '东方不败 Java']
dict = {' ' : ';',
'+86' : '',
'@163.com' : '@qq.com',
'Java' : 'Python'
}
new_li = []
for str in li:
for key in dict:
str = str.replace(key, dict[key])
new_li.append(str)
print(new_li)
运行结果:
['令狐冲;18812345678;linghu@qq.com;Python', '任盈盈;17712345678;renying@qq.com;Python', '风清扬;16612345678', '东方不败;Python']
这个用到的就是上面 问题1(连续型)。若遇到随机+重值型的字符串列表参考上面问题2,原理相同。
附:如何查找一个字符串s1 包含另一个字符串s2?
【思路】:可用 RK(Rabin-Karp)算法。
先对s2求hash;再对s1每个长度为len(s2)的子字符串求hash。用hash比较两个hash是否相等。