LeetCode 2601. Prime Subtraction Operation
周賽338。
題目
輸入長度為n的整數陣列nums。
你可以執行以下動作任意次:
- 選取未選過的索引i,再找一個嚴格小於nums[i]的質數p,將nums[i]減去p
如果能夠使得nums成為嚴格遞增的陣列,則回傳true;否則回傳false。
解法
先篩出所有範圍內的質數。本題nums[i]最大1000,所以只要找1000以內的質數。
如果從左往右遍歷,找到某個nums[i+1]大於nums[i],為了要使nums嚴格遞增,則必須將nums[i]減少;而減少nums[i]可能又會使左方其他元素不符合,很難處理。
如果從右往左遍歷,修改nums[i]則不會影響右方已經處理過的元素。而為了使左邊元素合法的機率更大,必須選擇可以剛好使得nums[i]<nums[i+1]的最小質數p。
注意:若nums[i]原本就小於nums[i+1]則不需要動作。
時間複雜度O(P*N),其中P為質數個數,N為nums長度。空間複雜度O(MX)。
n=1000
sieve = [True]*(n+1)
prime = []
for i in range(2, n+1):
if sieve[i]:
prime.append(i)
for j in range(i*i, n+1, i):
sieve[j] = False
class Solution:
def primeSubOperation(self, nums: List[int]) -> bool:
N=len(nums)
for i in range(N-2,-1,-1):
if nums[i]<nums[i+1]:
continue
for p in prime:
if p<nums[i] and nums[i]-p<nums[i+1]:
nums[i]-=p
break
if nums[i]>=nums[i+1]:
return False
return True
找最小質數p的部分可以用二分搜來優化加速。
時間複雜度O(N log P),其中P為質數個數,N為nums長度。空間複雜度O(MX)。
n=1000
sieve = [True]*(n+1)
prime = [0]
for i in range(2, n+1):
if sieve[i]:
prime.append(i)
for j in range(i*i, n+1, i):
sieve[j] = False
class Solution:
def primeSubOperation(self, nums: List[int]) -> bool:
N=len(nums)
for i in range(N-2,-1,-1):
need=nums[i]-nums[i+1]
idx=bisect_right(prime,need)
if idx==len(prime) or prime[idx]>=nums[i]:
return False
nums[i]-=prime[idx]
return True