日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一、数组经典题型

發布時間:2023/12/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一、数组经典题型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、數組經典題型

  • * 前言
  • 1、元素查找 (暴力解法、二分查找)
    • 35.搜索插入位置
    • 34.在排序數組中查找元素的第一個和最后一個位置
    • 69.x的平方根
    • 367.有效的完全平方數
    • 875.愛吃香蕉的珂珂
  • 2、元素移除 (暴力解法、雙指針法)
    • 26.刪除有序數組中的重復項
    • 283.移動零
    • 844.比較含退格的字符串
    • 977.有序數組的平方
  • 3、長度最小的子數組(暴力解法、滑動窗口)
    • 904.水果成籃
    • 76.最小覆蓋子串
    • 239.滑動窗口最大值
  • 4、過程模擬 (無算法,邏輯思維理解)
    • 54.螺旋矩陣
    • 劍指Offer29.順時針打印矩陣
  • 參考

* 前言

后續題目基于基礎算法部分,請參考:算法刷題總結 (一) 數組



1、元素查找 (暴力解法、二分查找)

35.搜索插入位置

leetcode鏈接

(1). 暴力解法,遍歷列表:

class Solution:def searchInsert(self, nums: List[int], target: int) -> int:# 分別處理如下三種情況# 目標值在數組所有元素之前# 目標值等于數組中某一個元素# 目標值插入數組中的位置for i in range(len(nums)):# 一旦發現大于或者等于target的num[i],那么i就是我們要的結果if nums[i]>=target:return i# 目標值在數組所有元素之后的情況# 如果target是最大的,或者 nums為空,則返回nums的長度return len(nums)

(2). 二分法,二分列表:

class Solution:def searchInsert(self, nums: List[int], target: int) -> int:# 分別處理如下四種情況# 目標值在數組所有元素之前 [0, -1]# 目標值等于數組中某一個元素 return middle;# 目標值插入數組中的位置 [left, right],return right + 1# 目標值在數組所有元素之后的情況 [left, right], 因為是右閉區間,所以 return right + 1# 1. 使用二分法快速查找(比遍歷快),如果能找到target,返回索引left, right = 0, len(nums)-1 # 定義target在左閉右閉的區間里,[left, right]while left<=right:mid = (left+right)//2if nums[mid]>target:# target 在左區間,所以[left, middle - 1]right = mid-1elif nums[mid]<target:# target 在右區間,所以[middle + 1, right]left = mid +1else:return mid# 2. 如果找不到# 返回right+1 或者 返回 leftreturn left

一個簡單的中間過程

nums = [1,2,5,8,10] target = 9 searchInsert(nums, target) """ [left, right]: [0, 4] [left, right]: [3, 4] [left, right]: [4, 4] [left, right]: [4, 3] # 交叉退出 """

暴力與二分法的區別在于暴力是遍歷列表,而二分法是二分查找,速度相對快。



34.在排序數組中查找元素的第一個和最后一個位置

leetcode鏈接

(1). 暴力法:

class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:if target in nums:start = nums.index(target)end = len(nums)-(nums[::-1].index(target)+1)return [start, end]return [-1, -1]

(2). 二分法:

