面試常見基礎編程題

基礎編程題

二分搜索

  1. 經典二分搜索

    需要注意的點

    • 循環(huán)條件 left <= right 還是 left < right
      • 需要看 left == right 是不是可以進入循環(huán) 可能是target嗎
      • 需要防止程序死循環(huán) 如果left == right == mid 在循環(huán)體內不能出去 就會構成死循環(huán)
    • 左右邊界更新 right = mid - 1 還是 right = mid
    class Solution:
        def bs(self, nums, target):
            left, right = 0, len(nums) - 1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] == target:
                    return mid + 1
                elif nums[mid] < target:
                    left = mid + 1  # 為什么可以+1 因為mid不可能是target 
                else:
                    right = mid - 1  # 同理 這樣也保證了算法可以收斂 不會死循環(huán)
            return -1
    
  2. 一個有重復元素的數組中查找 key 的最左位置

    跟第一題的區(qū)別:

    • 循環(huán)條件
    • 邊界更新
    • 循環(huán)體內不判斷是否找到目標 循環(huán)體外才判斷 需要考慮出循環(huán)的兩種情況
    class Solution:
        def bs(self, nums, target):
            left, right = 0, len(nums) - 1
            while left < right:
                mid = (left + right) // 2
                if nums[mid] < target: # 左半部分可以丟掉 并且mid不可能是target
                    left = mid + 1
                else: # nums[mid] >= target
                    right = mid # 因為mid可能是target
            return right if nums[right] == target else -1 # 因為走到這里有兩種情況 找到目標 或者沒有目標
    

鏈表

  1. O(1)時間復雜度刪除鏈表節(jié)點

    題目描述:給定單向鏈表的頭指針和一個節(jié)點指針嫉拐,定義一個函數在O(1)時間刪除該節(jié)點。
    解題思路:常規(guī)的做法是從鏈表的頭結點開始遍歷,找到需要刪除的節(jié)點的前驅節(jié)點福压,把它的 next 指向要刪除節(jié)點的下一個節(jié)點,平均時間復雜度為O(n)较性,不滿足題目要求呵晚。
    那是不是一定要得到被刪除的節(jié)點的前一個節(jié)點呢?其實不用的。我們可以很方面地得到要刪除節(jié)點的下一個節(jié)點怎栽,如果我們把下一個節(jié)點的內容復制到要刪除的節(jié)點上覆蓋原有的內容,再把下一個節(jié)點刪除沮脖,那就相當于把當前要刪除的節(jié)點刪除了塌忽。

    單向鏈表不能回頭 只能往后面走

    class Solution:
        def deleteNode(self, pHead, Node):
            if pHead == None or Node == None:
                return
            if Node.next:
                Node.val = Node.next.val
                Node.next = Node.next.next
            # 此時確定 Node 位于鏈表尾
            elif pHead == Node: # 鏈表只有一個元素
                pHead = None
            else:
                while pHead.next.next:
                    pHead = pHead.next
                pHead.next = None
            return pHead
    
  1. 翻轉鏈表

    定義兩個指針precur拍埠,每反轉一個節(jié)點涉及到三個操作:

    • 連接cur指針的next
    • 分別移動指針precur

    關于Python 等號左右多個變量同時賦值
    兩個原則:

    • 等號右邊的變量存放的都是舊的值 等號左邊的變量存放的都是新的值
    • 等號左邊的變量會被刷新 注意先后順序 先取值后賦值
    class Solution:
        def ReverseList(self, pHead):
            prev = None # 輔助節(jié)點
            while pHead:
                pHead.next, prev, pHead = prev, pHead, pHead.next
            return prev
    

    正常的代碼

    class Solution:
        def reverse(self, pHead):
            prev = None
            while pHead:
                tp = pHead.next # 存下下一個節(jié)點
                pHead.next = prev
                prev = pHead
                pHead = tp
            return prev
    

    遞歸版本:

    class Solution:
        def ReverseList(self, pHead):
            if not pHead or not pHead.next: # 停止向下遞歸 往回返
                return pHead
            res = self.ReverseList(pHead.next)
            pHead.next.next = pHead # 連接
            pHead.next = None # 尾節(jié)點
            return res
    
  1. 判斷鏈表是否有環(huán)

    快慢指針 如何證明?

    感想: while循環(huán)內部作為函數return出口很常見 while循環(huán)體外往往代表著另外一種情況

    class Solution(object):
        def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            fast, slow = head, head
            while fast and fast.next:
                fast = fast.next.next
                slow = slow.next
                if fast == slow: 
                    return True
            return False
    
  1. 找到環(huán)形鏈表的入口

    先判斷有沒有環(huán) 代碼同上

    之后將快指針移動到鏈表頭 兩個指針同時移動 如何證明土居?枣购?

    使用while - else語法區(qū)分出循環(huán)的兩種情況

    class Solution(object):
        def detectCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            slow = fast = head
            while fast and fast.next:
                slow = slow.next
                fast = fast.next.next
                if slow == fast:
                    break
            else: # 因為出循環(huán)存在兩種情況 所以需要區(qū)分 這里使用while else語法作區(qū)分
                return None
            while head != slow: # 直接移動頭指針
                slow = slow.next
                head = head.next
            return head
    
  1. 計算環(huán)的長度

    快慢指針在環(huán)內相遇之后 讓滿指針繼續(xù)移動 再次相遇經過多少步就可以計算環(huán)的長度

  2. 刪除單鏈表倒數第n個節(jié)點

    class Solution:
        def FindKthToTail(self, head, k):
            # write code here
            if head == None or k <= 0:
                return None
    
            # 設定兩個指針 第一個指針指向頭節(jié)點 第二個指向k-1節(jié)點
            p1, p2 = head, head
            i = 0
            while p2.next and i < k - 1:
                p2 = p2.next
                i += 1
            # while 循環(huán)結束 一定要對各種不同的情況進行判斷
            if i != k - 1:  # 鏈表沒有K個元素
                return None
    
            while p2.next:
                p1, p2 = p1.next, p2.next
            return p1
    

