Leetcode 遞歸知識點總結

自古套路留人心,發現自己對遞歸這塊掌握的真的是“感人肺腑“(最近的語文水平斷崖式下跌哎)


來看下Leetcode中Tag爲Recursion的題目

  • [Leetcode 687] Longest Univalue Path:給定二叉樹,求節點值全部相等的最長路徑。路徑不一定要通過樹根。Easy
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def longestUnivaluePath(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root: return 0
        left,right,val = root.left,root.right,root.val
        return max(self.longestlength(left,val)+self.longestlength(right,val),
                   self.longestUnivaluePath(left),self.longestUnivaluePath(right))
    def longestlength(self,root,val):
        if not root or root.val != val:  return 0
        return 1+max(self.longestlength(root.left,val),self.longestlength(root.right,val))
  • [Leetcode 395] Longest Substring with At Least K Repeating Characters:給定一個字符串s(只包含小寫字母),定義子串T,其中所有字符出現次數均不少於k次,返回子串T的最大長度。Medium
    思路:統計當前字符串中出現最少次數的字符c和最少次數s.count(c)。如果該次數s.count(c)>=k說明在字符串中所有的字符次數都大於k,否則用c對字符串進行拆分,然後遞歸求解
class Solution(object):
    def longestSubstring(self, s, k):
        """
        :type s: str
        :type k: int
        :rtype: int
        """
        if len(s)<k: return 0
        c = min(set(s),key=s.count)
        if s.count(c)>=k: return len(s)
        return max(self.longestSubstring(t,k) for t in s.split(c))
  • [Leetcode 698] Partition to K Equal Sum Subsets:判斷數組nums是否可以劃分爲k個和相等的子數組,Medium
    思路:記憶化搜索(Search + Memoization)
class Solution(object):
    def canPartitionKSubsets(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: bool
        """
        if sum(nums) % k: return False
        dmaps = {}
        def dfs(nums, target, k): 
            if nums == []: return False
            if k == 1: return sum(nums) == target
            key = (tuple(nums), k)
            if key in dmaps: return dmaps[key]
            size = len(nums)
            ans = False
            for x in range(1 << size): #枚舉所有的子集
                tsums = 0
                rest = []
                for y in range(size):
                    if (x >> y) & 1:
                        tsums += nums[y]
                    else:
                        rest.append(nums[y])
                if tsums == target and dfs(rest, target, k - 1):
                    ans = True
                    break
            dmaps[key] = ans
            return dmaps[key]
        return dfs(sorted(nums), sum(nums) / k, k)
  • [Leetcode 779] K-th Symbol in Grammar:第一行寫一個0,接下來的每一行,都把上一行的0換成01,把1換成10,求第N行第K列的數字。Medium
    思路:第N行第K列的數字是和第N-1行第K-1列的數字有關係的(這裏需要注意下標是從0開始)即(1,2) -> 1 (3,4)-> 2 … 即 N,K 對應 N,(K+1)/2
    然後 0: 1: 0 2: 1
    1: 1: 1 2: 0
    可以歸納爲 return 0 if ans ^ (K%2) else 1
class Solution(object):
    def kthGrammar(self, N, K):
        """
        :type N: int
        :type K: int
        :rtype: int
        """
        if N == 1: return 0
        ans = self.kthGrammar(N - 1, (K + 1) / 2)
        return 0 if ans ^ (K%2) else 1
  • [Leetcode 794] Valid Tic-Tac-Toe State:判斷一個3X3棋盤是否合法,先者執’X’,後者執’O’,當橫縱或者對角線爲相同符號則結束遊戲。Medium
    思路:統計當前’X’,’O’的個數nx,no 進行判斷
class Solution(object):
    def validTicTacToe(self, board):
        """
        :type board: List[str]
        :rtype: bool
        """
        nx = ''.join(board).count('X')
        no = ''.join(board).count('O')
        wx,wo = self.iswinner(board,'X'),self.iswinner(board,'O')
        if wx: return nx == no + 1 and not wo
        if wo: return nx == no
        return nx - 1 <= no <= nx

    def iswinner(self,board,ch):
        if any(r == ch * 3 for r in board): return True
        if any(c == ch * 3 for c in zip(*board)): return True
        if board[0][0] == board[1][1] == board[2][2] == ch: return True
        if board[0][2] == board[1][1] == board[2][0] == ch: return True
        return False
  • [Leetcode 726] Number of Atoms:將分子式展開,返回各原子的個數,Hard
    思路:字符串處理,分情況討論(其實我覺得這題放在stack更穩妥些)
import collections
class Solution(object):
    def countOfAtoms(self, formula):
        """
        :type formula: str
        :rtype: str
        """
        size = len(formula)
        def getDigit(idx):
            cnt = 0
            while (idx < len(formula) and formula[idx].isdigit()):
                cnt = cnt*10+int(formula[idx])
                idx += 1
            idx-=1
            if cnt:
                return cnt,idx
            else:
                return 1,idx

        stack = [collections.defaultdict(int)]
        idx = 0
        while(idx<len(formula)):
            token = formula[idx]
            if token>='A' and token<='Z':
                ch = token
                idx+=1
                while (idx < len(formula) and formula[idx]>='a' and formula[idx]<='z'):
                    ch+=formula[idx]
                    idx += 1
                cnt,idx = getDigit(idx)
                stack[-1][ch]=stack[-1][ch]+cnt 
            elif token=='(':
                stack.append(collections.defaultdict(int))
            elif token==')':
                idx +=1
                cnt,idx = getDigit(idx)
                for key in stack[-1]:
                    stack[-1][key] = stack[-1][key]*cnt
                tstack = stack.pop()
                for key in tstack:
                    stack[-1][key]+=tstack[key]
            idx+=1

        ret = ''
        for x in sorted(stack[-1].items(),key=lambda x:x[0]):
            if x[1]!=1:
                ret+=x[0]+str(x[1])
            else:
                ret+=x[0]
        return ret
  • [Leetcode 761] Special Binary String:特殊二進制字符串滿足以下條件
    1.) 字符串0和1出現的次數相等
    2.) 非常關鍵,字符串開始一定是以1開頭,且前綴1出現的次數至少與0出現的次數相等。比如”11100100”是special binary string,因爲1出現的次數始終大於等於0。要求我們任意交換兩個相鄰的特殊二進制串(可以交換任意次)使得最終得到的序列的字典序最大,並且滿足是特殊二進制串。Hard
    思考來源
    按照special binary string的定義,首字母一定是”1”,末尾一定是”0”,這兩位是我們無法改變的,所以我們完全可以求解子問題:除了首尾的字符串。各位且慢,舉個例子”1010”,是special binary string,首尾的確分別是1和0,但很遺憾”01”並不是special binary string啊,那怎麼用遞歸解決啊!所以我們需要確保找到”1A….B0”之後,”A…B”也是special binary string。 很簡單,只要第一次出現count == 0的字符串。它除了首尾的子串一定是special binary string。證明:因爲”1A….CB0” count = 0,所以,”1A….CB”時,count = 1,如果”B = 1”,只能爲”1A…C” ,count = 0,這就提前出現了count = 0的情況,吼吼,與假設矛盾。
    嘿,既然能夠找到第一個count = 0的special binary string,並且確保了子問題也是special binary string,就可以遞歸求解了。不過,最終還需要輸出lexicographically,所以排個序再合併之前分解的special binary string.
class Solution(object):
    def makeLargestSpecial(self, S):
        """
        :type S: str
        :rtype: str
        """
        cnt,i,ret = 0,0,[]
        for j,v in enumerate(S):
            cnt = cnt + 1 if v == '1' else cnt-1
            if cnt==0:
                ret.append('1'+self.makeLargestSpecial(S[i+1:j])+'0')
                i = j+1
        return ''.join(sorted(ret)[::-1])

Github答案鏈接(Python)
Recursion

發佈了196 篇原創文章 · 獲贊 73 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章