8. String to Integer (atoi)
-
ls = list(str.strip())
先去除字符串两端的空格,并把它存放到数组里。 - 检查字符串首位是正号还是负号,检查完并给sign赋值后,将字符串首位删掉
- 初始化res和循环变量i,
while i<len(ls) and ls[i].isdigit()
, 注意判断的条件。判断的是数组的长度,已经不再是字符串的长度了。还有就是要对数组每一位判断是否为数字。
-res = res*10 + ord(ls[i]) - ord('0')
- return
max(-2**31, min(2**31-1, res*sign))
这里是注意数组越界情况
12. Integer to Roman
运用/和%运算来取得四位数的第1,2,3,4个数字,然后将这个数字作为索引去相应的list里找罗马数字。
罗马数字个位数:Q = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
十位数:W = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
百位数:E = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
千位数: R = ["", "M", "MM", "MMM"]
注意第一个元素应该是空,这样可以使下标与数字对应起来。
13. Roman to Integer
初始化一个dict,里边存放所有的罗马字符和他们相对应的数字:
roman = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1}
罗马数字的计算规则:
- 相同的数字连写,所表示的数等于这些数字相加得到的数,例如:III = 3
- 小的数字在大的数字右边,所表示的数等于这些数字相加得到的数,例如:VIII = 8
- 小的数字,限于(I、X和C)在大的数字左边,所表示的数等于大数减去小数所得的数,例如:IV = 4
- 正常使用时,连续的数字重复不得超过三次
- 在一个数的上面画横线,表示这个数扩大1000倍(本题只考虑3999以内的数,所以用不到这条规则)
python中string可以直接以List的形式访问。
所以当roman[s[i]] < roman[s[i+1]]
时,就将res -= roman[s[i]]
,否则res += roman[s[i]]
, res初始化为0.
**需要注意的是,最后一个罗马字符永远是加上去的,不符合上述规律,所有要返回return res + roman[s[-1]]
14. Longest Common Prefix
运行时间为O(m*n), m为字符串最小长度,n为字符串个数
找每个string的公共最长prefix,举例说明:
- {"a","a","b"} should give "" as there is nothing common in all the 3 strings.
- {"a", "a"} should give "a" as a is longest common prefix in all the strings.
- {"abca", "abcd"} as abc
- {"ac", "ac", "a", "a"} as a.
先找出最短的string,以它作为标准。min()函数可以添加key = len属性,来找到最短长度的元素: shortest = min(strs, key = len)
然后针对shortest中的每一个字符,检查strs中的其他字符串相对应的位置是不是该字符,若不是,则返回shortest[:i]
,对shortest遍历时用enumerate比较方便。最后若都存在,就返回shortest
17. Letter Combinations of a Phone Number
Iterative:
思路在于要维护一个last数组,存放针对当前未组合的一个string,已经组合好的上一组string集合。有点类似于backtracking.
所以last一开始是为空的,取得第一个字符对应的string后,将string里的每个字符与last数组里的每一个string进行连接,append到一个新的数组里。最后再将新的数组作为last进行下一轮循环。需要注意的是,为什么要存在这个中间数组,以及什么时候对它进行初始化。
还是要想清楚这道题的思路,最后的结果数组,也就是我们的last数组,是在不断被替换更新的。它不可以直接append进新的字符串,因为老的字符串依然存在,但我们以及不需要了。所以我们需要一个中间数组来存放新一轮的结果,每次循环结束再将它赋值给last。并且这个中间数组要每次外层循环都更新为空。
- 还有重要的一点就是,注意字符连接顺序。要使last中的字符再前,新加的字符在后。
Recursive
backtracking思想,不断传递除了最后一个字符的数字符串进去,总会有某一次,传进去的数字符串长度为1. 当数字符串长度为1时,返回list形式的相对应的string。
if len(digits)==1: return list(dic[digits[0]])
然后将数字符串最后一个数字符所对应的string取出来,最后将迭代的结果,和最后一个字符串对应的string相加。
last = self.letterCombinations(digits[:-1])
first = dic[digits[-1]]
return [ele + char for ele in last for char in first]
20. Valid Parentheses
- 先说一种比较投机取巧的方法,用字符串中的replace函数。
while '()' in s or '[]' in s or '{}' in s:
s = s.replace('()', '').replace('{}', '').replace('[]', '')
if len(s) == 0:
return True
else:
return False
- 另外一种方法用到了stack和hash,将右括号作为key,左括号作为value存到哈希表中。然后对s中的每个字符进行遍历,如果char在value里
if char in dic.values()
,就将这个char append到stack中,如果char在Keyif char in dic.keys()
里,就从stack里Pop出来一个元素与char在dic里所对应的value比较,如果不相等,就证明Invalid。这里要注意pop之前应该先判断stack是否为空。最后返回stack是否为空,因为每针对一个右括号,我们都会pop出来一个左括号,所以最后stack是空的。
因为如果是valid的,我们就总是先遇到左括号,所以将左括号作为value,并加入到stack里。 - 如果s的长度为奇数,就一定不是valid, 可以直接返回false,但注意当s长度为0时,我们认为他是valid的,返回true。
28. Implement strStr()
在一个字符串中找到另一个字符串第一次出现的位置。trick的点在于对大字符串进行for循环遍历时,range的范围是for i in range(len(str1) - len(str2) + 1):
, 因为如果str2的长度是3,那在str1中就要3个3个的进行比较,所以在str1只剩最后三个字符时就要停止比较,所以将len(str2)减去,加1是因为range取不到最后一位,为了取到,就多加上一个。
if str1[i : i + len(str2)] == str2: return i
这就是上述3个3个的比较的实现,注意这里就不用再加1了。因为i + len(str2)本来就比实际长度多了一个。
22. Generate Parentheses
- 先对left,right,list初始化,
left, right, list = n, n, []
- 调用dfs函数,
self.dfs(left, right, list, '')
,最后一个空字符串是用来存放valid排列的 - 当左右都不存在的时候,将此时的string append到list里去,并且注意一定要返回!因为valid排列不只一个
- 如果没有
if right < left: return
, 就会出现很多‘)(’这种组合,因为valid排列总是先左后右的,所以做这种检查,不然就会先右后左 - 动态规划解法:
https://discuss.leetcode.com/topic/28374/clean-python-dp-solution
38. Count and Say
题目说的实在是太不明白了。。。
解释一下就是,输入n,那么我就打出第n行的字符串。
怎么确定第n行字符串呢?他的这个是有规律的。
n = 1时,打印一个1。
n = 2时,看n=1那一行,念:1个1,所以打印:11。
n = 3时,看n=2那一行,念:2个1,所以打印:21。
n = 4时,看n=3那一行,念:一个2一个1,所以打印:1211。
以此类推。(注意这里n是从1开始的)
所以构建当前行的字符串要依据上一行的字符串。“小陷阱就是跑完循环之后记得把最后一个字符也加上,因为之前只是计数而已。”
其实就是对上一个字符串进行统计计数,需要注意的地方有:
- 要将temp, pivot, count的初始化写字for循环里边,for循环总共循环n-1次,因为当n=1时,res = '1'. temp应该定义为空字符串,而不是空数组
- 共两个for循环,外层控制循环次数,内层控制遍历统计上一个字符串的字符。当
char != pivot
时,我们已经完成了对char的计数,就将temp += str(count) + pivot
添加到字符串里,并对pivot进行更新,同时将新的count设置为1. - 当内层for循环结束后,还要将统计结果再一次添加到temp中
temp += str(count) + pivot
,这是因为内层循环结束后最后一个字符还尚未添加进去 - 在每次内层循环结束后,更新res
res = temp
43. Multiply Strings
- 先初始化一个用来存放结果数字的数组,数组的长度为
res = [0]*(len(num1) + len(num2))
, 两个数组相乘的位数是小于他们的位数之和的,注意是位数之和,而不是相加后的位数。 - 内层for循环结束后,digit要减1,这是因为计算相乘时,将分别相乘的和加起来时,是要向后错位的,自己在纸上写一下计算过程就知道了。
- 每次内层循环也要cur - 1,也是因为每单次计算结果时也是从后往前得出结果的
- for 循环时,一定要是
for int1 in reversed(num1)
,reversed很重要,千万不能忘 - 内层for循环,在计算两个数的真正成绩,和进位数字的时候,一定要是'+=',
res[inner] += int(int1) * int(int2)
,
res[inner - 1] = res[inner] / 10
. 相乘时不要忘了类型转换 - 最后要将res数组前边的0pop掉,然后当res数组不为空时,返回join结果,如果为空,就返回‘0’
-
' '.join(map(str, res))
: map(str, res)是将List数组中的每个元素转换为str类型,并去掉list结构。' ' .join()就是将他们连接起来成为一个字符串
67. Add Binary
用到的和43题类似的方法,初始化一个数组,然后一位一位的相加,最后将数组再转换为字符串。需要注意几个地方:
- 执行完
a.zfill(l2)
等语句之后,要将之后用到的len更新,不能再使用旧的lenth符号 - 相乘那道题用的是两层for循环,这道题只需要一个while循环,因为相加是每位都对照的
- 最后也要检查res数组在
res.pop(0)
之后是否长度为0,若为0 就直接返回‘0’, 若不为0,再用join, map方法将数组转换为字符串输出
71. Simplify Path
费了半天力气,原来根本没有理解透题意,因为对Unix的路径含义不是很清楚。简单来说就是,.
意味着当前文件夹,..
意味着parent folder
对于每一个块(以‘/’作为分界)进行分析,如果遇到‘../’则表示要上一层,那么就是进行出栈操作,如果遇到‘./’则是停留当前,直接跳过,其他文件路径则直接进栈即可
- 先将path以'/'字符进行split,此时得到的是数组形式的结果,然后对数组进行解析,将值为空或者为
.
的元素去掉。然后初始化一个空数组stack - 对数组中的每个元素进行遍历,如果元素值为
..
,就意味着要返回上一层,我们就从stack中pop出来一个元素,注意要检查stack是否为空 - 若元素值不为
..
,我们就将元素append到stack中。 - 最后返回
'/' + '/'.join(stack)
, 不要忘了最头端的'/', 并且再用'/'把stack中的元素连接起来
93. Restore IP Addresses
实现中需要一个判断数字是否为合法ip地址的一项的函数,首先要在0-255之间,其次前面字符不能是0。