记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
-
-
- [10/19 2089. 找出数组排序后的目标下标](#10/19 2089. 找出数组排序后的目标下标)
- [10/20 3886. 可排序整数求和](#10/20 3886. 可排序整数求和)
- [10/21 3863. 将一个字符串排序的最小操作次数](#10/21 3863. 将一个字符串排序的最小操作次数)
- [10/22 3942. 排序排列的最少操作数](#10/22 3942. 排序排列的最少操作数)
- [10/23 3644. 排序排列](#10/23 3644. 排序排列)
- [10/24 2409. 统计共同度过的日子数](#10/24 2409. 统计共同度过的日子数)
- [10/25 1254. 统计封闭岛屿的数目](#10/25 1254. 统计封闭岛屿的数目)
-
10/19 2089. 找出数组排序后的目标下标
遍历一次 nums,统计 target 出现的次数 count,以及小于 target 的数的个数 small。
排序后 target 的位置从 small 开始,一共持续 count 个。
python
def targetIndices(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
small = 0
count = 0
for num in nums:
if num==target:
count+=1
elif num<target:
small+=1
ans = [small+i for i in range(count)]
return ans
10/20 3886. 可排序整数求和
k 必须整除数组长度。把数组切成若干段长度为 k 的连续子数组,每段只能整体旋转,转完后整个数组要变成非递减。
一段能转成非递减,当且仅当把它首尾连成一个圈,变小的地方最多只有一处。
从左往右看每一段:左边已经能排好的那些数里的最大值,不能大于从这里开始一直到末尾的最小值,否则拼起来还会下降。
先预处理前缀最大值、后缀最小值和相邻下降次数,每个因数 k 就能直接判断。把所有可行的 k 加起来。
python
def sortableIntegers(nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
pref_max = [0] * (n + 1)
for i, x in enumerate(nums):
pref_max[i + 1] = max(pref_max[i], x)
suff_min = [10**9] * (n + 1)
for i in range(n - 1, -1, -1):
suff_min[i] = min(nums[i], suff_min[i + 1])
pref_drop = [0] * n
for i in range(1, n):
pref_drop[i] = pref_drop[i - 1] + (nums[i - 1] > nums[i])
def ok(k):
for start in range(0, n, k):
end = start + k - 1
drops = pref_drop[end] - pref_drop[start]
if nums[end] > nums[start]:
drops += 1
if drops > 1 or pref_max[start] > suff_min[start]:
return False
return True
ans = 0
for k in range(1, n + 1):
if n % k == 0 and ok(k):
ans += k
return ans
10/21 3863. 将一个字符串排序的最小操作次数
每次只能把一段真子串排成非降序,不能一次排整个字符串。
已经排好就不用操作。只有两个字符又没排好时,任何真子串都改变不了它们的顺序,返回 -1。
开头已经是最小字母,把后面整段排一次即可;结尾已经是最大字母,把前面整段排一次即可。
否则最小或最大字母出现在中间,先排一段把它送到开头或结尾,再把剩下那段排好。
最小字母只在结尾、最大字母只在开头时,要三次才能排好。
python
def minOperations(s):
"""
:type s: str
:rtype: int
"""
n = len(s)
if all(s[i] <= s[i + 1] for i in range(n - 1)):
return 0
if n == 2:
return -1
mn, mx = min(s), max(s)
if s[0] == mn or s[-1] == mx:
return 1
if any(c == mn or c == mx for c in s[1:-1]):
return 2
return 3
10/22 3942. 排序排列的最少操作数
只能整体反转,或者把第一个数挪到末尾。这两种操作改不了数字在圆环上的相对顺序,只会换方向、换起点。
所以从 0 出发,顺着或逆着走一圈,必须正好是 0,1,2,...,n-1,否则排不出来。
顺着递增时,左旋 zero 次就能把 0 转到开头;也可以先反转、再转、再反转回来,次数是 n-zero+2。
逆着递增时,先转到再反转要 zero+2 次,先反转再转到要 n-zero 次。
两种方向里取最小的次数,都不行就返回 -1。
python
def minOperations(nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
zero = nums.index(0)
def check(step):
for i in range(1, n):
prev = (zero + (i - 1) * step) % n
curr = (zero + i * step) % n
if nums[prev] > nums[curr]:
return False
return True
ans = n + 3
if check(1):
ans = min(ans, zero, n - zero + 2)
if check(-1):
ans = min(ans, zero + 2, n - zero)
return -1 if ans == n + 3 else ans
10/23 3644. 排序排列
只有不在自己位置上的数才需要交换。两个数能交换,当且仅当它们的按位与正好等于 k,所以 k 里每一个是 1 的位,这些错位数里也必须是 1。
因此最大的 k 就是所有错位数的按位与。这个 k 自己也在数组里,可以拿它当中转,把错位数换到该去的位置。
数组已经有序就不用交换,返回 0。
python
def sortPermutation(nums):
"""
:type nums: List[int]
:rtype: int
"""
ans = -1
for i, x in enumerate(nums):
if i != x:
ans &= x
return max(ans, 0)
10/24 2409. 统计共同度过的日子数
同一年里,把日期转化成该年第几天。
两人共同在的日子,是到达日里较晚的那天到离开日里较早的那天。到达比对方离开还晚,就没有交集,返回 0。
python
def countDaysTogether(arriveAlice, leaveAlice, arriveBob, leaveBob):
"""
:type arriveAlice: str
:type leaveAlice: str
:type arriveBob: str
:type leaveBob: str
:rtype: int
"""
mon = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
d = [0]*12
for i in range(1,12):
d[i] = d[i-1]+mon[i-1]
def trans(date):
m = int(date[:2])
ind = d[m-1]
ind += int(date[-2:])
return ind
aA = trans(arriveAlice)
aB = trans(arriveBob)
lA = trans(leaveAlice)
lB = trans(leaveBob)
if aA>lB or aB>lA:
return 0
return min(lA,lB)-max(aA,aB)+1
10/25 1254. 统计封闭岛屿的数目
0 是陆地,1 是水。上下左右连在一起的陆地算一座岛,碰到网格边界的岛不算封闭。
先从四条边上的陆地出发,把和边界连在一起的整片陆地都改成水。
然后再看内部还剩下的陆地,每找到一片就计数,并把它整片改成水,避免重复统计。
python
def closedIsland(grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m, n = len(grid), len(grid[0])
def flood(x, y):
st = [(x, y)]
while st:
i, j = st.pop()
if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 1:
continue
grid[i][j] = 1
st.append((i + 1, j))
st.append((i - 1, j))
st.append((i, j + 1))
st.append((i, j - 1))
for i in range(m):
flood(i, 0)
flood(i, n - 1)
for j in range(n):
flood(0, j)
flood(m - 1, j)
ans = 0
for i in range(1, m - 1):
for j in range(1, n - 1):
if grid[i][j] == 0:
ans += 1
flood(i, j)
return ans