1.替换空格
问题描述
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
考察点:字符串匹配
思路1 创建新的字符串存最终结果(以下采用2)
- 1st顺序遍历字符串,确定除空格外字符串长度
- 2nd顺序遍历字符串,顺序存储,碰到字符串就直接存储,空格就存‘20%’
思路2 在原数组上进行扩充
- 顺序遍历字符串,确定空格个数,确定新字符串长度
- 逆序遍历字符串,逆序存储,碰到字符串就直接存储,空格就存‘20%’
class Solution11:
def replaceSpace(self, s):
# write code here
r=""
s=s.split(" ")
n=len(s)
#取除最后一个字符外的所有字符
for i in s[:n-1]:
print i
r=r+i+"%20"
#将最后一个字符加入修改后的字符串
r+=s[n-1]
return r
if __name__ == '__main__':
s = Solution11()
print s.replaceSpace("123 hello 234")
123
hello
123%20hello%20234
2.二进制中1的个数
问题描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
考察点:位运算
- 有符号数,正(首位0)、负(首位1)
- 二进制中的5中运算:与(&)、或(|)、异或(^,相异为1)、左移(<<)、右移(>>)
- 左移(m<<n):将m左移n位,左侧的舍去,右侧补0。
- 右移(m>>n):将m左移n位,右侧舍去,左侧补0/符号位(若为有符号数)。
- 二进制补码:正数(不变)、负数(除符号位外,其余按位取反,然后再加1)
思路
- 可能陷入死循环的解法:从n的2进制形式的最右边开始判断是不是1。(跟1做“与&”) 但是:若输入时负数会陷入死循环,因为负数右移时,在最高位补得是1,那么会有无数个1了。
- 正解思想:将待比较的数‘1’左移(其实后来就不是1了),和n的每位进行位与,来判断1的个数。 可以避免原数右移,可能增加1的情况。
- 最优解思想:把一个整数减去1,再和原整数做“与”,会把该整数最右边一个1变为0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。 这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0. 那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
# 正解
# private static int NumberOf1_low(int n) {
# int count = 0;
# int flag = 1;
# while (flag != 0) {
# if ((n & flag) != 0) {
# count++;
# }
# flag = flag << 1;
# }
# return count;
# }
class Solution2:
# 最优解
def NumberOf1(self, n):
# write code here
count = 0
if n<0:
# 把负号去掉,0xFFFFFFFF代表一个16进制数,转为2进制为:32个1.
n=n&0xFFFFFFFF
while n:
n = n&(n-1)
count+= 1
return count
if __name__ == '__main__':
s = Solution2()
print s.NumberOf1(-54)
28
3.字符串的排列
问题描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
考察点:字符串的全排列
思路1
- 将字符串分为两部分:首字符+其后的所有字符;求其后字符的全排列
- 拿第一个字符与其后的字符逐个交换
class Solution:
def Permutation(self,ss):
if not ss:
return []
if len(ss)==1:
# 返回列表形式的字符串
return list(ss)
allList = []
charList = list(ss)
charList.sort() #按字典顺序进行排列,不去重
for i in range(len(charList)):
# 限制i>0 : 防止charList[i-1]下标越界
if i>0 and charList[i]==charList[i-1]:
continue # 忽略重复的字符
#Permutation():乱序,接受array类型及int类型的输入。
#shuffle():乱序,只接受array类型输入。
temp = self.Permutation(''.join(charList[:i])+''.join(charList[i+1:]))
for j in temp:
allList.append(charList[i]+j)
return allList
s = Solution()
s.Permutation('abc')
['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
4.第一个只出现一次的字符
问题描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1
考察点:字符串的统计
思路1:O(n)
- 用字典统计每个字符出现的次数(自己统计)
- 按顺序,以str中字符为key,判断字典中统计的出现次数是否为1,是则输出下标。
思路2: 更快
- 用‘内置方法’统计字符串中字符出现的次数count()
class Solution:
def FirstNotRepeatingChar(self, s):
# write code here
sdict = {}
for i in range(len(s)):
if sdict.has_key(s[i]):
sdict[s[i]] += 1
else:
sdict[s[i]] = 1
for i in range(len(s)):
if (sdict[s[i]]==1):
return i
return -1
s = Solution()
s.FirstNotRepeatingChar('')
-1
class Solution:
def FirstNotRepeatingChar(self, s):
# write code here
for k,i in enumerate(s):
# 内置函数,直接统计出现次数
if s.count(i)==1:
return k
return -1
s = Solution()
s.FirstNotRepeatingChar('google')
4
5.左旋转字符串
问题描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
考察点:知识迁移
思路1:切片-拼接
需要占内存,遍历两次字符串
- 将S切成s[n:],s[:n]
- 拼接两部分s[n:]+s[:n],并返回
思路2: 定义字符串反转函数(剑指,更快)
调用3次reverse方法,reverse实则为首尾元素交换,然后首依次往后,尾依次往前,直到“首=尾”。
reverse方法复杂度0(1),列表按下标查找。
- 定义字符串所有字符都反转的函数 reverse(eg:abc->cba)
- 将字符串按第n位分割为两部分,分别进行 reverse
- 将反转后的两部分拼接后,再整体进行reverse
总结
- 字符串S无法直接按位交换,即s[i]=s[j]不合法;需S=list(S),再s[i]=s[j]即可。
# -*- coding:utf-8 -*-
class Solution:
def LeftRotateString(self, s, n):
# write code here
if len(s)<n:
return ''
if len(s)==n:
return s
return s[n:]+s[:n]
# -*- coding:utf-8 -*-
class Solution:
def reverse(self,s):
if not s:
return ''
length = len(s)
if length<=0:
return ''
s = list(s) #必须要有,不然不能使用s[i]=s[j]
start = 0
end = length-1
while start<end:
s[start],s[end]= s[end],s[start]
start += 1
end -= 1
return ''.join(s)
def LeftRotateString(self, s, n):
# write code here
length = len(s)
if length<=0:
return ''
if n>length:
n = n%length
first = ''
second = ''
for i in range(n):
first += s[i]
for i in range(n,length):
second += s[i]
first = self.reverse(first)
second = self.reverse(second)
return self.reverse(first+second)
6.翻转单词顺序列
问题描述
一一的翻转字符串中所有单词的顺序,如将“I am a student.”翻转为“student. a am I”
考察点:知识迁移
思路:翻转函数reverse
- “整体翻转”:先将字符串中所有字符进行
- “局部翻转”:将字符串按空格进行分隔,每个单词分别翻转
总结
- 字符串翻转时,需要按空格进行分词时,需记录首尾位置,不能直接用split(’ ')进行分割
# 错误,不能用split(' ')分隔字符串,翻转再拼接。因为“ ”测试不通过。
class Solution:
def reverse(self,s):
if not s:
return ''
length = len(s)
if length<=0:
return ''
s = list(s) #必须要有,不然不能使用s[i]=s[j]
start = 0
end = length-1
while start<end:
s[start],s[end]= s[end],s[start]
start += 1
end -= 1
return ''.join(s)
def ReverseSentence(self, s):
# write code here
length = len(s)
if length <=0:
return ''
if s ==" ":
return " "
s = self.reverse(s)
s = s.split(' ')
res = ''
for i in s:
i = self.reverse(i)
res = res+i+' '
return res.strip()
s = Solution()
s.ReverseSentence(' ')
'student. a am I'
class Solution:
def reverse(self,s,start,end):
if not s:
return ''
length = len(s)
if length<=0:
return ''
s = list(s) #必须要有,不然不能使用s[i]=s[j]
while start<end:
s[start],s[end]= s[end],s[start]
start += 1
end -= 1
return ''.join(s)
def ReverseSentence(self, s):
# write code here
length = len(s)
if length <=0:
return ''
#整体翻转
s = self.reverse(s,0,length-1)
#局部翻转
st= 0
e = 0
i = 0
while i<length:
# 忽略单词开头的空格
while i<length and s[i] == ' ':
i += 1
#记录非空格的第一个字符的位置
st = i
e = i
#找到第一个单词的结尾下标
while i<length and s[i]!=' ':
i += 1
e += 1
s = self.reverse(s,st,e-1)
return s
s = Solution()
s.ReverseSentence('I am a student. ')
' student. a am I'
7.把字符串转为整数
问题描述
- 输入一个字符串,包括数字字母符号,可以为空
- 如果是合法的数值表达则返回该数字,否则返回0
考察点:综合
思路
- 首先判断首位,如果不是数字,则首位上字符的值为0;如果不是+/-,则数字非法,返回0。
- 依次对其余位上的数求值,若遇到非数字,则数字非法,返回0.
- 求和,返回。
class Solution:
def StrToInt(self, s):
# write code here
if len(s)==0:
return 0
else:
# 若首位非数字时,a=0
if s[0]>'9' or s[0]<'0':
a=0
if s[0]!='+' and s[0]!='-':
return 0
else:
# 首位位数字,计算首位的值
a=int(s[0])*10**(len(s)-1)
if len(s)>1:
for i in range(1,len(s)):
if s[i]>='0' and s[i]<='9':
a=a+int(s[i])*10**(len(s)-1-i)
else:
# 发现除首位外的位置上含非数字,则数值不合法,返回0
return 0
if s[0]=='+':
return a
if s[0]=='-':
return -a
return a
s=Solution()
print s.StrToInt('+123')
print s.StrToInt('a123')
123
0
8.正则表达式匹配
问题描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。
思路:
# -*- coding:utf-8 -*-
class Solution:
# s, pattern都是字符串
def match(self, s, pattern):
# write code here
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]=="*":
#如果字符串第一个模式跟模式第一个字符匹配(相等或匹配到“.”),可以有3种匹配方式
if len(s)>0 and (s[0]==pattern[0] or pattern[0]=='.'):
#1.模式后移2字符,相当于x*被忽略
#2.字符串后移1字符,模式后移2字符
#3.字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位
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 (s[0]==pattern[0] or pattern[0]=='.'):
return self.match(s[1:],pattern[1:])
return False
9.表示数值的字符串
问题描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
思路1:正则表达式
- 是否匹配:re.match(r" ", mstr)
- ^:字符串的开始位置
- 特殊字符的匹配,需要加转译字符‘\’:$,(,),*,+,-,[,?,\,^,{,|。
- ?:匹配子表达式0次/1次;*:匹配子表达式0次/多次,+:匹配子表达式1次/多次。
# -*- coding:utf-8 -*-
import re
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
return re.match(r"^[\+\-]?[0-9]*(\.[0-9]*)?([eE][\+\-]?[0-9]+)?$",s)
思路2:判断是否能转为float
- 能转为float的才为数字
# -*- coding:utf-8 -*-
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
try:
p = float(s)
return True
except:
return False
10.字符流中第一个不重复的字符
问题描述
- 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
- 如果当前字符流没有存在出现一次的字符,返回#字符。
思路
- 方法1:遍历字符串,调用mstr.count(‘i’)查找mstr中‘i’出现的次数。
- 方法2:遍历字符串,用字典存储‘字符—次数’,之后再遍历字典,找到出现1次的字符。【较快】
- 方法3:遍历字符串,用列表mlist依次存储字符出现的次数。当字符已存在时,用mlist.index(‘i’)获取其下标后,令其值加1。【最快】
# 方法1
# -*- coding:utf-8 -*-
class Solution:
# 返回对应char
def __init__(self):
self.mstr = ""
def FirstAppearingOnce(self):
# write code here
for i in self.mstr:
if self.mstr.count(i)==1:
return i
return '#'
def Insert(self, char):
# write code here
self.mstr += char
# 方法2
# -*- coding:utf-8 -*-
class Solution:
# 返回对应char
def __init__(self):
self.s=''
self.dict1={}
def FirstAppearingOnce(self):
# write code here
for i in self.s:
if self.dict1[i]==1:
return i
return '#'
def Insert(self, char):
# write code here
self.s=self.s+char
if char in self.dict1:
self.dict1[char]=self.dict1[char]+1
else:
self.dict1[char]=1
# 方法3
# -*- coding:utf-8 -*-
class Solution:
chars = []
counts = []
def __init__(self):
self.chars = []
self.counts = []
def FirstAppearingOnce(self):
# write code here
counter = 0
while counter<len(self.counts):
if self.counts[counter]==1:
return self.chars[counter]
counter += 1
return "#"
def Insert(self, char):
# write code here
if char in self.chars:
self.counts[self.chars.index(char)] += 1
else:
self.chars.append(char)
self.counts.append(1)