日常系列LeetCode《1·数组常用技巧篇》
Posted 常某某的好奇心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常系列LeetCode《1·数组常用技巧篇》相关的知识,希望对你有一定的参考价值。
数据规模->时间复杂度
<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(1)
数组元素作为索引下标
优:减少内存占用(map:数组+链表,优化哈希冲突cost)
注:元素范围不能太大
LC442:https://leetcode.cn/problems/find-all-duplicates-in-an-array/
#时间复杂度为 O(n) 且仅使用常量额外空间的算法
#方案1:访问使用负数标记
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
#o(1);假定返回的数组不算在额外的空间内
res=[]
#o(n):负数标记
for x in nums:
index=abs(x)-1
if nums[index]<0: res.append(abs(x)) #已访问
else: nums[index]*=-1
return res
#方案2:访问使用+n标记
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
#o(n);+n标记
n=len(nums)
for x in nums:
index=(x-1)%n
nums[index]+=n
#o(1):假定返回的数组不算在额外的空间内
res=[]
for i in range(n):
if nums[i]>2*n:res.append(i+1)
return res
LC448【top100】:https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/
不使用额外空间且时间复杂度为 O(n)
class Solution:
def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
#o(1)
res=[]
#o(n):+n标记
n=len(nums)
for x in nums:
index=(x-1)%n
nums[index]+=n
#
for i in range(n):
if nums[i]<=n:res.append(i+1)#未访问
return res
字符串字符作为下标索引
LC1002:https://leetcode.cn/problems/find-common-characters/
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] 由小写英文字母组成
class Solution:
def commonChars(self, words: List[str]) -> List[str]:
#o(n^2):利用words[0]初始minfreq
minfreq=[0]*26
for sr in words[0]:
for c in sr:
minfreq[ord(c)-ord('a')]+=1
#o(n^2):统计freq[i],并获得最后minfreq
for i in range(1,len(words)):
freq=[0]*26
for c in words[i]:
freq[ord(c)-ord('a')]+=1
for j in range(26):
minfreq[j]=min(minfreq[j],freq[j])
#minfreq转成字符数组
res=list()
for i in range(26):
res.extend(minfreq[i]*[chr(i+ord('a'))])
return res
LC1370:https://leetcode.cn/problems/increasing-decreasing-string/
1 <= s.length <= 500
s 只包含小写英文字母
class Solution:
def sortString(self, s: str) -> str:
#o(n^2):统计counts
counts=[0]*26
for c in s:
counts[ord(c)-ord('a')]+=1
#o(n^2):上升-下降
res=list()
while len(res)<len(s):
#上升
for i in range(26):
if counts[i]>0:
res.append(chr(i+ord('a')))
counts[i]-=1
#下降
for i in range(25,-1,-1):
if counts[i]>0:
res.append(chr(i+ord('a')))
counts[i]-=1
return "".join(res)
双指针
1)快慢指针:
slow指针:已经处理的区域
fast 指针:指向当前正在处理的元素
2)对撞指针
LC283【top100】:https://leetcode.cn/problems/move-zeroes/
原地对数组进行操作
尽量减少完成的操作次数
方案一:交换
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
#O(1):快慢指针
slow=fast=0
#o(n):比较,交换
while fast< len(nums):
if nums[fast]!=0:
if slow!=fast: #减少交换次数,例如7-6-4-3-8
nums[slow],nums[fast]=nums[fast],nums[slow]
slow+=1
fast+=1
#
return nums
方案二:优化-使用赋值,代替交换;赋值语句比比较语句快
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
#o(1):快慢指针
slow=fast=0
#o(n);比较,赋值
while fast< len(nums):
if nums[fast]!=0:
nums[slow]=nums[fast]
slow+=1
fast+=1
#尾部设0
for i in range(slow,len(nums)) :
nums[i]=0
#
return nums
LC26:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
空间复杂度为O(1)
1 <= nums.length <= 3 * 10^4
-104 <= nums[i] <= 104
nums 已按 升序 排列
不需要考虑数组中超出新长度后面的元素
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
#o(1):快慢指针
slow=0
fast=1
#o(n):赋值,交换
while fast<len(nums):
if nums[fast]!=nums[slow]:
slow+=1
nums[slow]=nums[fast]
fast+=1
#返回k
return slow+1
LC80:https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/
空间复杂度为O(1)
1 <= nums.length <= 3 * 10^4
-104 <= nums[i] <= 104
nums 已按升序排列
不需要考虑数组中超出新长度后面的元素
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
#o(1)
slow=1#指向已处理的区域的最后一个位置
fast=2
#o(n):比较,赋值
while fast<len(nums):
if nums[fast]!=nums[slow-1]:
slow+=1
nums[slow]=nums[fast]
fast+=1
#
return slow+1
LC27:https://leetcode.cn/problems/remove-element/
空间复杂度为O(1)
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
不需要考虑数组中超出新长度后面的元素
进阶:如果要删除的元素特别少,怎样可以提高性能
#方案一:快慢指针
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
#o(1)
slow=fast=0
#o(n)
while fast<len(nums):
if nums[fast]!=val:
nums[slow]=nums[fast]
slow+=1
fast+=1
#
return slow
#方案二:进阶-对撞指针
#例如1-2-2-3-2-1-2
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
#o(1)
left,right=0,len(nums)-1
#o(n)
while left<=right:
if nums[left]==val:#直至替换到非val值,left+=1
nums[left]=nums[right]
right-=1
else:left+=1
#
return left
LC344:https://leetcode.cn/problems/reverse-string/
空间复杂度o(1)
1 <= s.length <= 105
s[i] 都是 ASCII 码表中的可打印字符
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
#o(1)
left,right=0,len(s)-1
#o(n)
while left<=right:
s[left],s[right]=s[right],s[left]
left,right=left+1,right-1
#
return s
LC125【剑18】:https://leetcode.cn/problems/valid-palindrome/
1 <= s.length <= 2 * 10^5
字符串 s 由 ASCII 字符组成
class Solution:
def isPalindrome(self, s: str) -> bool:
#o(1)
left,right=0,len(s)-1
#o(n^2)
while left<right:
#忽略处理
while left<right and not s[left].isalnum():
left+=1
while left<right and not s[right].isalnum():
right-=1
#转换,比较
if left<right:
if s[left].lower()!=s[right].lower():
return False
left,right=left+1,right-1
return True
LC11【top100】:https://leetcode.cn/problems/container-with-most-water/
n == height.length
2 <= n <= 10^5
0 <= height[i] <= 10^4
class Solution:
def maxArea(self, height: List[int]) -> int:
#o(1)
left,right=0,len(height)-1
#o(n)
res=0
while left<right:
area=min(height[left],height[right])*(right-left)
res=max(res,area)
#更新:在宽度一定的情况下面积取决于最短的那个边
if height[left]<=height[right]:
left+=1
else:right-=1
#
return res
LC1480:https://leetcode.cn/problems/running-sum-of-1d-array/
1 <= nums.length <= 1000
-10^6 <= nums[i] <= 10^6
class Solution:
def runningSum(self, nums: List[int]) -> List[int]:
#o(n)
prefixsum=[0]*len(nums)
#o(n):动态规划-通过中间值推导消除重复计算
prefixsum[0]=nums[0]
for i in range(1,len(nums)):
prefixsum[i]=prefixsum[i-1]+nums[i]
#
return prefixsum
LC238【top100】:https://leetcode.cn/problems/product-of-array-except-self/
提示:
2 <= nums.length <= 10^5
-30 <= nums[i] <= 30
保证数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
进阶:
你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
#0(1):返回数组不作空间
res=[0]*len(nums)
#o(n)
#①存前缀积
res[0]=1
for i in range(1,len(nums)):
res[i]=res[i-1]*nums[i-1]
#②o(1):优化空间复杂度-后缀积作变量更新
sufixproduct=1
for i in range(len(nums)-1,-1,-1):
res[i]=res[i]*sufixproduct
#更新
sufixproduct=sufixproduct*nums[i]
#
return res
以上是关于日常系列LeetCode《1·数组常用技巧篇》的主要内容,如果未能解决你的问题,请参考以下文章