记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
-
-
- [4/13 1848. 到目标元素的最小距离](#4/13 1848. 到目标元素的最小距离)
- [4/14 2463. 最小移动总距离](#4/14 2463. 最小移动总距离)
- [4/15 2515. 到目标字符串的最短距离](#4/15 2515. 到目标字符串的最短距离)
- [4/16 3488. 距离最小相等元素查询](#4/16 3488. 距离最小相等元素查询)
- [4/17 3761. 镜像对之间最小绝对距离](#4/17 3761. 镜像对之间最小绝对距离)
- [4/18 3783. 整数的镜像距离](#4/18 3783. 整数的镜像距离)
- [4/19 1855. 下标对中的最大距离](#4/19 1855. 下标对中的最大距离)
-
4/13 1848. 到目标元素的最小距离
从start位置开始向左向右遍历 找到第一个等于target的位置 返回最小距离
python
def getMinDistance(nums, target, start):
"""
:type nums: List[int]
:type target: int
:type start: int
:rtype: int
"""
n = len(nums)
l = start
r = start
while l>=0 or r<n:
if l>=0 and nums[l]==target:
return start-l
if r<n and nums[r]==target:
return r-start
l-=1
r+=1
return -1
4/14 2463. 最小移动总距离
先将机器人位置和工厂位置都从小到大排序。
排序后有一个很重要的性质:
最优方案中,不会出现"交叉分配"。
也就是说,如果 robot[i] < robot[j],那么它们分配到的工厂顺序也不会反过来。
所以每个工厂在排序后,负责的一定是一段连续的机器人。
于是可以做记忆化搜索:
dfs(i, j) 表示"从第 i 个机器人开始,使用第 j 个及之后的工厂去修理,
所需的最小总移动距离"。
对于当前工厂 factory[j] = [pos, limit],有两类选择:
1 这个工厂一个机器人都不修:
代价是 dfs(i, j + 1)
2 这个工厂修连续的 1 个、2 个、...、limit 个机器人:
假设修了 t 个,那么就是修 robot[i] 到 robot[i+t-1]
代价为:
abs(robot[i] - pos) + ... + abs(robot[i+t-1] - pos) + dfs(i+t, j+1)
把这些情况取最小值即可。
边界:
1如果 i == len(robot),说明所有机器人都修好了,返回 0
2如果 j == len(factory) 但还有机器人没修,返回一个很大值
python
def minimumTotalDistance(robot, factory):
"""
:type robot: List[int]
:type factory: List[List[int]]
:rtype: int
"""
from functools import lru_cache
robot.sort()
factory.sort()
m = len(robot)
n = len(factory)
INF = 10**18
@lru_cache(None)
def dfs(i, j):
if i == m:
return 0
if j == n:
return INF
ans = dfs(i, j + 1)
pos, limit = factory[j]
dist = 0
for k in range(limit):
if i + k >= m:
break
dist += abs(robot[i + k] - pos)
ans = min(ans, dist + dfs(i + k + 1, j + 1))
return ans
return dfs(0, 0)
4/15 2515. 到目标字符串的最短距离
找到目标字符串位置 计算左右两边到目标字符串的最短距离 返回最小距离
距离step 找左右两边是否存在目标字符串 存在则返回距离
step不需要n次 因为step超过n/2时 会重复
python
def closestTarget(words, target, startIndex):
"""
:type words: List[str]
:type target: str
:type startIndex: int
:rtype: int
"""
n = len(words)
step = 0
while step<=n//2:
l = (startIndex-step+n)%n
r = (startIndex+step)%n
if words[l]==target:
return step
if words[r]==target:
return step
step+=1
return -1
4/16 3488. 距离最小相等元素查询
对于下标 i,找和 nums[i]相等的其它位置里,距离 i 最近的那个位置
由于数组是环形的,两个位置 a、b 的距离是:min(abs(a - b), n - abs(a - b))
先按数值分组,记录每个数出现的所有下标。
对于同一个数的出现位置列表 pos,某个位置只需要比较它在列表中的前一个和后一个
相同元素即可,因为在线性顺序下最近的相同元素一定出现在相邻位置,环形情况则通过首尾相连处理。
预处理出每个下标的答案后,queries 直接返回即可
python
def solveQueries(nums, queries):
"""
:type nums: List[int]
:type queries: List[int]
:rtype: List[int]
"""
from collections import defaultdict
n = len(nums)
pos_map = defaultdict(list)
for i, v in enumerate(nums):
pos_map[v].append(i)
dist = [-1] * n
for pos in pos_map.values():
m = len(pos)
if m == 1:
continue
for i, cur in enumerate(pos):
prev_idx = pos[(i - 1) % m]
next_idx = pos[(i + 1) % m]
prev_dist = min(abs(cur - prev_idx), n - abs(cur - prev_idx))
next_dist = min(abs(cur - next_idx), n - abs(cur - next_idx))
dist[cur] = min(prev_dist, next_dist)
return [dist[q] for q in queries]
4/17 3761. 镜像对之间最小绝对距离
从头遍历 计算当前位置的镜像并记录位置
如果之后有值符合计算距离即可
python
def minMirrorPairDistance(nums):
"""
:type nums: List[int]
:rtype: int
"""
n=len(nums)
m={}
ans=float("inf")
def reverse(x):
return int(str(x)[::-1])
for i,v in enumerate(nums):
r = reverse(v)
if v in m:
ans = min(ans,abs(i-m[v]))
m[r] = i
return -1 if ans==float("inf") else ans
4/18 3783. 整数的镜像距离
翻转字符串 计算镜像距离
python
def mirrorDistance(n):
"""
:type n: int
:rtype: int
"""
v=n
rev=0
while v:
rev=rev*10+v%10
v//=10
return abs(n-rev)
4/19 1855. 下标对中的最大距离
双指针:
i 指向 nums1,j 指向 nums2,始终保持 j >= i
若 nums1[i] <= nums2[j],说明 (i, j) 合法,可以尝试增大 j 扩大距离
否则说明 i 太小对应值太大,需要右移 i,并保证 j 至少跟到 i
python
def maxDistance(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: int
"""
i, j = 0, 0
ans = 0
n1, n2 = len(nums1), len(nums2)
while i < n1 and j < n2:
if i > j:
j = i
continue
if nums1[i] <= nums2[j]:
ans = max(ans, j - i)
j += 1
else:
i += 1
return ans