LeetCode習題整理(中等)I

快速排序

class Solution(object):
    def quickSort(self, L, low, high):
        if low < high:
            i = self.partition(L, low, high)
            self.quickSort(L, low, i-1)
            self.quickSort(L, i+1, high)

    def partition(self, L, low, high):
        i, j = low, high
        x = L[low] 
        while i < j:
            while L[j] <= x and i < j:
                j -= 1
            while L[i] >= x and i < j:
                i += 1
            
            if i != j:
                temp = L[j]
                L[j] = L[i]
                L[i] = temp
        '''
        temp = L[j]
        L[j] = L[low]
        L[low] = temp
        '''
        return j

    def lexicalOrder(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        

        L = [str(i) for i in range(1, n+1)]

        self.quickSort(L, 0, n-1)
        return L

分割連接字符串

給定一個字符串列表,你可以將這些字符串連接成一個循環字符串,對於每個字符串,你可以選擇是否翻轉它。在所有可能的循環字符串中,你需要分割循環字符串(這將使循環字符串變成一個常規的字符串),然後找到字典序最大的字符串。

具體來說,要找到字典序最大的字符串,你需要經歷兩個階段:

1.將所有字符串連接成一個循環字符串,你可以選擇是否翻轉某些字符串,並按照給定的順序連接它們。
2.在循環字符串的某個位置分割它,這將使循環字符串從分割點變成一個常規的字符串。
你的工作是在所有可能的常規字符串中找到字典序最大的一個。

示例:
輸入: “abc”, “xyz”
輸出: “zyxcba”
解釋: 你可以得到循環字符串 “-abcxyz-”, “-abczyx-”, “-cbaxyz-”, “-cbazyx-”,
其中 ‘-’ 代表循環狀態。
答案字符串來自第四個循環字符串,
你可以從中間字符 ‘a’ 分割開然後得到 “zyxcba”。

注意:

  1. 輸入字符串只包含小寫字母。
  2. 所有字符串的總長度不會超過 1,000。

答案:

class Solution(object):
    def splitLoopedString(self, strs):
        """
        :type strs: List[str]
        :rtype: str
        """
        # 首先,如果要求是字典排序最大的,那麼對每個字符串而言,
        # 它自己和自己的翻轉字符串之間,選取字典排序大的保留下來,
        # 這樣,後續構造出的拼接字符串纔是大的。
        strs = [s[::-1] if s[::-1] > s else s for s in strs]
        #''.join(strs)是將strs中的每個字符串之間用''連接,最終構成一個字符串
        # 這樣就構成了一個默認串ans,就相當於是從strs的第0個字符串的第0個位置做的分割
        ans = ''.join(strs)
        # enumarate是迭代器,可以同時迭代數組或list等對象的下標和內容。
        for i, s in enumerate(strs):
        # 另外,考慮到分割的位置可能是在任意第i個小字符串中的第j個位置
        # 故首先將第i個小字符串除外,其他的所有字符串拼接起來組成other字符串
            other = ''.join(strs[i + 1:]) + ''.join(strs[: i])
            # 然後,因爲中間部分的other已經有了,那麼,現在就是需要將頭和尾補上
            # 因爲是從strs中的第i個字符串中的第j個位置分割的,所以
            # head = s[j:]爲頭部,tail = s[:j]爲尾部,cur = head + other + tail
            # 另外,通過將ans與不同的cur比較,最終保留最大的放在ans並返回
            for j, _ in enumerate(s):
                head = s[j:]
                tail = s[:j]
                cur = head + other + tail
                ans = max(ans, cur)
                # 注意,這裏還要增加一次將頭和尾同時翻轉的比較,因爲在一開始
                # 我們只是考慮了當字符串沒有從中間切分開的情況下, 取字典排序最大的
                # 保留在strs中,但是,一旦從中間切分開,可能情況就不一樣了,因此
                # 必須增加這一次比較,但是頭和尾是否翻轉,必須是一致的。
                cur = tail[::-1] + other + head[::-1]
                ans = max(ans, cur)
        return ans

花括號展開II

如果你熟悉 Shell 編程,那麼一定了解過花括號展開,它可以用來生成任意字符串。

花括號展開的表達式可以看作一個由 花括號、逗號 和 小寫英文字母 組成的字符串,定義下面幾條語法規則:

如果只給出單一的元素 x,那麼表達式表示的字符串就只有 “x”。
例如,表達式 {a} 表示字符串 “a”。
而表達式 {ab} 就表示字符串 “ab”。
當兩個或多個表達式並列,以逗號分隔時,我們取這些表達式中元素的並集。
例如,表達式 {a,b,c} 表示字符串 “a”,“b”,“c”。
而表達式 {a,b},{b,c} 也可以表示字符串 “a”,“b”,“c”。
要是兩個或多個表達式相接,中間沒有隔開時,我們從這些表達式中各取一個元素依次連接形成字符串。
例如,表達式 {a,b}{c,d} 表示字符串 “ac”,“ad”,“bc”,“bd”。
表達式之間允許嵌套,單一元素與表達式的連接也是允許的。
例如,表達式 a{b,c,d} 表示字符串 “ab”,“ac”,"ad"​​​​​​。
例如,表達式 {a{b,c}}{{d,e}f{g,h}} 可以代換爲 {ab,ac}{dfg,dfh,efg,efh},表示字符串 “abdfg”, “abdfh”, “abefg”, “abefh”, “acdfg”, “acdfh”, “acefg”, “acefh”。
給出表示基於給定語法規則的表達式 expression,返回它所表示的所有字符串組成的有序列表。

假如你希望以「集合」的概念瞭解此題,也可以通過點擊 “顯示英文描述” 獲取詳情。

示例 1:

輸入:"{a,b}{c{d,e}}"
輸出:[“acd”,“ace”,“bcd”,“bce”]

示例 2:

輸入:"{{a,z}, a{b,c}, {ab,z}}"
輸出:[“a”,“ab”,“ac”,“z”]
解釋:輸出中 不應 出現重複的組合結果。

提示:

  1. 1 <= expression.length <= 50
  2. expression[i] 由 ‘{’,’}’,’,’ 或小寫英文字母組成
  3. 給出的表達式 expression 用以表示一組基於題目描述中語法構造的字符串
class S(set):
    def __add__(self, other):
    #|是位運算符
        return S(self | other)
    
    def __mul__(self, other):
        return S(i + j for i, j in itertools.product(self, other))
    
class Solution:
	# python中快速定義函數的方法
	# def 函數名(參數:類型)->返回值類型:函數體
    def braceExpansionII(self, expression: str) -> List[str]:
        expression = re.sub('(\w+)', r'S(["\1"])', expression)
        d = {',': '+', '{': '(', '}': ')'}
        expression = re.sub('[\,\{\}]', lambda x: d[x.group(0)], expression)
        expression = re.sub('\)([S\(])', r')*\1', expression)
        return sorted(S(eval(expression)))

安裝柵欄

在一個二維的花園中,有一些用 (x, y) 座標表示的樹。由於安裝費用十分昂貴,你的任務是先用最短的繩子圍起所有的樹。只有當所有的樹都被繩子包圍時,花園才能圍好柵欄。你需要找到正好位於柵欄邊界上的樹的座標。
示例 1:

輸入: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
輸出: [[1,1],[2,0],[4,2],[3,3],[2,4]]
解釋:

在這裏插入圖片描述
示例 2:

輸入: [[1,2],[2,2],[4,2]]
輸出: [[1,2],[2,2],[4,2]]
解釋:
在這裏插入圖片描述
即使樹都在一條直線上,你也需要先用繩子包圍它們。

注意:

  1. 所有的樹應當被圍在一起。你不能剪斷繩子來包圍樹或者把樹分成一組以上。
  2. 輸入的整數在 0 到 100 之間。
  3. 花園至少有一棵樹。
  4. 所有樹的座標都是不同的。
  5. 輸入的點沒有順序。輸出順序也沒有要求。
class Solution(object):
    def outerTrees(self, points):
  
      n = len(points)
        if n < 3: return points
        pts = sorted(set(points), key = lambda a: (a.x, a.y))
        # 利用向量外積判斷凸點,如果外積小於零說明新的點屬於外圍點,也就是凸點,反之新的點就是凹點。
        cross = lambda o, a, b: (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x)
        
        low = []
        for p in pts:
        	# 若新點是凸點則將新點放入low,將凹點low[-1]從low中刪除。
        	# 先進行下面那半邊外圈線的掃描
            while len(low) > 1 and cross(low[-2], low[-1], p) < 0:
                low.pop()
            low.append(p)
        
        up = []
        for p in reversed(pts):
        	# 若新點是凸點則將新點放入low,將凹點low[-1]從low中刪除。
        	# 再進行上面那半邊外圈線的掃描
            while len(up) > 1 and cross(up[-2], up[-1], p) < 0:
                up.pop()
            up.append(p)
        
        return list(set(low[:-1] + up[:-1]))
              

等差數列劃分II

如果一個數列至少有三個元素,並且任意兩個相鄰元素之差相同,則稱該數列爲等差數列。

例如,以下數列爲等差數列:

1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下數列不是等差數列。

1, 1, 2, 5, 7

數組 A 包含 N 個數,且索引從 0 開始。該數組子序列將劃分爲整數序列 (P0, P1, …, Pk),P 與 Q 是整數且滿足 0 ≤ P0 < P1 < … < Pk < N。

如果序列 A[P0],A[P1],…,A[Pk-1],A[Pk] 是等差的,那麼數組 A 的子序列 (P0,P1,…,PK) 稱爲等差序列。值得注意的是,這意味着 k ≥ 2。

函數要返回數組 A 中所有等差子序列的個數。

輸入包含 N 個整數。每個整數都在 -231 和 231-1 之間,另外 0 ≤ N ≤ 1000。保證輸出小於 2^31-1。

示例:

輸入:[2, 4, 6, 8, 10]

輸出:7

解釋:
所有的等差子序列爲:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]

