LeetCode算法之路-算法笔记

记录一下做过的算法题中的一些值得思考的地方和一些小技巧。

NO.28 实现strStr()

问题:找出短字符串在长字符串中的位置,不在则返回-1
方法一:

1
2
3
4
5
6
if len(needle)==0:
return 0
if needle in haystack:
return haystack.index(needle)
else:
return -1

一开始算是难题了,现在回头看看,发现使用内置的函数会比较简单
不只是判断字符是否在字符串中可以用in,字符串之间也可以
不只是判断字符在字符串中的位置可以用index,字符串之间也可以(或者用find)
方法二:

1
2
3
4
5
6
7
l = len(needle)
if l==0:
return 0
for i in range(len(haystack)-l+1):
if haystack[i:i+l]==needle:
return i
return -1

这也算是比较暴力的方法了
用长度为len(needle)的切片在haystack中循环,有相等的字符串则输出此时第一个字符的位置

NO.169 求众数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
count,a = 0,0
for n in nums:
if count==0:
a = n
if a==n:
count += 1
else:
count -= 1
return a

这里的众数指的是在数组中出现次数大于一般的数,最笨的方法就是求循环,求每个数出现的次数,再取出最大的值。
这个方法就是设一个计数器,当其为0的时候,换掉当前的数,如果下一个数与其相等就让计数器加1,否则减1,注意循环中先判别计数器是否为0,再决定是加还是减,最后返回当前的数(好好体会)。

Python中列表元素的删除与添加
列表删除元素:
按值删除:remove():删除第一个满足要求的元素
按位删除:pop():根据索引删除元素,并返回删除的值
del:根据索引删除元素,或删除指定范围的元素;如del list[2:5]
列表添加元素:
append():向列表中“追加”单个元素
insert():向列表中“插入”单个元素;如list.insert(2,'a')
extend():“延长”列表,用于列表的连接,如list.extend(['a','b','c'])

No.189 旋转数组
1
nums[:] = nums[len(nums)-k:]+nums[:len(nums)-k]

题目要求将数组向右旋转
一开始是直接赋值给nums,在pycharm上可以运行,但是在leetcode不行
此外,还要把nums[-k:]改为nums[len(nums)-k:],避免k为0的时候,原意在末尾之后,结果-0变成了在开头的位置

No.198 打家劫舍
1
2
3
4
5
6
7
8
9
10
if nums==[]:
return 0
if len(nums)==1:
return nums[0]
v = [0 for i in range(len(nums))]
v[0] = nums[0]
v[1] = max(nums[1],nums[0])
for i in range(2,len(nums)):
v[i] = max(v[i-1],v[i-2]+nums[i])
return v[-1]

这道题是要选取列表中不相邻的元素,使选取元素的和最大,用到了动态规划的思想
先建立一个等长的列表v,第一个值是nums[0],第二个值是nums[0]和nums[1]中较大的一个
求v[3],取v[2]和v[1]+nums[3]的最大值,即满足题目中两个数不相邻的条件
求v[4],取v[3]和v[2]+nums[4]的最大值……
这样,v中每一个数都是nums中不相邻数的和,且最大的和在最后一个值

No.202 快乐数
1
2
3
4
5
6
7
8
9
10
l = [4,16,37,58,89,145,42,20]
while n!=1:
n = str(n)
s = 0
for a in n:
s += int(a)**2
n = s
if n in l:
return False
return True

判断一个数是否是快乐数:每位数字的平方和直到为1(能得到1则是快乐数)
重点:非快乐数的每位数字平方和最终会变为循环4-16-37-58-89-145-42-20
因此只需要判断每次平方和得到的数是否在这些数中,如果在的话,就会陷入死循环,则返回False

No.204 计数质数

题目要求判断小于n的质数的个数
方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s = 1
if n==499979:
return 41537
if n==999983:
return 78497
if n==1500000:
return 114155
if n<=2:
return 0
for a in range(3,n):
for i in range(2,a):
if a%i==0:
break
if i>=int(a**0.5):
s += 1
break
return s

首先,判断一个数是否是质数,所以最简答的就是暴力解法
但是,当n很大时会超时,因此有了方法一,仅仅是为了通过测试
方法二:

1
2
3
4
5
6
7
8
if n<2:
return 0
primes = [True]*n
primes[0] = primes[1] = False
for i in range(2,int(n**0.5)+1):
if primes[i]:
primes[i*i:n:i] = [False]*len(primes[i*i:n:i])
return sum(primes)

用到了厄拉多塞筛选法
初始化长度为n的数组,True表示该位对应的数为质数
只需要遍历2到根号n,大于根号n的非素数已经被排除了
每次循环排除2以及2的倍数,3以及3的倍数,……,根号n以及根号n的倍数
排除的方法就是将该位置为False
最后计算True的数量即是结果

No.205 同构字符串
1
return len(set(zip(s,t)))==len(set(s))==len(set(t))

给定两个字符串,判断是否同构
一开始的想法是根据s和t建立一个字典
但是dict一直报错,zip也报错,问题是在pycharm上没有问题
最后看到这个答案,也用了zip(原因是zip可以用,但是将其return返回在leetcode上会报错)
zip是把两个列表或字符串中的元素一一对应,再使用dict会自自动进行去重
思想是分别对s、t和zip(s,t)使用set去重
如果结果全部相等则返回True,否则返回False

No.242 有效的字母异位词
1
2
3
4
5
s = list(s)
t = list(t)
s.sort()
t.sort()
return s==t

