算法从零到壹
1.最大子序和
题目:给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。(最大子序和)
方法一:动态规划
f(i)表示为以i为末尾的最大子序和
f(i) = f(i-1) + nums[i]
方法二:分治
取[l,r]中最大子序列
运用分治思想,将序列分为两个子序列,m = (l+r)/2,[l,m]和[m,r]两个子序列
lsum:以序列最左端开始的最大的子序和
rsum:以序列最右端开始的最大子序和
isum:序列总和
msum:序列中最大子序和
所以[l,r]序列的isum是左子序列的isum+右子序列的isum
[l,r]序列的lsum可能为左子序列的lsum或者左子序列的isum+右子序列和的lsum,两者取大
[l,r]序列的rsum可能为右子序列的rsum或者右子序列的isum+左子序列和的rsum,两者取大
求[l,r]的最大子序和msum,分为三种情况:
1.左子序列的最大子序和
2.右子序列的最大子序和
3.左子序列的rsum,右子序列的lsum
三者取大
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
if len(nums)==0:
return 0
dp = [0] * len(nums)
dp[0] = nums[0]
result = nums[0]
for i in range(1,len(nums)):
dp[i] = max(nums[i],dp[i-1]+nums[i])
result = max(dp[i],result)
return result
2.最长回文串
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 "Aa"
不能当做一个回文字符串。
知识点
import collections
aa = collections.Counter("sdfdsgsdf;sdfssfd") #把所有元素出现的次数统计下来了
print(aa)
print(aa.values())
#输出结果:
#Counter({'s': 6, 'd': 5, 'f': 4, ';': 1, 'g': 1})
#dict_values([6, 5, 4, 1, 1])
思路:
回文串,最多只有一个字母个数为奇数,其余为偶数
class Solution:
def longestPalindrome(self, s: str) -> int:
ans = 0
count = collections.Counter(s)
for v in count.values():
ans += v // 2 *2
if ans % 2 == 0 and v % 2 == 1:
ans += 1
return ans
3.分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i
,都有一个胃口值 g[i]
,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j
,都有一个尺寸 s[j]
。如果 s[j] >= g[i]
,我们可以将这个饼干 j
分配给孩子 i
,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值
知识点
#排序函数介绍:sort()和sorted()都属于Python list的排序方法
#区别:sort()属于永久性排列,直接改变该list; sorted属于暂时性排列,会产生一个新的序列。
#sorted()
>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
#sort()
>>> L = [5, 2, 3, 1, 4]
>>> L.sort()
>>> print L
[1, 2, 3, 4, 5]
#enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
思路:
核心:贪心
首先将胃口的数组,食物的数组从小到大进行排序,每次让食物按照从小到大的顺序优先满足胃口小的人。
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
g.sort()
s.sort()
ans = 0
m = len(g)
n = len(s)
i = j = 0
while i < m:
if(j == n):
break
while j < n:
if s[j] >= g[i]:
i += 1
j += 1
ans += 1
break
else:
j += 1
return ans
4.种花
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
思路:
核心:贪心
先使用贪心思想,看看原来数组中最多可以再种多少花,再与n进行比较
[i,j]表示i到j的区间内是空的,所以一个数组可以看成(0,i),很多段(i,j),(j,len(flowerbed))这几个部分分别进行讨论
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
if flowerbed.count(1) <= 0:
if len(flowerbed) % 2 ==0 :
num = len(flowerbed) / 2
else :
num = len(flowerbed) // 2 + 1
return num >= n
first = flowerbed.index(1)
num = first//2
# 中间部分
front =first
for i in range(first,len(flowerbed)):
if flowerbed[i] == 1:
end = i
if end -front >=4:
num = num + (end -front)//2 -1
front = end
flowerbed.reverse()
last = flowerbed.index(1)
num = num + last//2
return num >= n