""" 尋找target在數組里的左右邊界,有如下三種情況:情況一:target 在數組范圍的右邊或者左邊,例如數組{3, 4, 5},target為2或者數組{3, 4, 5},target為6,此時應該返回{-1, -1} 情況二:target 在數組范圍中,且數組中不存在target,例如數組{3,6,7},target為5,此時應該返回{-1, -1} 情況三:target 在數組范圍中,且數組中存在target,例如數組{3,6,7},target為6,此時應該返回{1, 1} """ class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:# 二分查找,尋找target的右邊界(不包括target)# 如果rightBorder為沒有被賦值(即target在數組范圍的左邊,例如數組[3,3],target為2),為了處理情況一def getRightBorder(nums:List[int], target:int) -> int:# 定義target在左閉右閉的區間里,[left, right] left, right = 0, len(nums)-1# 記錄一下rightBorder沒有被賦值的情況rightBoder = -2 # 當left==right,區間[left, right]依然有效while left <= right:middle = left + (right-left) // 2if nums[middle] > target:right = middle - 1# 當nums[middle] == target的時候,更新left,這樣才能得到target的右邊界# 尋找右邊界,nums[middle] == target的時候更新leftelse: left = middle + 1rightBoder = leftreturn rightBoderdef getLeftBorder(nums:List[int], target:int) -> int:left, right = 0, len(nums)-1 leftBoder = -2 # 記錄一下leftBorder沒有被賦值的情況while left <= right:middle = left + (right-left) // 2if nums[middle] >= target: # 尋找左邊界,nums[middle] == target的時候更新rightright = middle - 1;leftBoder = right;else:left = middle + 1return leftBoderleftBoder = getLeftBorder(nums, target)rightBoder = getRightBorder(nums, target)# 情況一if leftBoder == -2 or rightBoder == -2: return [-1, -1]# 情況三if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1]# 情況二return [-1, -1]

69.x的平方根

leetcode鏈接

二分法:

class Solution:def mySqrt(self, x: int) -> int:left, right, ans = 0, x, -1# 遍歷整數的平方,最大的小于x的值就是結果while left<=right:# 不斷找中值分界點mid = (left+right)//2# 不斷將結果存起來,最后更新保存的結果為最大值if mid*mid<=x:ans = midleft = mid + 1# 縮減大的值else:right = mid - 1return ans

此題還有牛頓迭代法解,只是套用一個公式。



367.有效的完全平方數

leetcode鏈接

二分法:

class Solution:def isPerfectSquare(self, num: int) -> bool:left, right, ans = 0, num, Falsewhile left<=right:mid = (left+right)//2if mid*mid<num:left = mid+1elif mid*mid>num:right = mid-1else:ans=Truereturn ansreturn ans

875.愛吃香蕉的珂珂

leetcode鏈接

暴力解法(超時):

class Solution:def minEatingSpeed(self, piles: List[int], h: int) -> int:# 最慢一次吃一根,最快按最大值去吃每棵樹,時間為樹的個數# 遍歷,尋找某個最小速度,使時間剛好為hfor i in range(1, max(piles)+1):nums = 0# 遍歷樹for j in piles:# 累加每棵樹的次數nums = nums + math.ceil(j/i)# 第一次累計到h,就為吃的最慢,并且在警衛來之前走# 后面存在時間還為h,但是速度稍微快一些的情況,這個就不符合題意了if h==nums:return i

雙指針法:
接著上一個代碼進行修改,因為是遍歷查找,所以可以使用快速查找的算法,二分法。

class Solution:def minEatingSpeed(self, piles: List[int], h: int) -> int:# 最慢一次吃一根,最快按最大值去吃每棵樹,時間為樹的個數# 遍歷,尋找某個最小速度,使時間剛好為hleft, right = 1, max(piles)while left<=right:# 代替循環 for i in range(1, max(piles)+1):直接選取中點為速度mid = (left+right)//2# 累積時間nums = 0# 遍歷樹for j in piles:# 累加每棵樹的次數nums = nums + math.ceil(j/mid)# 時間花的過多,增加速度,if nums>h:left = mid+1else:right = mid-1# 最后的mid與h可能不相等,不能為判斷條件return left

注意這個例子:
piles,h = [312884470], 312884469
v只能取2,但是取2后,時間最多只能為156442235,不可能等于h,因為若等于1則又超時。
那么,二分法的條件判斷,不能以nums==h為條件,最后倒數第二步為left=right=1,nums<h(156442235<312884469),這時left = mid+1=2,此時left>right(2>1),交錯,輸出2為正確結果。



2、元素移除 (暴力解法、雙指針法)