for循環(huán)版本

  class Solution:
    def FindKthToTail(self, head, k):
        if not head or k <= 0:
            return
        fast = slow = head
        for i in range(k - 1):
            if not (fast and fast.next): # 為了保證fast指針最后停下的位置也是非空的  所以加上fast.next
                return
            fast = fast.next

        while fast and fast.next:
            fast = fast.next
            slow = slow.next
        return slow
  1. 求鏈表中間節(jié)點

  2. 判斷兩個鏈表是否相交

隊列和棧

字符串

排序

  1. 插入排序

    • 左側已排序
    • 右側未排序
    • 將未排序部分的第一個元素插入到已排序部分的合適的位置
    • 插入排序穩(wěn)定 相同值的元素的相對順序不會改變
image.png
def insertionSort(nums):
    for i in range(1, len(nums)):
        cur, p = nums[i], i  # 取出當值位置的數值 因此當前位置可以被填充
        while p - 1 >= 0 and nums[p - 1] > cur:
            nums[p] = nums[p - 1]
            p -= 1
        nums[p] = cur
    return nums
  1. 歸并排序

    image.png
def merge_sort(nums):
    if len(nums) <= 1:
        return nums
    mid = len(nums) // 2
    left = merge_sort(nums[:mid])
    right = merge_sort(nums[mid:])
    return merge(left, right)  # 合并左右兩個已經排序的部分

def merge(left, right):
    l, r = 0, 0
    result = [] # 需要開辟新空間存放排完序的結果
    while l < len(left) and r < len(right):
        if left[l] < right[r]:  # 將left與right較小元素按序加入新序列
            result.append(left[l])
            l += 1
        else:
            result.append(right[r])
            r += 1
    result += left[l:]
    result += right[r:]
    return result
  1. 快速排序

    效率底 但是容易理解的版本 生成了新的數組

    def quicksort(nums):
        size = len(nums)
        if not nums or size < 2:  # 遞歸出口,空數組或者只有一個元素的數組都是有序的
            return nums
        idx = 0 # 標定點
        pivot = nums[idx] # 標定值
        less_part = [nums[i] for i in range(size) if nums[i] <= pivot and idx != i]
        great_part = [nums[i] for i in range(size) if nums[i] > pivot and idx != i]
        return quicksort(less_part) + [pivot] + quicksort(great_part)
    

    正常 版本 直接在原始數組上修改

    image.png
    def quickSort(nums, first, last):
        splitpoint = partition(nums, first, last)
        quickSort(nums, first, splitpoint - 1)
        quickSort(nums, splitpoint + 1, last)
    
    
    def partition(nums, first, last):
        rand = randint(first, last)  # 優(yōu)化擦耀,隨機取標定點棉圈,以解決近乎有序的列表
        nums[first], nums[rand] = nums[rand], nums[first]
    
        pivot = nums[first]
        left = first + 1
        right = last
        while True:  # 這里使用了雙路快排,以解決有大量相同值的列表
            while left <= right and nums[left] < pivot:
                left += 1
            while right >= left and nums[right] > pivot:
                right -= 1
    
            if left > right:
                break
            else:
                nums[left], nums[right] = nums[right], nums[left]
                left += 1
                right -= 1 # 這兩行代碼必須有 否則程序可能死循環(huán) 測試樣例 [3,2,2,2,3]
        nums[first], nums[right] = nums[right], nums[first] # right處于<=v部分最后一個元素 
        return right
    
    

動態(tài)規(guī)劃

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末眷蜓,一起剝皮案震驚了整個濱河市分瘾,隨后出現的幾起案子,更是在濱河造成了極大的恐慌吁系,老刑警劉巖德召,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異汽纤,居然都是意外死亡氏捞,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門冒版,熙熙樓的掌柜王于貴愁眉苦臉地迎上來液茎,“玉大人,你說我怎么就攤上這事辞嗡±Φ龋” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵续室,是天一觀的道長栋烤。 經常有香客問我,道長挺狰,這世上最難降的妖魔是什么明郭? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮丰泊,結果婚禮上薯定,老公的妹妹穿的比我還像新娘。我一直安慰自己瞳购,他們只是感情好话侄,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般年堆。 火紅的嫁衣襯著肌膚如雪吞杭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天变丧,我揣著相機與錄音芽狗,去河邊找鬼。 笑死痒蓬,一個胖子當著我的面吹牛译蒂,可吹牛的內容都是我干的。 我是一名探鬼主播谊却,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哑芹!你這毒婦竟也來了炎辨?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤聪姿,失蹤者是張志新(化名)和其女友劉穎碴萧,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體末购,經...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡破喻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了盟榴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曹质。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖擎场,靈堂內的尸體忽然破棺而出羽德,到底是詐尸還是另有隱情,我是刑警寧澤迅办,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布宅静,位于F島的核電站,受9級特大地震影響站欺,放射性物質發(fā)生泄漏姨夹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一矾策、第九天 我趴在偏房一處隱蔽的房頂上張望磷账。 院中可真熱鬧,春花似錦贾虽、人聲如沸够颠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽履磨。三九已至蛉抓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剃诅,已是汗流浹背巷送。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矛辕,地道東北人笑跛。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像聊品,于是被迫代替她去往敵國和親飞蹂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內容