替换空格
题目:请实现一个函数,将一个字符串中的空格替换成‘%20’。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
想: 先想,不急于做题
- 替换空格,正则就可以了
# -*- coding:utf-8 -*-
import re
class Solution:
# s 源字符串
def replaceSpace(self, s):
# write code here
return re.sub(' ','%20',s)
小小知识课堂
尊重知识产权:
re
大家没有疑问吗?为什么我们需要正则表达式呢?我们处在信息交流的虚拟世界里,信息不可避免的会使用文字作为载体。我们希望文字的处理快捷方便。
‘re'模块提供了几个方法对输入的字符串进行确切的查询。我们将会要讨论的方法有:
•re.match()#匹配
•re.search()#搜索
•re.findall()#寻找
使用re.match查找 – 匹配开始
match()方法的工作方式是只有当被搜索字符串的开头匹配模式的时候它才能查找到匹配对象。
举个例子,对字符串‘dog cat dog'调用mathch()方法,查找模式‘dog'将会匹配:
re.match(r'dog', 'dog cat dog')
<_sre.SRE_Match object at 0xb743e720<
但是,如果我们对同一个字符串调用math()方法,查找模式‘cat',则不会找到匹配。
re.match(r'cat', 'dog cat dog')
#没有任何的返回
使用re.search查找 – 匹配任意位置
search()方法和match()类似,不过search()方法不会限制我们只从字符串的开头查找匹配,因此在我们的示例字符串中查找‘cat'会查找到一个匹配:
search(r'cat', 'dog cat dog')
>>> match.group(0)
'cat'
然而search()方法会在它查找到一个匹配项之后停止继续查找,因此在我们的示例字符串中用searc()方法查找‘dog'只找到其首次出现的位置。
使用 re.findall – 所有匹配对象
目前为止在Python中我使用的最多的查找方法是findall()方法。当我们调用findall()方法,我们可以非常简单的得到一个所有匹配模式的列表,而不是得到match的对象(我们会在接下来更多的讨论match对象)。对我而言这更加简单。对示例字符串调用findall()方法我们得到:
['dog', 'dog']
>>> re.findall(r'cat', 'dog cat dog')
['cat']
使用 match.start 和 match.end 方法
例如,match对象可以告诉我们匹配的内容在原始字符串中的开始和结束位置:
>>> match = re.search(r'dog', 'dog cat dog')
>>> match.start()
>>> match.end()
sub(pat,repl,string) :用repl替换 pat匹配项
(留的是中间的,因为中间在中心)
re.sub('a','A','abcasd') *#找到a用A替换,后面见和group的配合使用*
'AbcAsd'
compile(pattern):创建模式对象
import re
pat=re.compile('A')
m=pat.search('CBA') #等价于 re.search('A','CBA')
print m
<_sre.SRE_Match object at 0x9d690c8> #匹配到了,返回MatchObject(True)
m=pat.search('CBD')
print m
None
escape(string) :对字符串里面的特殊字符串进行转义
re.escape('www.dxy.cn')
#'www\\.dxy\\.cn' #转义
re.escape('www.dxy.,cn')
#'www\\.dxy\\.\\,cn' #转义
函数的方法
group:获取子模式(组)的匹配项
pat = re.compile(r'www\.(.*)\.(.*)') #用()表示1个组,2个组
m = pat.match('www.dxy.com')
m.group() #默认为0,表示匹配整个字符串
'www.dxy.com'
m.group(1) #返回给定组1匹配的子字符串
'dxy'
m.group(2)
'com'
start:给定组匹配项的开始位置
m.start(2) #组2开始的索引
8
end:给定组匹配项的结束位置
m.end(2) #组2结束的索引
11
span: 给定组匹配项的开始结束位置
m.span(2) #组2开始、结束的索引
(8, 11)
数量词
“*” :0次或多次
( 乘0会变成0)
>>> pat = re.compile('[abc]*')
>>> pat.match('abcabcdefabc').group()
'abcabc' #2次
>>> pat.search('abcabcdefabc').group()
'abcabc' #2次
>>> pat.findall('abcabcdefabc')
['abcabc', '', '', '', 'abc', ''] #2次和1次,因为有0次,所以匹配了''
字符串的排列
输入一个字符串,,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
小小知识课堂
python中itertools里的product和permutation
平时经常碰到全排列或者在n个数组中每个数组选一个值组成的所有序列等等问题,可以用permutation和product解决,很方便,所以在此mark一下吧
from itertools import *
if __name__ == '__main__':
for j in permutations([2,5,6]):
print(j)
'''
(2, 5, 6)
(2, 6, 5)
(5, 2, 6)
(5, 6, 2)
(6, 2, 5)
(6, 5, 2)
'''
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]
for i in product(list1,list2,list3):
print(i)
'''
(1, 4, 7)
(1, 4, 8)
(1, 4, 9)
(1, 5, 7)
(1, 5, 8)
(1, 5, 9)
(1, 6, 7)
(1, 6, 8)
(1, 6, 9)
(2, 4, 7)
(2, 4, 8)
(2, 4, 9)
(2, 5, 7)
(2, 5, 8)
(2, 5, 9)
(2, 6, 7)
(2, 6, 8)
(2, 6, 9)
(3, 4, 7)
(3, 4, 8)
(3, 4, 9)
(3, 5, 7)
(3, 5, 8)
(3, 5, 9)
(3, 6, 7)
(3, 6, 8)
(3, 6, 9)
'''
#[list2]*3表示[list2,list2,list2]
#最前面的*号表示将[list2,list2,list2]列表解析成独立的参数
#也就是相当于入参是(list2,list2,list2)
for i in product(*[list2]*3):
print(i)
'''
(4, 4, 4)
(4, 4, 5)
(4, 4, 6)
(4, 5, 4)
(4, 5, 5)
(4, 5, 6)
(4, 6, 4)
(4, 6, 5)
(4, 6, 6)
(5, 4, 4)
(5, 4, 5)
(5, 4, 6)
(5, 5, 4)
(5, 5, 5)
(5, 5, 6)
(5, 6, 4)
(5, 6, 5)
(5, 6, 6)
(6, 4, 4)
(6, 4, 5)
(6, 4, 6)
(6, 5, 4)
(6, 5, 5)
(6, 5, 6)
(6, 6, 4)
(6, 6, 5)
(6, 6, 6)
'''
所以:
# -*- coding:utf-8 -*-
import itertools
class Solution:
def Permutation(self, ss):
# write code here
if not ss:
return []
return sorted(list(set(map(''.join, itertools.permutations(ss)))))
除去这些,我们还可以递归。
尊重知识产权:
我们可以先根据这个实际的例子想想,怎样才能无遗漏的输出全排列
-
两个数就不用说了,对于
12,只有12和21两种 -
三个数,比如
123,我们先分为三种情况,就是1开头,2开头和3开头- 对于
1开头的情况,剩下2和3,这就回到了两个数的排列 - 对于
2开头的情况,剩下1和3,这也回到了两个数的排列 3开头的情况同理
- 对于
-
四个数,先按照开头分为四种情况,然后按照三个数的排列去处理
-
.....
-
以此类推
你可能已经看出来了,这就是一个递归。就好像求斐波那契数列的某一个元素,我们要先求出前面的;要想求出前面的,我们就要求出更前面的。记 “斐波那契数列的第 n 位” 这件事为 F(n),则有 F(n) = F(n - 1) + F(n - 2)
类似地,记 “求出 n 个字符串的全排列” 这件事为 P(n),则有 P(n) = 分别以这n个字符之一开头 + P(n - 1)。其中,P(n - 1) 表示去掉那个开头字符的剩余字符串的全排列。哪怕只有两个字符,比如对于上面例子中的 12,同样符合这一条结论
以 'abc' 为例,执行步骤如下:
给出 abc
1. a 作为开头 -> 求 bc 全排列 -> 得到 bc 和 cb -> 与 a 合并 -> 得到 abc 和 acb
2. b 作为开头 -> 求 ac 全排列 -> 得到 ac 和 ca -> 与 b 合并 -> 得到 bac 和 bca
3. c 作为开头 -> 求 ab 全排列 -> 得到 ab 和 ba -> 与 c 合并 -> 得到 cab 和 cba
-
注意,这只是其中一种实现方式。后面我们还会看到另一种实现
-
首先我们来想一下公共逻辑是什么。对于一个字符串,我们取出一个字符作为开头,然后对去掉这个开头字符的剩余字符串继续求全排列。求出来之后,与取到的字符合并起来就行
-
对于
P(n)来说,我们要取出一个字符作为开头,而且原始的字符串可能本身就含有重复的字符。在代码中,我们可以通过开头字符在原字符串中的索引来区分 -
对于我们封装的函数,可以直接使用字符串作为参数。这是因为,在获取剩余字符串全排列,即
P(n - 1)时,我们并不关心去掉的那个,用作开头的字符是什么,只需要关心现在我们要生成谁的全排列就好 -
因此,我们需要在递归调用时,传入去掉那个用作开头的字符之后的,剩余字符串。这个很容易实现,如果我们知道了去掉的那个字符的索引,那我们就可以用
str.slice(0, i)来获取这个字符之前的字符串,用str.slice(i + 1, str.length)来获取这个字符之后的字符串 (注意,slice方法的第一个参数是包含的,第二个不包含。如果i本身就是0,那么取到的是 空字符串),拼接在一起就可以作为递归调用的参数 -
跳出条件也不难想,只要传入的参数长度为
1或0,直接返回即可 -
另外,每次调用,我们都需要一个数组来保存根据当前参数生成的全排列。代码如下
代码:
class Solution:
def Permutation(self, ss):
# write code here
#首先呢?按字典打印,得先排序
ss = list(ss)
if len(ss) == 0:
return None
if len(ss) == 1:
return ss[0]
save_val = []
for i in range(len(ss)):
pre = ss[:i]+ss[i+1:]
rep = self.Permutation(pre)
#到临界点了,开始返了
for j in rep:
# print(j)
save_val.append(ss[i]+j)
map(''.join, save_val[-1])
return save_val
a = Solution()
b = a.Permutation('abc')
print(b)
第一个只出现一次的字符
题目:在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置。
# -*- coding:utf-8 -*-
class Solution:
def FirstNotRepeatingChar(self, s):
# write code here
s = list(s)
if len(s)==0:
return -1
for i in range(len(s)):
if s.count(s[i])==1:
return i
return -1
左旋转字符串
题目:汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
# -*- coding:utf-8 -*-
class Solution:
def LeftRotateString(self, s, n):
# write code here
s1 = s[n:]+s[:n]
return s1
翻转单词顺序列
题目:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
# -*- coding:utf-8 -*-
class Solution:
def ReverseSentence(self, s):
# write code here
s = s.split(' ')
return ' '.join(s[::-1])
小小知识课堂
split()是指按某某切某字符为数组
比如:
a = 'a v s'
print(a.split(' '))
# ['a', 'v', 's']
[Finished in 0.3s]
而与list()不同
list()
a = 'a v s'
print(list(a))
#['a', ' ', 'v', ' ', 's']
[Finished in 0.3s]
把字符串转换成整数
题目:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
例子:
>>> s1='123'
>>> s2='1.23'
>>> s3=''
>>> s4=None
>>> int(s1)
123
>>> int(s2)
ValueError
>>> int(s3)
ValueError
>>> int(s4)
TypeError
>>> float(s1)
123.0
>>> float(s2)
1.23
>>> float(s3)
ValueError
>>> float(s4)
TypeError
# -*- coding:utf-8 -*-
class Solution:
def StrToInt(self, s):
# write code here
if len(s)==0:
return 0
val = ['0','1','2','3','4','5','6','7','8','9']
if s[0]=='+':
s = s[1:]
for i in range(len(s)):
if s[i] not in val:
return 0
d = 0
for j in range(len(s)):
d = d+int(s[j])*10**(len(s)-1-j)
return d
elif s[0]=='-':
s = s[1:]
for i in range(len(s)):
if s[i] not in val:
return 0
d = 0
for j in range(len(s)):
d = d+int(s[j])*10**(len(s)-1-j)
return -d
else:
for i in range(len(s)):
if s[i] not in val:
return 0
d = 0
for j in range(len(s)):
d = d+int(s[j])*10**(len(s)-1-j)
return d
正则表达式匹配
题目:请实现一个函数用来匹配包括'.'和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配。
这题可能比较难,我一开始没有想出来。
- 字符串为空、模式也为空,为
True - 字符串为空,模式为空,为
Flase - 模式中的第一个字符为
.或是与字符串第一个字符相同,重复 - 如果模式中的第二个字符为
*- 模式中的第一个字符为
.或是与字符串第一个字符相同- 出现0次-----即返回
self.match(s,pattern[2:]) - 出现1次----即返回
self.match(s[1:],pattern[2:]) - 出现N次---即返回
self.match(s[1:],pattren[:])
- 出现0次-----即返回
- 模式中的第一个字符不为
.或是与字符串第一个字符不相同- 出现0次---即返回
self.match(s,pattern[2:])
- 出现0次---即返回
- 模式中的第一个字符为
代码:
# -*- coding:utf-8 -*-
class Solution:
def match(self, s, pattern):
if (len(s) == 0 and len(pattern) == 0):
return True
if (len(s) > 0 and len(pattern) == 0):
return False
if (len(pattern) > 1 and pattern[1] == '*'):
if (len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.')):
return (self.match(s, pattern[2:])
or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern))
else:
return self.match(s, pattern[2:])
if (len(s) > 0 and (pattern[0] == '.' or pattern[0] == s[0])):
return self.match(s[1:], pattern[1:])
return False