26.刪除有序數組中的重復項

leetcode鏈接
注意:當刪除單個重復元素時,list可以無序,而刪除多個重復元素時,保持相似的算法步驟則需要list有序,(這道題也指明了有序),否則需要較多的更改邏輯結構,比如下面(2)中的第二個解法。

(1). 暴力遍歷:

class Solution:def removeDuplicates(self, nums: List[int]) -> int:# 選取所有不重復,待遍歷的元素for i in set(nums):# 設置計數器,方便后續大于1則刪除count = 0# 遍歷新創建的列表,防止刪除原列表造成索引位移for j in nums[:]:# 重復則+1if i==j:count+=1# 多于一次重復則刪除,否則不管if count>1:nums.remove(i)return len(nums)

(2). 快慢指針:

class Solution:def removeDuplicates(self, nums: List[int]) -> int:fast = 0slow = 0while fast<len(nums):if nums[fast] != nums[slow]:# 下一個索引賦值給新的不重復的值slow+=1nums[slow] = nums[fast]fast+=1# 這里要+1,表示下一位,即表示數組有效長度。# 因為原快慢指針算法,上面slow+1是在賦值之后,而這里是在賦值之前。return slow+1

第二個解法,可以刪除無序list的重復元素,但較多的修改了原算法:

class Solution:def removeDuplicates(self, nums: List[int]) -> int:fast = 0# 從1開始,因為nums[:0]為空,慢指針這相當于取了域值,而不是前面的單個值slow = 1while fast<len(nums):# 這里取nums的slow索引之前的所有值進行重復元素的排查if nums[fast] not in nums[:slow]:# 相當于slow的閾值擴展nums[slow] = nums[fast]# 指向下一個待擴展進閾值的索引slow+=1fast+=1return slow

283.移動零

leetcode鏈接
(1). 暴力遍歷:

class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""for i in nums[:]:# 查詢到0就刪除原表的0,結尾添加0if i==0:nums.remove(0)nums.append(0)

(2). 快慢指針:
先快慢指針把非零的選出來,再根據slow的長度將list后續非有效部分變成0

class Solution:def moveZeroes(self, nums: List[int]) -> None:fast = 0slow = 0while fast<len(nums):if nums[fast] != 0:nums[slow] = nums[fast]slow += 1fast+=1nums[slow:]=[0]*(len(nums)-slow)

每次遇到0就交換,把0換到fast的索引位置,把非0的值換到slow的位置,最后0都在結尾。有點類似冒泡。

class Solution:def moveZeroes(self, nums: List[int]) -> None:fast = 0slow = 0while fast<len(nums):if nums[fast] != 0:nums[slow], nums[fast] = nums[fast], nums[slow]slow += 1fast+=1

844.比較含退格的字符串

leetcode鏈接
(1). 重構字符串:

class Solution:def backspaceCompare(self, s: str, t: str) -> bool:def change(x):tmp = []for p in x:if p != '#':tmp.append(p)elif tmp:tmp.pop()return ''.join(tmp)return change(s) == change(t)

(2). 雙指針:

class Solution:def backspaceCompare(self, S: str, T: str) -> bool:i, j = len(S) - 1, len(T) - 1skipS = skipT = 0while i >= 0 or j >= 0:while i >= 0:if S[i] == "#":skipS += 1i -= 1elif skipS > 0:skipS -= 1i -= 1else:breakwhile j >= 0:if T[j] == "#":skipT += 1j -= 1elif skipT > 0:skipT -= 1j -= 1else:breakif i >= 0 and j >= 0:if S[i] != T[j]:return Falseelif i >= 0 or j >= 0:return Falsei -= 1j -= 1return True

參考答案



977.有序數組的平方

leetcode鏈接
(1). 重構后排序:

class Solution:def sortedSquares(self, nums: List[int]) -> List[int]:nums = list(map(lambda x:x**2, nums))nums.sort()return nums

