学习来源:
1560 圆形赛道上经过次数最多的扇区
算法分析:题目只要求取被访问次数最多的扇区,因此可以只看开始位置与结束位置。中间必定是所有的扇区都访问了0,1,2,…
遍。对最后的判定无影响。
res = []
start = rounds[0]
end = rounds[-1]
length = end - start
if length < 0:
length += n
while length > -1:
if start+length>n:
res.append((start+length)%n)
else:
res.append(start+length)
length -= 1
res.sort()
return res
1561 可以获得的最大硬币数目
算法分析:先将数组排序,尾指针每次前移两个元素,头指针每次后移一个元素。
piles.sort()
res = 0
l = 0
# len(piles)-1表示最大的硬币堆,依题意会被Alice拿走,因此选择len(piles)-2开始拿取
r = len(piles)-2
while l<r:
res += piles[r]
l += 1
r -= 2
return res
1562 查找大小为M的最新分组
算法分析:设定border[i]
表示以i
为边界的连续的1
的长度,num[i]表示长度为i的连续1的个数。若当前操作位置为pos
,则该位置左边
的连续1
的长度为border[pos-1]
,右边
的连续1
的长度为border[pos+1]
,更新后num[border[pos-1]]
与num[border[pos+1]]
减少1
,num[border[pos - 1] + 1 + border[pos + 1]]
加1
。每次更新后判断num[m]
是否大于0
,即是否存在长度为m
的连续1
。
lens = len(arr)
# border[i]表示以i为边界的连续的1的长度
border = [0 for _ in range(lens+2)]pos
# num[i]表示长度为i的连续1的个数
num = [0 for _ in range(lens+1)]
res = -1
for count, pos in enumerate(arr):
left = border[pos - 1]
right = border[pos + 1]
new_length = right + left + 1
border[pos - left] = border[pos + right] = new_length
num[new_length] += 1
num[left] -= 1
num[right] -= 1
# 若num[m]>0说明此时存在长度为m的连续1,更新结果
if num[m] > 0:
res = count+1
return res
1563 石子游戏
题意理解:将给定数组划分为非空的两段,舍弃元素总和更大的子段,得分累加另一子段的元素和。重复进行此操作,直至只剩下一个元素,求解最大的得分。
示例:stoneValue = [1,2,2]
,第一次划分为:L=[1]
、R=[2,2]
,则sum(L)=1
、sum(R)=4
,即舍去右边,得分累加左边sum(L)
。此时只剩下一个元素,结束操作,最终得分为1
。若第一次划分为:L=[1,2]
、R=[2]
,则sum(L)=3
、sum(R)=2
,即舍去左边,得分累加右边sum(R)
。此时只剩下一个元素,结束操作,最终得分为2
。最终答案为2
。
算法分析:区间动态规划,dp[i][j]
表示左右边界为i
和j
时的最优解。
lens =len(stoneValue)
# sum[i][j]表示stoneValue中i到j的元素和
sum_num = [[0 for _ in range(lens)] for _ in range(lens)]
for i in range(lens):
sum_num[i][i] = stoneValue[i]
for j in range(i+1,lens):
sum_num[i][j] = sum_num[i][j-1]+stoneValue[j]
# dp[i][j]表示左边界为i,右边界为j的stoneValue的最优解
dp = [[0 for _ in range(lens)] for _ in range(lens)]
def maxres(start,end,sum_num):
# 只剩下一个石头,返回0
if start == end:
dp[start][end] = 0
return dp[start][end]
# 避免重复计算
if not dp[start][end]:
# 遍历start到end中所有可能的划分位置
for i in range(start,end):
left = sum_num[start][i]
right = sum_num[i+1][end]
# 左边小于右边,右边被舍弃
if left < right:
dp[start][end] = max(dp[start][end],left + maxres(start,i,sum_num))
# 右边小于左边,左边被舍弃
elif left > right:
dp[start][end] = max(dp[start][end],right + maxres(i+1,end,sum_num))
# 两边相等,dp寻找两边的最优解
else:
dp[start][end] = max(dp[start][end],left + maxres(start,i,sum_num),right + maxres(i+1,end,sum_num))
return dp[start][end]
maxres(0,lens-1,sum_num)
return dp[0][lens-1]