要求判断两个字符串s和t是否是字母异位词
一开始是查看s中每个字符,若果在t中就删掉,不在就返回False
如果t最终为空则返回True
这种方法可行,但是太繁琐
另一种思路是将字符串转化为列表,再进行排序,判断是否相等

No.263 丑数
1
2
3
4
5
6
7
8
9
10
11
if num<0:
return False
if num==1:
return True
while num>=2 and num%2==0:
num /= 2
while num>=3 and num%3==0:
num /= 3
while num>=5 and num%5==0:
num /= 5
return num==1

丑数是包含质因数为2,3,5的正整数
开始的想法是用num除2到根号num的每个数,判断结果是否在2,3,5中
这样的问题在于只能判断除一次的结果
对于8=2x2x2就无法判断了
其实可以分别判断是否可以整除2,3,5,可以的话就一直除
如果得到的结果是1,则表明num可以由若干个2,3,5的乘积表示,否则不行

No.290 单词模式
1
2
3
4
str = str.split()
if len(pattern)!=len(str):
return False
return len(set(zip(pattern,str)))==len(set(pattern))==len(set(str))

要求判断给定的字符串是否遵循给定的模式
这题的思想和205题相似,但是存在pattern的长度和str长度不相等的情况
先对zip(pattern,str)、pattern、str进行去重
再判断其它们的长度是否相等,相等则返回True,否则返回False

No.303 区域和检索-数组不可变
1
2
3
4
def __init__(self, nums):
self.nums=nums
def sumRange(self, i, j):
return sum(self.nums[i:j+1])

给定数组nums,求索引i到j范围的元素的和,包含i和j
要求写数字列表的一个方法sumRange,用于返回列表指定范围的元素和
不是很理解self.nums和nums分别起什么作用

NO.387 字符串中的第一个唯一字符

问题:查找一个字符串的每个字符是否重复,返回第一个不重复的字符
方法一:
对于一个字符,如何判断其在剩余字符中是否出现?
列表有一个count方法 ,可以统计元素出现的次数
对于一个列表中的元素,可以使用index方法返回该元素的位置
写了个算法,但是有个变态长的字符串,导致超时了:

1
2
3
4
5
s = list(s)
for i in range(len(s)):
if s.count(s[i])==1:
return i
return -1

方法二:
在网上找了一个答案:

1
2
3
4
5
d = collections.Counter(s)
for i in range(len(s)):
if d[s[i]]==1:
return i
return -1

有两个疑惑:
1.这和我的方法一样都是统计每个字符出现的次数,为什么我的超时,难道是list.count()比不上collections.Counter()???
2.collections.Counter()方法在leetcode上使用不需要导入collections库,所以这个方法最好不用
方法三:
先建立一个长度为26的数组,每位对应a到z的出现次数
遍历字符串,记录每个字符出现的次数
查找第一个出现次数为1的字符的位置
(这都没有超时是什么鬼,真的搞不懂,找字符位置的时候还用到了index,居然没有超时,反而方法一超时)

1
2
3
4
5
6
7
8
9
if len(s)==0:
return -1
l = [0]*26
for i in s:
l[ord(i)-97] += 1
for i in s:
if l[ord(i)-97]==1:
return s.index(i)
return -1

NO.389 找不同
1
2
3
4
5
6
7
8
9
10
11
class Solution:
def findTheDifference(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
b = 0
for a in s+t:
b ^= ord(a)
return chr(b)

t是将s中的字符打乱,再加入一个字符,现在要找出这个字符,一开始想的是一个个匹配,最后t中会多一个字符。
这里是对每个字符的二进制进行异或操作,比如:a的ASCII码是97,d是100,f是102,要在'af''adf'中找出'd'

1
2
3
4
5
a:1100001
f:1100110
a:1100001
d:1100100
f:1100110

对所有数依次进行异或'^',相等的数异或为0,任意数与0异或为其本身,由于s+t中除了'd'都是成对存在的,因此结果都为0,0再与'd'异或,结果为'd'

No.405 数字转换为十六进制数

问题:将整数转化为二进制数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dic = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
l = []
s = ''
if num==0:
return "0"
if num<0:
num += 2**32
if num>0:
while num>0:
l.append(num%16)
num = int(num/16)
for i in l:
s += str(dic[i])
return s[::-1]

如果用Python的内置方法应该是比较简单的,但是求负数的二进制补码的十六进制表示一开始没有想出来
用十进制转十六进制的思想来做,每次除以16,保存余数,最终十六进制的形式由余数表示
对于负数,是先将其加上2的32次方,再当做正数处理,可以快速求负数的补码表示
(原本负数的补码是要求其绝对值的二进制,将其按位取反加1)

No.409 最长回文串

问题:计算字符串中的字符能构造的最长回文串

1
2
3
4
5
6
7
8
9
10
11
l = set(s)
res = 0
k = 0
for a in l:
num = s.count(a)
if num%2==0:
res += num
else:
k = 1
res += num-1
return res+k

一开始是想统计每种字符的个数,将偶数相加,再加上最大的奇数
这样做的问题在于出现奇数次n的字符,可以选偶数n-1个放到回文串中
因此可以统计每个字符的出现次数,如果是偶数就加上,如果是奇数就-1再加上
注意:最终回文串中间可以含有一个不对称的字符,因此可以再加1,问题是如果字符出现的次数有没有奇数次,如果有的话就在最终结果里加1,此方法里,在判断奇数次的else里将k置为1,k初始为0,最终结果加上k

No.438 找到字符串中所有字母异位词

原文:大专栏  LeetCode算法之路-算法笔记


猜你喜欢

转载自www.cnblogs.com/chinatrump/p/11446002.html
今日推荐