(2). 雙指針法:
參考答案



3、長度最小的子數組(暴力解法、滑動窗口)

904.水果成籃

leetcode鏈接

(1). 暴力遍歷:
算法同上,但會超時。

(2). 滑動窗口:
因為普通算法會超時,這里用Counter進行存儲每次遍歷的值。

def totalFruit(fruits):# ind表示起始點# s用來存儲最大長度ind,s = 0,0# 使用Counter,累次計數,不然會超時d = Counter()# 開始遍歷for i in range(len(fruits)):print('-------------------------------')# 計數d[fruits[i]]+= 1print(d)# 種類大于2則刪除起始元素# 該被刪除的元素有多少個數,起始點就后移多少位while len(d)>2:print('***1***')print('d1',d)print('dd',fruits[ind])# 起始點前移,減去起始點一次# 如果減到0則刪除,避免占用一個種類d[fruits[ind]]-=1if d[fruits[ind]] == 0:del d[fruits[ind]]print('d2',d)# 起始點前移ind += 1print('***2***')# 選取原長度與處理后(刪除或增加后)的長度的最大長度保留下來s = max(s, i-ind+1)print(s)return stest = [3,3,3,1,2,1,1,2,3,3,4] totalFruit(test)

結果打印:

------------------------------- Counter({3: 1}) 1 ------------------------------- Counter({3: 2}) 2 ------------------------------- Counter({3: 3}) 3 ------------------------------- Counter({3: 3, 1: 1}) 4 ------------------------------- Counter({3: 3, 1: 1, 2: 1}) ***1*** d1 Counter({3: 3, 1: 1, 2: 1}) dd 3 d2 Counter({3: 2, 1: 1, 2: 1}) ***2*** ***1*** d1 Counter({3: 2, 1: 1, 2: 1}) dd 3 d2 Counter({3: 1, 1: 1, 2: 1}) ***2*** ***1*** d1 Counter({3: 1, 1: 1, 2: 1}) dd 3 d2 Counter({1: 1, 2: 1}) ***2*** 4 ------------------------------- Counter({1: 2, 2: 1}) 4 ------------------------------- Counter({1: 3, 2: 1}) 4 ------------------------------- Counter({1: 3, 2: 2}) 5 ------------------------------- Counter({1: 3, 2: 2, 3: 1}) ***1*** d1 Counter({1: 3, 2: 2, 3: 1}) dd 1 d2 Counter({1: 2, 2: 2, 3: 1}) ***2*** ***1*** d1 Counter({1: 2, 2: 2, 3: 1}) dd 2 d2 Counter({1: 2, 2: 1, 3: 1}) ***2*** ***1*** d1 Counter({1: 2, 2: 1, 3: 1}) dd 1 d2 Counter({1: 1, 2: 1, 3: 1}) ***2*** ***1*** d1 Counter({1: 1, 2: 1, 3: 1}) dd 1 d2 Counter({2: 1, 3: 1}) ***2*** 5 ------------------------------- Counter({3: 2, 2: 1}) 5 ------------------------------- Counter({3: 2, 2: 1, 4: 1}) ***1*** d1 Counter({3: 2, 2: 1, 4: 1}) dd 2 d2 Counter({3: 2, 4: 1}) ***2*** 5 5

76.最小覆蓋子串

leetcode鏈接

(1). 暴力遍歷:
方法同上,但會超時

(2). 滑動窗口:
大致思路同上,但是這里需要加上flag進行判斷,進入while循環,也就是起始點后移的的條件,因為字母會出現重復增刪,flag只計算一次,d仍然需要計算每次改變。