class Solution:
    def numberOfArithmeticSlices(self, A: List[int]) -> int:
        from collections import defaultdict
        dp = [defaultdict(int) for _ in range(len(A))] 
        res = 0
        for i in range(len(A)):
        # 選擇第i個位置爲當前子序列的最後一個元素
            for j in range(i):
            # 從第0個元素開始到第i個元素
            	# 計算第j個位置元素和第i個位置元素之間的差,記作diff。
                diff = A[i] - A[j]
                # 因爲dp[k][diff]存的是以第k個元素作爲結尾且元素之間的間距爲diff的子序列的個數
                # 故dp[i][diff] += dp[j][diff] +  1,相當於將第i個元素放到了原本第j個元素的後面構成了更長的新的子序列
                dp[i][diff] += dp[j][diff] +  1
                # A[i] - A[j] == diff 且 dp[j][diff] >= 1
                # 則將A[i]放到原本dp[j][diff]所表示的子序列後面生成的新序列滿足長度大於等於3
                if diff in dp[j]:
                    res += dp[j][diff] # 計數
        return res

路徑和IV

對於一棵深度小於 5 的樹,可以用一組三位十進制整數來表示。

對於每個整數:

  1. 百位上的數字表示這個節點的深度 D,1 <= D <= 4。
  2. 十位上的數字表示這個節點在當前層所在的位置 P, 1 <= P <= 8。位置編號與一棵滿二叉樹的位置編號相同。
  3. 個位上的數字表示這個節點的權值 V,0 <= V <= 9。

