这是昨天写的,写完有点晚了,本来想今天下午补的……结果看了一天综艺,还是很舒服的
整体不难,争取半小时内搞定,进度是 -45
简单题
现在我们给定两个列表,一个列表表示的是房子的位置;另外一个列表表示的是加热器的位置。
现在问,加热器的辐射范围多大能够将所有的房子覆盖到。
Example 1:
Input: [1,2,3],[2]
Output: 1
Explanation: The only heater was placed in the position 2, and if we use the radius 1 standard, then all the houses can be warmed.
Example 2:
Input: [1,2,3,4],[1,4]
Output: 1
Explanation: The two heater was placed in the position 1 and 4. We need to use radius 1 standard, then all the houses can be warmed.
思路1:
这算是一个最小最大问题,对于每一个房子我们都要被加热器辐射到,这时候我们需要求每个每个房子如果被辐射到的最小的范围,然后对于所有房子,我们要保证所有房子都被辐射到,所以这里我们需要求所有辐射范围里面最大的那个。
我们可以看到所有的房子,除了第一个和最后一个都在两个加热器的中间,那么就是对于这个house
来说最小的辐射范围就是 min(house - heaters[i], heaters[i+1]-house)
,其中heaters[i]
同时我们可以在加热器的头部加一个无限小的位置,在尾部加一个无限大的位置这样就可以保证所有的房子都处在两个加热器中间。
代码如下:
class Solution(object):
def findRadius(self, houses, heaters):
"""
:type houses: List[int]
:type heaters: List[int]
:rtype: int
"""
heaters+=[float('inf'), float('-inf')]
houses.sort()
heaters.sort()
i, ans, res = 0, 0, float('-inf')
for house in houses:
while house > heaters[i+1]:
i+=1
ans = min(house - heaters[i], heaters[i+1] - house)
res = max(ans, res)
return res
思路二,其实通过上面的分析我们也可以知道,我们要找的就是房子处在哪两个加热器中间,因此我们也可以不用对house进行排序,通过二分法找到房子所对应的加热器的位置。
代码如下:
class Solution(object):
def findRadius(self, houses, heaters):
"""
:type houses: List[int]
:type heaters: List[int]
:rtype: int
"""
heaters+=[float('inf'), float('-inf')]
heaters.sort()
res = float('-inf')
for house in houses:
index = bisect.bisect(heaters, house)
left = house - heaters[index-1]
right = heaters[index] - house
res = max(res, min(left, right))
return res
魔法序列
魔法序列是值下面的序列S = “1221121221221121122……”
这个S神奇在什么地方呢,我们将其1和2分开可以排成
1 22 11 2 1 22 1 22 11 2 11 22
我们可以看到对应的每个1和2的数量是
1 2 2 1 1 2 1 2 2 1 2 2
而这个就恰好是S
所以魔法序列指的就是能够由自身产生自身的序列。
通过上面的分析我们就可以得到S的生成规则。
给定n,那么求S前n个数字有多少1。
如果上面的S要接着往下走的话,是生成1,那么是生成多少个1呢,我们将连续的1或者2看成是一个整体,这个1就是对应第13个,那么生成的数量就是S[12],是1个1。
所以代码如下:
class Solution(object):
def magicalString(self, n):
"""
:type n: int
:rtype: int
"""
s = '122'
count = 3
while len(s)<=n:
if count%2==1:
s+='1'*int(s[count-1])
else:
s+='2'*int(s[count-1])
count+=1
return s[:n].count('1')
写的更简洁点的话就是
class Solution(object):
def magicalString(self, n):
"""
:type n: int
:rtype: int
"""
s = '122'
count = 3
while len(s)<=n:
s+=str((2 - count%2))*int(s[count-1])
count+=1
return s[:n].count('1')
EASY题,很简单, 题目描述
直接上代码了:
class Solution(object):
def licenseKeyFormatting(self, S, K):
"""
:type S: str
:type K: int
:rtype: str
"""
S = S.upper().replace('-','')
strs = [S[max(i-K, 0):i] for i in range(len(S), 0, -K)][::-1]
return '-'.join(strs)
最长有多少个1连在一起
这个也是简单题, 题目描述
代码如下:
class Solution(object):
def findMaxConsecutiveOnes(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
res, cur = 0, 0
for i in nums:
cur = cur*i+i
res = max(res, cur)
return res
现在给定一个由整数组成的列表。
有玩家1和玩家2,玩家1先玩,他可以从列表的两端任选一个数字,然后玩家2再选,玩家1选过的数字玩家2不能再选。
最后谁手上的数字大谁就能够获胜,假设两个人都是非常会玩的。
那这其实就是一个动态规划的题目,我们要求玩家1最多能够拿到多少数字,然后判断这个数字是不是大于总数的2分之一即可。
用dp[i][j]
表示能够在nums[i:j+1]
拿到的最大值。
一开始想的时候,我们可能会觉得转移方程是dp[i][j] = max(dp[i][j-1] + nums[j], dp[i+1][j]+nums[i])
不过是跑过程序还是后来又仔细分析过了我们就会发现这个是错的。
因为如果dp[i][j]
是玩家1的能够拿到的最大的话,那dp[i][j-1]
就是玩家2能够拿到的最大总和,在玩家1选择了末尾的数字以后。
而玩家1要做的应该是让玩家2能够拿到的是最少的,这样才能保证自己拿到最多。
因此,dp[i][j]
和dp[i][j-1]
以及dp[i-1][j]
之间存在的关系并不是上面这样的。
玩家1应该要做出玩家2能够拿到最少的选择,那么就是 min(dp[i][j-1], dp[i+1][j])
,而玩家1和玩家2最后拿到的总和应该是sum(nums[i:j+1])
所以转移方程为:dp[i][j] = sum(nums[i:j+1]) - min(dp[i][j-1], dp[i+1][j])
最后需要注意的是,大概是用五六个wrong answer得到的经验, 题目虽然说的是得分最高的胜利,但是平局也算是玩家1胜利,也可能是我理解有误…………
所以代码如下, 这是用递归形式写的。
class Solution(object):
def PredictTheWinner(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
self.dp = {}
return self.helper(nums, 0, len(nums)-1)*2 >= sum(nums)
def helper(self, nums, start, end,):
if (start, end) in self.dp:
return self.dp[(start, end)]
if start==end:
self.dp[(start, end)] = nums[start]
return nums[start]
res = sum(nums[start:end+1]) - min(self.helper(nums, start+1, end), self.helper(nums, start, end-1))
self.dp[(start, end)] = res
return res
写成双重循环的形式的话:
class Solution(object):
def PredictTheWinner(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
dp = [[0]*len(nums) for _ in range(len(nums))]
for i in range(len(nums)):
dp[i][i] = nums[i]
for i in range(len(nums), -1, -1):
for j in range(i+1, len(nums)):
dp[i][j] = sum(nums[i:j+1]) - min(dp[i+1][j], dp[i][j-1])
print(dp)
return dp[0][len(nums)-1]>=(sum(nums)+1)//2