def minWindow(s, t):ind,l = 0,'*'*len(s)+'*'# 動態改變d = Counter(t)# while判斷flag = Counter(t)print('d:',d)# 遍歷sfor i in range(len(s)):print('-------------------------')print('1l',l)# s出現在t中if s[i] in d:d[s[i]] -= 1# 為0則t中都出現過,小于0則出現的次數多于t# flag變為0,表示出現過if d[s[i]] <= 0:flag[s[i]]=0print('1d:',d)# 縮小窗口,前移起始索引print('******************')while sum(flag.values()) == 0:# 縮小前,保留值print('cmp:', l, s[ind:i+1])l = min(l, s[ind:i+1], key=len)# 如果刪的是t中的字符,d中減去if s[ind] in d:d[s[ind]] +=1# 待出現的數量大于等于標準# flag變為1表示沒出現if d[s[ind]]>0:flag[s[ind]]=1# 索引前移ind += 1print('******************')print('2l',l)print('2d:',d)print('ind, end', ind, i)return '' if l == '*'*len(s)+'*' else la="ADOBECODEBANC" b="ABC" # "BANC" minWindow(a,b)

結果過程展示:

d: Counter({'A': 1, 'B': 1, 'C': 1}) ------------------------- 1l ************** 1d: Counter({'B': 1, 'C': 1, 'A': 0}) ****************** ****************** 2l ************** 2d: Counter({'B': 1, 'C': 1, 'A': 0}) ind, end 0 0 ------------------------- 1l ************** 1d: Counter({'B': 1, 'C': 1, 'A': 0}) ****************** ****************** 2l ************** 2d: Counter({'B': 1, 'C': 1, 'A': 0}) ind, end 0 1 ------------------------- 1l ************** 1d: Counter({'B': 1, 'C': 1, 'A': 0}) ****************** ****************** 2l ************** 2d: Counter({'B': 1, 'C': 1, 'A': 0}) ind, end 0 2 ------------------------- 1l ************** 1d: Counter({'C': 1, 'A': 0, 'B': 0}) ****************** ****************** 2l ************** 2d: Counter({'C': 1, 'A': 0, 'B': 0}) ind, end 0 3 ------------------------- 1l ************** 1d: Counter({'C': 1, 'A': 0, 'B': 0}) ****************** ****************** 2l ************** 2d: Counter({'C': 1, 'A': 0, 'B': 0}) ind, end 0 4 ------------------------- 1l ************** 1d: Counter({'A': 0, 'B': 0, 'C': 0}) ****************** cmp: ************** ADOBEC ****************** 2l ADOBEC 2d: Counter({'A': 1, 'B': 0, 'C': 0}) ind, end 1 5 ------------------------- 1l ADOBEC 1d: Counter({'A': 1, 'B': 0, 'C': 0}) ****************** ****************** 2l ADOBEC 2d: Counter({'A': 1, 'B': 0, 'C': 0}) ind, end 1 6 ------------------------- 1l ADOBEC 1d: Counter({'A': 1, 'B': 0, 'C': 0}) ****************** ****************** 2l ADOBEC 2d: Counter({'A': 1, 'B': 0, 'C': 0}) ind, end 1 7 ------------------------- 1l ADOBEC 1d: Counter({'A': 1, 'B': 0, 'C': 0}) ****************** ****************** 2l ADOBEC 2d: Counter({'A': 1, 'B': 0, 'C': 0}) ind, end 1 8 ------------------------- 1l ADOBEC 1d: Counter({'A': 1, 'C': 0, 'B': -1}) ****************** ****************** 2l ADOBEC 2d: Counter({'A': 1, 'C': 0, 'B': -1}) ind, end 1 9 ------------------------- 1l ADOBEC 1d: Counter({'A': 0, 'C': 0, 'B': -1}) ****************** cmp: ADOBEC DOBECODEBA cmp: ADOBEC OBECODEBA cmp: ADOBEC BECODEBA cmp: ADOBEC ECODEBA cmp: ADOBEC CODEBA ****************** 2l ADOBEC 2d: Counter({'C': 1, 'A': 0, 'B': 0}) ind, end 6 10 ------------------------- 1l ADOBEC 1d: Counter({'C': 1, 'A': 0, 'B': 0}) ****************** ****************** 2l ADOBEC 2d: Counter({'C': 1, 'A': 0, 'B': 0}) ind, end 6 11 ------------------------- 1l ADOBEC 1d: Counter({'A': 0, 'B': 0, 'C': 0}) ****************** cmp: ADOBEC ODEBANC cmp: ADOBEC DEBANC cmp: ADOBEC EBANC cmp: EBANC BANC ****************** 2l BANC 2d: Counter({'B': 1, 'A': 0, 'C': 0}) ind, end 10 12 'BANC'

