人工智能 – 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.comJava替换为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.comJava替换为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是否相等。