給定一個包含三位整數的升序數組,表示一棵深度小於 5 的二叉樹,請你返回從根到所有葉子結點的路徑之和。

樣例 1:

輸入: [113, 215, 221]
輸出: 12
解釋:
這棵樹形狀如下:
在這裏插入圖片描述

路徑和 = (3 + 5) + (3 + 1) = 12.

樣例 2:

輸入: [113, 221]
輸出: 4
解釋:
這棵樹形狀如下:
在這裏插入圖片描述

路徑和 = (3 + 1) = 4.

def pathSum(self, nums: List[int]) -> int:
    node = [[None]*8 for _ in range(4)]                # 初始化數組

    for n in nums:
        node[n//100-1][(n-n//100*100)//10-1] = n%10    # 將三位整數所攜帶的節點信息按規則填入數組
                                                       # 百位 n//100 爲層數
                                                       # 十位 (n-n//100*100)//10 爲所處位置
                                                       # 個位 n%10 爲攜帶值
    #print(*node,sep='\n')                             # 用於檢驗所得數組是否正確

    res = 0
    
    for i in range(4):                                 # 對數組進行遍歷
        for j in range(2**i):                          # 第i層最多包含2^i個節點 
                                 
            if node[i][j] != None and (i==3 or (node[i+1][j*2]==None and node[i+1][j*2+1]==None)):                                                      # 判斷是否爲葉節點,條件:
                                                       # 1. 節點值非空
                                                       # 2. 節點是否爲最底層節點,或者子節點爲空
                res += node[i][j]
                ii,jj = i,j
                while ii>0:                            #如果節點爲子節點,自下至上回溯直到根節點
                    ii -= 1
                    jj >>= 1
                    res += node[ii][jj]
    
    return res

我的做法:

class Node():
    def __init__(self, value, left=None, right=None, deep_idx=0, pos_idx=0):
        self.value = value
        self.left = left
        self.right = right
        self.deep_idx = deep_idx
        self.pos_idx = pos_idx
        self.fathernode = None
    def addFartherNode(self, fathernode):
        self.fathernode = fathernode
    
    
class Tree():
    def __init__(self, L):
        nodes = []
        for s in L:
            deep_idx = s // 100
            pos_idx = (s - deep_idx * 100) // 10
            value = (s - deep_idx * 100) % 10

            assert deep_idx>=1 and deep_idx<=4
            assert pos_idx>=1 and pos_idx<=2**(deep_idx-1)
            assert value>=0 and value<=9

            node = Node(value,deep_idx=deep_idx,pos_idx=pos_idx)
            print('deep_idx={}, pos_idx={}, value={}'.format(deep_idx, pos_idx, value))
            nodes.append(node)

        self.root = nodes[0]

        for i in range(len(nodes)-1):
            for j in range(i+1,len(nodes)):
                if nodes[i].deep_idx + 1 == nodes[j].deep_idx and nodes[i].pos_idx * 2 - 1  == nodes[j].pos_idx:
                    nodes[i].left = nodes[j]
                    nodes[j].addFartherNode(nodes[i])
                elif nodes[i].deep_idx + 1 == nodes[j].deep_idx and nodes[i].pos_idx * 2 == nodes[j].pos_idx:
                    nodes[i].right = nodes[j]
                    nodes[j].addFartherNode(nodes[i])
        
        self.FindLeaf(nodes)

        #return self.root, self.Leaves

    def FindLeaf(self, nodes):
        self.Leaves = []
        for node in nodes:
            if node.left == None and node.right == None:
                self.Leaves.append(node)
            

class Solution(object):
    def pathSum(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        tree = Tree(nums)
        
        root, Leafnodes = tree.root, tree.Leaves
        #print(Leafnodes)
        #print('{}->{},{}'.format(root.value,root.right.value))
        self.Sum = 0
        for leaf in Leafnodes:
            fn = leaf
            print(leaf.value)
            #print('[')
            while fn != None:
                self.Sum += fn.value
                #print('{}'.format(fn.value))
                fn = fn.fathernode
            #print(']')
        return self.Sum

將數組分割成和相等的子數組

給定一個有 n 個整數的數組,你需要找到滿足以下條件的三元組 (i, j, k) :

0 < i, i + 1 < j, j + 1 < k < n - 1
子數組 (0, i - 1),(i + 1, j - 1),(j + 1, k - 1),(k + 1, n - 1) 的和應該相等。
這裏我們定義子數組 (L, R) 表示原數組從索引爲L的元素開始至索引爲R的元素。

示例:

輸入: [1,2,1,2,1,2,1]
輸出: True
解釋:
i = 1, j = 3, k = 5.
sum(0, i - 1) = sum(0, 0) = 1
sum(i + 1, j - 1) = sum(2, 2) = 1
sum(j + 1, k - 1) = sum(4, 4) = 1
sum(k + 1, n - 1) = sum(6, 6) = 1

注意:

1 <= n <= 2000。
給定數組中的元素會在 [-1,000,000, 1,000,000] 範圍內。

class Solution:
    def splitArray(self, arr: List[int]) -> bool:
        prefix = arr[::]
        for i in range(1, len(arr)):
            prefix[i] += prefix[i-1]

        mapsum = collections.defaultdict(list)
        for i in range(len(prefix)):
            mapsum[prefix[i]].append(i)

        # find pairs
        pairs = []
        for k in range(5, len(arr)):
            val = prefix[-1]-prefix[k] 
            pairs += [(i+1, k) for i in mapsum[val] if i+5 <= k]
            
        for i, k in pairs:
            for j in range(i+2, k-1):
                if prefix[i-1] == prefix[j-1]-prefix[i] == prefix[k-1]-prefix[j]:
                    return True
        return False

兩數之和

給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。

你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個數組中同樣的元素。

示例:

給定 nums = [2, 7, 11, 15], target = 9

因爲 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

def twoSum(nums, target):
    lens = len(nums)
    j=-1
    for i in range(lens):
        if (target - nums[i]) in nums:
            if (nums.count(target - nums[i]) == 1)&(target - nums[i] == nums[i]):#如果num2=num1,且nums中只出現了一次,說明找到是num1本身。
                continue
            else:
                j = nums.index(target - nums[i],i+1) #index(x,i+1)是從num1後的序列後找num2                
                break
    if j>0:
        return [i,j]
    else:
        return []

找兩個有序數組的中位數

給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。

請你找出這兩個有序數組的中位數,並且要求算法的時間複雜度爲 O(log(m + n))。

你可以假設 nums1 和 nums2 不會同時爲空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

則中位數是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

則中位數是 (2 + 3)/2 = 2.5

方法:
1.題目獲取兩個數組的中位數,那麼遍歷這兩個數組到他們的mid(中間)位置即可
2.將mid前的兩個數存入事先聲明好的長度爲2的數組ary[0,0]
3.接下來根據這兩個數組的總長度判斷直接返回中位數還是取其中間的兩個數相加後的平均值。
圖解:

在這裏插入圖片描述

在這裏插入圖片描述

  1. 判斷是一箇中位數,還是二箇中位數,然後根據對應規則返回結果集。
    在這裏插入圖片描述
class Solution:
    def findMedianSortedArrays(self, nums1, nums2) -> float:
        # 1. 下面這些情況進行處理
        len1 = len(nums1)
        len2 = len(nums2)
        # 一個數組爲空,補上另一個數組,中值/2後還是原來的結果(類似於: 3 * 2 / 2還是原來的結果)
        if len1 == 0: nums1 = nums2
        elif len2 == 0: nums2 = nums1
        if len1 == 1 and len2 == 1: return (nums1[0] + nums2[0]) / 2 # 這個情況直接返回

        # 2. 獲取基本變量信息
        lenAll = len1 + len2
        mid = int(lenAll / 2 + 1) # 使運行到這裏長度總>=3,mid中值的位置(3/2+1=2、4/2+1=3)
        i = j = 0 # 便利索引
        ary = [0, 0] # 存儲中值的列表

        # 3. 核心代碼
        while i < len1 and j < len2:
            # 假定兩個數字長度相同,和一個數組遍歷到臨界點的時候,剛好i + j == mid

            if nums1[i] < nums2[j]:
                ary[(i + j) % 2] = nums1[i]
                i += 1
            else:
                ary[(i + j) % 2] = nums2[j]
                j += 1
            if i + j == mid: break # 達到中值 退出循環
        # 對兩個數組長度不一,以及一個數組下標i或j先行達臨界點(nums1.length = i或nums2.length == j)進行補充
        while i + j < mid and i == len1:
            ary[(i + j) % 2] = nums2[j]
            j += 1
        while i + j < mid and j == len2:
            ary[(i + j) % 2] = nums1[i]
            i += 1

        # 4. 判斷後返回對應的運行結果
        if lenAll % 2 != 0:
            return ary[(i + j - 1) % 2] # 總長度爲奇數,最後一個賦值就是中值。
        else:
            return (ary[0] + ary[1]) / 2 # 總長度爲偶數,直接返回他們相加的平均值。

LRU緩存機制

運用你所掌握的數據結構,設計和實現一個 LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。

獲取數據 get(key) - 如果密鑰 (key) 存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰已經存在,則變更其數據值;如果密鑰不存在,則插入該組「密鑰/數據值」。當緩存容量達到上限時,它應該在寫入新數據之前刪除最久未使用的數據值,從而爲新的數據值留出空間。

進階:

你是否可以在 O(1) 時間複雜度內完成這兩種操作?

示例:

LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 該操作會使得密鑰 2 作廢
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 該操作會使得密鑰 1 作廢
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

import numpy as np

class LRUCache(object):

    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.stack = []
        self.capacity = capacity



    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        # 先獲取鍵值對
        for i in range(len(self.stack)-1, -1, -1):
            if self.stack[i][0] == key:# 如果存在,返回
                #print('找到{}'.format(key))
                last_key_idx = i
                last_key, last_value = self.stack[i][0], self.stack[i][1]
                # 由於最近使用過key這個鍵值對,將其放到stack的最後一位
                self.stack.pop(last_key_idx)
                self.stack.append([last_key, last_value])
                return last_value
       
        return -1
        


    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: None
        """
        for i in range(len(self.stack)-1, -1, -1):
            if self.stack[i][0] == key:
                #這個鍵已經存在,更新該位置的值,並移動到最後面。
                self.stack[i][1] = value
                last_key_idx = i
                last_key, last_value = self.stack[i][0], self.stack[i][1]
                # 由於最近使用過key這個鍵值對,將其放到stack的最後一位
                self.stack.pop(last_key_idx)
                self.stack.append([last_key, last_value])
                return

        if len(self.stack) == self.capacity:
            self.stack.pop(0)
        #print('放入{},{}'.format(key, value))
        self.stack.append([key, value])
        



# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

線程阻塞隊列

from threading import Condition
import threading

class BoundedBlockingQueue(object):
   

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.queue = collections.deque([])
        self.mutex = threading.Lock()
        self.not_full = Condition(self.mutex)
        self.not_empty = Condition(self.mutex)

        
    def enqueue(self, element: int) -> None:
        with self.not_full:
            while self.size() >= self.capacity:
                self.not_full.wait()
            self.queue.appendleft(element)
            self.not_empty.notify_all()


    def dequeue(self) -> int:
        with self.not_empty:
            while not self.size():
                self.not_empty.wait()
            ans = self.queue.pop()
            self.not_full.notify_all()
            return ans

    def size(self) -> int:
        return len(self.queue)

轟炸敵人

想象一下炸彈人遊戲,在你面前有一個二維的網格來表示地圖,網格中的格子分別被以下三種符號佔據:

‘W’ 表示一堵牆
‘E’ 表示一個敵人
‘0’(數字 0)表示一個空位

請你計算一個炸彈最多能炸多少敵人。

由於炸彈的威力不足以穿透牆體,炸彈只能炸到同一行和同一列沒被牆體擋住的敵人。

注意:你只能把炸彈放在一個空的格子裏

示例:

輸入: [[“0”,“E”,“0”,“0”],[“E”,“0”,“W”,“E”],[“0”,“E”,“0”,“0”]]
輸出: 3
解釋: 對於如下網格

0 E 0 0
E 0 W E
0 E 0 0

假如在位置 (1,1) 放置炸彈的話,可以炸到 3 個敵人

class Solution(object):
    def maxKilledEnemies(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        if len(grid) == 0:
            return 0
        rownum = len(grid)
        colnum = len(grid[0])
        Max = 0
        for i in range(rownum):
            for j in range(colnum):
                if grid[i][j] == '0':# 可放置炸彈
                    # 檢查同行或同列是否有牆
                    count_in_row = 0
                    count_in_col = 0
                    
                    for k in range(j+1, colnum):# 向右探索
                        if grid[i][k] == 'W':
                            break
                        elif grid[i][k] == 'E':
                            count_in_row += 1
                    
                    for k in range(j-1, -1, -1):# 向左探索
                        if grid[i][k] == 'W':
                            break
                        elif grid[i][k] == 'E':
                            count_in_row += 1

                    for k in range(i+1, rownum):# 向下探索
                        if grid[k][j] == 'W':
                            break
                        elif grid[k][j] == 'E':
                            count_in_col += 1

                    for k in range(i-1, -1, -1):# 向上探索
                        if grid[k][j] == 'W':
                            break
                        elif grid[k][j] == 'E':
                            count_in_col += 1

                    Count = count_in_row + count_in_col

                    if Count > Max:
                        Max = Count
        
        return Max

字典序排數

給定一個整數 n, 返回從 1 到 n 的字典順序。

例如,

給定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。

請儘可能的優化算法的時間複雜度和空間複雜度。 輸入的數據 n 小於等於 5,000,000。

class Solution(object):
    def lexicalOrder(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        def dfs(cur,n,res): # cur爲根結點
            if cur > n:
                return 
            else:
                res.append(cur)
                for i in range(10):
                    if 10 * cur + i > n: # 比如葉子結點爲14,而n是13,dfs就結束了
                        return 
                    dfs(10 * cur + i, n, res)
        res = []
        # 對每棵樹進行dfs
        for i in range(1,10):
            dfs(i, n, res)
        return res

螺旋矩陣III

在 R 行 C 列的矩陣上,我們從 (r0, c0) 面朝東面開始

這裏,網格的西北角位於第一行第一列,網格的東南角位於最後一行最後一列。

現在,我們以順時針按螺旋狀行走,訪問此網格中的每個位置。

每當我們移動到網格的邊界之外時,我們會繼續在網格之外行走(但稍後可能會返回到網格邊界)。

最終,我們到過網格的所有 R * C 個空間。

按照訪問順序返回表示網格位置的座標列表。

示例 1:

輸入:R = 1, C = 4, r0 = 0, c0 = 0
輸出:[[0,0],[0,1],[0,2],[0,3]]
在這裏插入圖片描述

示例 2:

輸入:R = 5, C = 6, r0 = 1, c0 = 4
輸出:[[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]]

在這裏插入圖片描述

提示:

1 <= R <= 100
1 <= C <= 100
0 <= r0 < R
0 <= c0 < C

class Solution(object):
    def Circle(self, L, R, C, center_i, center_j, r, start_i, start_j):
        # 先向右進一格
        start_j += 1
        if start_i >= 0 and start_i <= R-1 and start_j >= 0 and start_j <= C-1:
            L.append([start_i, start_j])
        # 向下探索
        for i in range(start_i+1, center_i+r+1):
            #print('i={}, start_j={}'.format(i, start_j))
            if i >= 0 and i <= R-1 and start_j >= 0 and start_j <= C-1:
                L.append([i, start_j])
        # 向左探索
        for k in range(start_j-1, center_j-r-1, -1):
            #print('i={}, k={}'.format(i, k))
            if i >= 0 and i <= R-1 and k >= 0 and k <= C-1:
                L.append([i, k])
        # 向上探索
        for m in range(i-1, center_i-r-1, -1):
            #print('m={}, k={}'.format(m, k))
            if m >= 0 and m <= R-1 and k >= 0 and k <= C-1:
                L.append([m, k])
        # 向右探索
        for s in range(k+1, center_j+r+1):
            #print('m={}, s={}'.format(m, s))
            if m >= 0 and m <= R-1 and s >= 0 and s <= C-1:
                L.append([m, s])
        # 增加半徑
        return m, s, r+1

    def spiralMatrixIII(self, R, C, r0, c0):
        """
        :type R: int
        :type C: int
        :type r0: int
        :type c0: int
        :rtype: List[List[int]]
        """
        if R ==1 and C == 1:
            return [[0,0]]

        r_max = max(r0, c0, R-r0-1, C-c0-1)

        print(r_max)

        L = []
        center_i = r0
        center_j = c0
        L.append([r0,c0])
        #L.append([r0,c0+1])
        start_i = r0
        start_j = c0
        r = 1
        while r <= r_max:
            start_i, start_j, r = self.Circle(L, R, C, center_i, center_j, r, start_i, start_j)
            #print(start_i, start_j)
        return L

搜尋名人

假設你是一個專業的狗仔,參加了一個 n 人派對,其中每個人被從 0 到 n - 1 標號。在這個派對人羣當中可能存在一位 “名人”。所謂 “名人” 的定義是:其他所有 n - 1 個人都認識他/她,而他/她並不認識其他任何人。

現在你想要確認這個 “名人” 是誰,或者確定這裏沒有 “名人”。而你唯一能做的就是問諸如 “A 你好呀,請問你認不認識 B呀?” 的問題,以確定 A 是否認識 B。你需要在(漸近意義上)儘可能少的問題內來確定這位 “名人” 是誰(或者確定這裏沒有 “名人”)。

在本題中,你可以使用輔助函數 bool knows(a, b) 獲取到 A 是否認識 B。請你來實現一個函數 int findCelebrity(n)。

派對最多隻會有一個 “名人” 參加。若 “名人” 存在,請返回他/她的編號;若 “名人” 不存在,請返回 -1。

示例 1:

輸入: graph = [
[1,1,0],
[0,1,0],
[1,1,1]
]
輸出: 1
解析: 有編號分別爲 0、1 和 2 的三個人。graph[i][j] = 1 代表編號爲 i 的人認識編號爲 j 的人,而 graph[i][j] = 0 則代表編號爲 i 的人不認識編號爲 j 的人。“名人” 是編號 1 的人,因爲 0 和 2 均認識他/她,但 1 不認識任何人。
示例 2:

輸入: graph = [
[1,0,1],
[1,1,0],
[0,1,1]
]
輸出: -1
解析: 沒有 “名人”

注意:

該有向圖是以鄰接矩陣的形式給出的,是一個 n × n 的矩陣, a[i][j] = 1 代表 i 與 j 認識,a[i][j] = 0 則代表 i 與 j 不認識。
請記住,您是無法直接訪問鄰接矩陣的。

# The knows API is already defined for you.
# @param a, person a
# @param b, person b
# @return a boolean, whether a knows b
# def knows(a, b):

class Solution(object):
    def findCelebrity(self, n):
        """
        :type n: int
        :rtype: int
        """
        for i in range(n):
            j = 0
            while j < n:
                if i != j and knows(i,j) == True:
                    break
                j += 1
            if j == n:
                k = 0
                while k < n:
                    if knows(k, i) == False:
                        break
                    k += 1
                if k == n:
                    return i
        return -1

距離相等的條形碼

在一個倉庫裏,有一排條形碼,其中第 i 個條形碼爲 barcodes[i]。

請你重新排列這些條形碼,使其中兩個相鄰的條形碼 不能 相等。 你可以返回任何滿足該要求的答案,此題保證存在答案。

示例 1:

輸入:[1,1,1,2,2,2]
輸出:[2,1,2,1,2,1]
示例 2:

輸入:[1,1,1,1,2,2,3,3]
輸出:[1,3,1,3,2,1,2,1]

提示:

1 <= barcodes.length <= 10000
1 <= barcodes[i] <= 10000

class Solution(object):
    def rearrangeBarcodes(self, barcodes):
        """
        :type barcodes: List[int]
        :rtype: List[int]
        """
        #print(collections.Counter(barcodes))
        counter = dict(collections.Counter(barcodes))
        #按出現次數統計元素
        sortedCounter = sorted(counter, key=lambda k: 0 - counter[k])
        #print(sortedCounter)
        barcodes = []
        #重新排序
        for i in sortedCounter:
            #print(i)
            barcodes += [i] * counter[i]
            #print([i] * counter[i])
            #print(barcodes)
        
        arrangedBarcodes = [None for _ in range(len(barcodes))]
        #間隔插入
        arrangedBarcodes[::2] = barcodes[:len(arrangedBarcodes[::2])]
        arrangedBarcodes[1::2] = barcodes[len(arrangedBarcodes[::2]):]

        return arrangedBarcodes

稀疏矩陣的乘法

給你兩個 稀疏矩陣 A 和 B,請你返回 AB 的結果。你可以默認 A 的列數等於 B 的行數。

請仔細閱讀下面的示例。

示例:

輸入:

A = [
[ 1, 0, 0],
[-1, 0, 3]
]

B = [
[ 7, 0, 0 ],
[ 0, 0, 0 ],
[ 0, 0, 1 ]
]

輸出:

 |  7 0 0 |   
 | -7 0 3 |   
import numpy as np
class Solution(object):
    def multiply(self, A, B):
        """
        :type A: List[List[int]]
        :type B: List[List[int]]
        :rtype: List[List[int]]
        """
        AD = {}
        BD = {}
        result = np.zeros((len(A),len(B[0])), dtype = int)

        for i in range(len(A)):
            AD[i] = []
            for j in range(len(A[0])):
                if A[i][j] != 0:
                    AD[i].append(j)
        
        for i in range(len(B)):
            BD[i] = []
            for j in range(len(B[0])):
                if B[i][j] != 0:
                    BD[i].append(j)
        
        # 利用AD和BD做A和B的乘法
        for key, value in AD.items():
            for col_A in AD[key]:
                for col_B in BD[col_A]:
                    result[key][col_B] += A[key][col_A] * B[col_A][col_B]
        
        for i in range(len(result)):
            result[i] = list(result[i])

        return list(result)

預測贏家

給定一個表示分數的非負整數數組。 玩家1從數組任意一端拿取一個分數,隨後玩家2繼續從剩餘數組任意一端拿取分數,然後玩家1拿,……。每次一個玩家只能拿取一個分數,分數被拿取之後不再可取。直到沒有剩餘分數可取時遊戲結束。最終獲得分數總和最多的玩家獲勝。

給定一個表示分數的數組,預測玩家1是否會成爲贏家。你可以假設每個玩家的玩法都會使他的分數最大化。

示例 1:

輸入: [1, 5, 2]
輸出: False
解釋: 一開始,玩家1可以從1和2中進行選擇。
如果他選擇2(或者1),那麼玩家2可以從1(或者2)和5中進行選擇。如果玩家2選擇了5,那麼玩家1則只剩下1(或者2)可選。
所以,玩家1的最終分數爲 1 + 2 = 3,而玩家2爲 5。
因此,玩家1永遠不會成爲贏家,返回 False。
示例 2:

輸入: [1, 5, 233, 7]
輸出: True
解釋: 玩家1一開始選擇1。然後玩家2必須從5和7中進行選擇。無論玩家2選擇了哪個,玩家1都可以選擇233。
最終,玩家1(234分)比玩家2(12分)獲得更多的分數,所以返回 True,表示玩家1可以成爲贏家。
注意:

1 <= 給定的數組長度 <= 20.
數組裏所有分數都爲非負數且不會大於10000000。
如果最終兩個玩家的分數相等,那麼玩家1仍爲贏家。

分析:
核心思想就是動態規劃,用一個二維數據dp記錄當前情況是從i到j時,先取分數的人,能比後取分數的人多得多少分。

length=j-i+1從1開始遞增:
1、當長度是1時,先取數的可以多得nums[i]分;
2、當長度是2時,先取數的人取兩個數中較大的數,最終比後取數的人多得abs(nums[i] - nums[j]);
3、當長度大於等於3時,可能先取左邊的數,也可能先取右邊的數,分別可以多得nums[i] - dp[i + 1][j]和num[j] - d[i][j - 1]分,取兩者中較大的數即可。

class Solution(object):
    def PredictTheWinner(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        n = len(nums)
        if n == 1:
            return True
        dp = [[0 for j in range(n)] for i in range(n)]
        for length in range(1, n + 1):
            for i in range(0, n - length + 1):
                j = i + length - 1
                if length == 1:
                    dp[i][j] = nums[i]
                elif length == 2:
                    dp[i][j] = abs(nums[i] - nums[j]) 
                else:
                    dp[i][j] = max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1])# 減號式因爲nums[i]被拿出去之後,另一個人成爲了dp[i+1][j]中先拿的那個人。
        if dp[0][n-1] >= 0:
            return True
        else:
            return False

兩數相加

給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。

如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。

您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。

示例:

輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        p = l1
        q = l2
        result = ListNode(0)
        pre = result
        R = result
        while p != None and q != None:
            S = p.val + q.val + result.val
            if S < 10:
                result.val = S
                Next = ListNode(0)
                
            else:
                result.val = S%10
                Next = ListNode(1)
                
            pre = result
            result.next = Next
            result = result.next

            p = p.next
            q = q.next

        print(result.val)
        
        if result.val == 0:
            pre.next = result.next
            result = pre

            if p != None:
                result.next = p
            elif q != None:
                result.next = q

            #result.next = result.next.next
        else:
            if p != None:
                pre.next = self.addTwoNumbers(result, p)
            elif q != None:
                pre.next = self.addTwoNumbers(result, q)
        
        return R

平面上的最短距離

表 point_2d 保存了所有點(多於 2 個點)的座標 (x,y) ,這些點在平面上兩兩不重合。

寫一個查詢語句找到兩點之間的最近距離,保留 2 位小數。

x y
-1 -1
0 0
-1 -2

最近距離在點 (-1,-1) 和(-1,2) 之間,距離爲 1.00 。所以輸出應該爲:

shortest
1.00

注意:任意點之間的最遠距離小於 10000 。

# Write your MySQL query statement below
select convert(power(power(a.x-b.x, 2)+power(a.y-b.y, 2), 1/2), decimal(7,2)) as shortest
from point_2d as a, point_2d as b
where not (a.x = b.x and a.y = b.y)
order by shortest asc
limit 1;

子數組的最小值之和

給定一個整數數組 A,找到 min(B) 的總和,其中 B 的範圍爲 A 的每個(連續)子數組。

由於答案可能很大,因此返回答案模 10^9 + 7。

示例:

輸入:[3,1,2,4]
輸出:17
解釋:
子數組爲 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。
最小值爲 3,1,2,4,1,1,2,1,1,1,和爲 17。

提示:

1 <= A <= 30000
1 <= A[i] <= 30000

class Solution(object):
    def sumSubarrayMins(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        
        len_A = len(A)
        if len_A == 0:
            return 0
        if len_A == 1:
            return A[0]
        
        ans = 0
        left = [0] * len_A
        right = [0] * len_A
        
        
        # 查找包含A[i]且以A[i]爲最小值的連續子數組
        # 即找到A[i]左邊第一個比A[i]小的值的位置和A[i]右邊第一個比A[i]小的值的位置
        
        stack = []
        for i in range(len_A):
            while stack and A[stack[-1]] > A[i]:
                stack.pop()
            if not stack:
                left[i] = -1
            else:
                left[i] = stack[-1]
            stack.append(i)
        
        
        stack = []
        for i in range(len_A - 1, -1, -1):
            while stack and A[stack[-1]] >= A[i]:
                stack.pop()
            if not stack:
                right[i] = len_A
            else:
                right[i] = stack[-1]
            stack.append(i)
        
        for i in range(len_A):
            # 子數組的左端點有(i-left)種選擇,右端點有(right-i)種選擇
            ans += (i - left[i]) * (right[i] - i) * A[i]
            ans %= 10**9 + 7
        return ans

給單鏈表加一

用一個 非空 單鏈表來表示一個非負整數,然後將這個整數加一。

你可以假設這個整數除了 0 本身,沒有任何前導的 0。

這個整數的各個數位按照 高位在鏈表頭部、低位在鏈表尾部 的順序排列。

示例:

輸入: [1,2,3]
輸出: [1,2,4]

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def __init__(self):
        self.pre = None
    def plusOne(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if self.pre == head:
            new_head = ListNode(1)
            new_head.next = head
            head = new_head
            return new_head

        p = head
        while p.next != self.pre:
            p = p.next
        
        
        s = p.val + 1
        self.pre = p

        if s >= 10:
            # 向前進一位,迭代
            p.val = s % 10
            head = self.plusOne(head)
        else:
            p.val = s
        
        return head

驗證前序遍歷序列二叉搜索樹

給定一個整數數組,你需要驗證它是否是一個二叉搜索樹正確的先序遍歷序列。

你可以假定該序列中的數都是不相同的。

參考以下這顆二叉搜索樹:

 5
/ \

2 6
/
1 3
示例 1:

輸入: [5,2,6,1,3]
輸出: false
示例 2:

輸入: [5,2,1,3,6]
輸出: true
進階挑戰:

您能否使用恆定的空間複雜度來完成此題?

class Solution(object):
    def verifyPreorder(self, preorder):
        """
        :type preorder: List[int]
        :rtype: bool
        """
        '''
        n = len(preorder)
        if n <= 1:
            return True

        center_node = preorder[0]
        division_idx = n
        flag = 0
        for i in range(1, n):
            if flag == 0 and preorder[i] > center_node:
                division_idx = i
                flag = 1
            if division_idx < n and i > division_idx and preorder[i] < center_node:
                return False
        
        re1 = self.verifyPreorder(preorder[1:division_idx])
        re2 = self.verifyPreorder(preorder[division_idx:])

        return re1 and re2
        '''
        stack = []
        new_min = float('-inf')  # 初始化下限值
        for i in range(len(preorder)):
            if preorder[i] < new_min: return False
            while stack and preorder[i] > stack[-1]:
                new_min = stack.pop()
            stack.append(preorder[i])
        return True
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章