239.滑動窗口最大值

leetcode鏈接

滑動窗口

class Solution:def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:n = len(nums)# 注意 Python 默認的優先隊列是小根堆q = [(-nums[i], i) for i in range(k)]# 將列表轉化為堆heapq.heapify(q)# 最大值為堆頂ans = [-q[0][0]]for i in range(k, n):# 插入一個值以及索引heapq.heappush(q, (-nums[i], i))# 不用每次刪除窗口外的值,而是當最大值在窗口外再進行刪除# 判斷堆頂是否在窗口外while q[0][1] <= i - k:# 在窗口外則彈出heapq.heappop(q)# 每次存儲堆頂為最大值ans.append(-q[0][0])return ans

4、過程模擬 (無算法,邏輯思維理解)

54.螺旋矩陣

leetcode鏈接

過程模擬:
套用螺旋矩陣二的模板:

class Solution:def spiralOrder(self, matrix: List[List[int]]) -> List[int]:# 存儲遍歷的值res = []# 長和寬length, width = len(matrix), len(matrix[0])# 上下左右走一圈的次數,最小邊長整除2loop = min(length, width)//2# 起始點,用來定位遍歷點startx, starty = 0, 0# 開始循環for offset in range(1,loop+1):# 從左到右,左閉右開for i in range(starty, width-offset):res.append(matrix[startx][i])# 從上到下,上閉下開for i in range(startx, length-offset):res.append(matrix[i][width-offset])# 從右到左,右閉左開for i in range(width-offset, starty, -1):res.append(matrix[length-offset][i])# 從下到上,下閉上開for i in range(length-offset, startx, -1):res.append(matrix[i][starty])# 起始點下移startx += 1starty += 1# 為正方形時,當為奇數,中間有一個點沒被遍歷到,手動添加,為中點if length == width and length%2!=0:res.append(matrix[length//2][length//2])# 為非長方形時else:# 短的邊為奇數時,添加沒被遍歷到的點if width>length and length%2!=0:for i in range(width-length+1):res.append(matrix[length//2][i+loop])elif width<length and width%2!=0:for i in range(length-width+1):res.append(matrix[i+loop][width//2])return res

劍指Offer29.順時針打印矩陣

leetcode鏈接

思路同上:

class Solution:def spiralOrder(self, matrix: List[List[int]]) -> List[int]:res = []if matrix:length, width = len(matrix),len(matrix[0])loop = min(length, width)//2startx, starty = 0, 0for offset in range(1, loop+1):for i in range(starty, width-offset):res.append(matrix[startx][i])for i in range(startx, length-offset):res.append(matrix[i][width-offset])for i in range(width-offset, starty, -1):res.append(matrix[length-offset][i])for i in range(length-offset, startx, -1):res.append(matrix[i][starty])startx+=1starty+=1if length==width and length%2!=0:res.append(matrix[length//2][length//2])else:if length>width and width%2!=0:for i in range(length-width+1):res.append(matrix[i+loop][width//2])elif length<width and length%2!=0:for i in range(width-length+1):res.append(matrix[length//2][i+loop])return reselse:return res

參考

算法刷題總結 (一) 數組
代碼隨想錄

總結

以上是生活随笔為你收集整理的一、数组经典题型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。