LEETCODE-刷題個人筆記 Python(1-400)

按tag分類,250/400的重點題目
LEETCODE-刷題個人筆記 Python(1-400)-TAG標籤版本

1.Two Sum(easy)

給定一個整型數組,找出能相加起來等於一個特定目標數字的兩個數。
給定一個整數數組,返回兩個數字的索引,使它們相加到特定目標。 您可以假設每個輸入只有一個解決方案,並且您可能不會兩次使用相同的元素。

思路:建立一個字典,存儲結果,然後在字典裏面找

    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dict = {}
        for i in range(len(nums)):
            complement = target - nums[i]
            if (dict.get(complement)!=None):
                return [dict.get(complement),i]
            else:
                dict[nums[i]] = i
        return None

2. Add Two Numbers(Medium)

給你兩個表示兩個非負數字的鏈表。數字以相反的順序存儲,其節點包含單個數字。將這兩個數字相加並將其作爲一個鏈表返回。
輸入: (2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出: 7 -> 0 -> 8

思路:
1.進位問題
2. l1 和 l2 長度不同
3. .當 l1 + l2 大於1000 進位問題.

    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        add = 0
        head = ListNode(0)
        point = head
        while l1 !=None and l2!=None:
            point.next = ListNode((l1.val+l2.val+add)%10)
            add = (l1.val+l2.val+add)/10
            l1 = l1.next
            l2 = l2.next
            point = point.next
        while l1!=None:
            point.next = ListNode((l1.val+add)%10)
            add = (l1.val+add)/10
            l1 = l1.next
            point = point.next
        while l2!=None:
            point.next = ListNode((l2.val+add)%10)
            add = (l2.val+add)/10
            l2 = l2.next
            point = point.next
        if add>0:
            point.next = ListNode(add)
        return head.next

3.Longest Substring Without Repeating Characters(Medium)

給定一個字符串,找出其沒有重複字符的最大子序列的長度。

思路:定義max_len、start、substring
循環s,當s[end]不在substring->substring+s[end]
否則:while s[start]!=s[end]: start++

    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        max_len = 0
        start = 0
        substring = ''
        for end in range(len(s)):
            if s[end] in substring:
                max_len = max(max_len,len(substring))
                while s[start] !=s[end]:
                    start +=1
                start +=1
                substring = s[start:end+1]
            else:
                substring +=s[end]
        return max(max_len,len(substring))

5. Longest Palindromic Substring(Medium)

給定一個字符串s,找到s中最長的迴文子字符串。您可以假設s的最大長度爲1000。

思路:
分爲兩種情況1、迴文串是奇數2、迴文串是偶數
跳入一個函數判斷當前 i 前後最大回文

    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        substring = ''
        for i in range(len(s)):
                res = self.findsub(s,i,i)
                if len(res)>len(substring):
                    substring = res
                res = self.findsub(s,i,i+1)
                if len(res)>len(substring):
                    substring = res
        return substring
    
    
    def findsub(self,s,j,k):
        while j>=0 and k<len(s) and s[j] == s[k]:
            j-=1
            k+=1
        return s[j+1:k]

6. ZigZag Conversion (Medium)

The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
在這裏插入圖片描述
And then read line by line: “PAHNAPLSIIGYIR”

思路:
1、記得判斷是上升還是下降

    def convert(self, s, numRows):
        """
        :type s: str
        :type numRows: int
        :rtype: str
        """
        if numRows ==1 or len(s)<=numRows:
            return s
        step =1
        index = 0
        L = [""]*numRows
        for i in s:
            L[index] +=i
            if index ==0:
                step = 1
            elif index==numRows-1:
                step = -1
            index +=step
        return ''.join(L)

7. Reverse Integer(Easy)

給定32位有符號整數,整數的反向數字。

思路:
1、記得判斷是正的還是負的
2、判斷x是否越界

    def reverse(self, x):
        """
        :type x: int
        :rtype: int
        """
        sign = [1,-1][x<0]
        x = sign*int(str(abs(x))[::-1])
        if x<=(2**31)-1 and x>=-(2**31):
            return x
        else:
            return 0

8. String to Integer (atoi) (Medium)

string 到 int
1、前面有n個空格 2、除空格外第一個必須爲數字或者 - 或者 + 3、只輸出數字 4、滿足- 231~ 231-1

思路:
按照規格做就好,沒什麼難度

    def myAtoi(self, str):
        """
        :type str: str
        :rtype: int
        """
        ls = list(str.strip())
        if len(ls) == 0 : return 0
        
        sign = -1 if ls[0] == '-' else 1
        if ls[0] in ['-','+'] : del ls[0]
        ret, i = 0, 0
        while i < len(ls) and ls[i].isdigit() :
            ret = ret*10 + ord(ls[i]) - ord('0')
            i += 1
        return max(-2**31, min(sign * ret,2**31-1))

9. Palindrome Number(Easy)

判斷該數字是不是迴文

思路:(兩個特點,x>=0 and (x%10!=0 or x==0))
可以用暴力破解(從左從右判斷),更好的方法是截取一半


           if (x<0 or (x %10 ==0 and x !=0)):
            return False
        
        revertedNumber = 0
        while (x > revertedNumber):
            revertedNumber = revertedNumber * 10 + x%10
            x= int(x/10)
        return x ==revertedNumber or x == int(revertedNumber/10)

11. Container With Most Water (Medium)

在這裏插入圖片描述

思路:首先先從兩邊開始,確定最大的寬,然後再慢慢縮小

    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        i= 0
        j = len(height)-1
        max = 0
        while(i!=j):
            if height[i]<height[j]:
                max = height[i]*(j-i) if height[i]*(j-i)>max else max
                i+=1
            else:
                max = height[j]*(j-i) if height[j]*(j-i)>max else max
                j-=1
        return max

12. Integer to Roman(Medium)

數字轉羅馬

    def intToRoman(self, num):
        """
        :type num: int
        :rtype: str
        """
        #1~9
        I = ['','I','II','III','IV','V','VI','VII','VIII','IX']
        #10-90
        X = ['','X','XX','XXX','XL','L','LX','LXX','LXXX','XC']
        #100-900
        C = ['','C','CC','CCC','CD','D','DC','DCC','DCCC','CM']
        #1000-3000
        M = ['','M','MM','MMM']
        return M[num/1000]+C[(num%1000)/100]+X[(num%100)/10]+I[(num%10)]

13. Roman to Integer(Easy)

羅馬到數字

思路:
1、先統計出每個羅馬數字的個數
2、然後減去前面放置的個數

    def romanToInt(self, s):
        """
        :type s: str
        :rtype: int
        """
        r = 0
        num_I = s.count('I')
        num_V = s.count('V')
        num_X = s.count('X')
        num_L = s.count('L')
        num_C = s.count('C')
        num_D = s.count('D')
        num_M = s.count('M')
        

        r +=num_I*1
        r +=num_V*5
        r +=num_X*10
        r +=num_L*50
        r +=num_C*100
        r +=num_D*500
        r +=num_M*1000
        if num_I>0:
            r += (s.count('IV')+s.count('IX'))*(-2)
        if num_X>0:
            r += (s.count('XL')+s.count('XC'))*(-20)
        if num_C>0:
            r += (s.count('CD')+s.count('CM'))*(-200)
        
        return r

14. Longest Common Prefix(Easy)

編寫一個函數來查找字符串數組中最長的公共前綴字符串。 如果沒有公共前綴,則返回空字符串“”。

思路:學會使用zip函數

    def longestCommonPrefix(self, strs):
        """
        :type strs: List[str]
        :rtype: str
        """
        prefix = ""        
        for i in zip(*strs):
            if i.count(i[0])==len(i):
                prefix +=i[0]
            else:
                return prefix
        return prefix

15. 3Sum(Medium)

給定n個整數的數組nums,是否有元素a,b,c在nums中,a + b + c = 0?找到數組中所有唯一的三元組,它們的總和爲零。

思路:
1、首先給list排序(重點!!)
2、按順序,如果list[i]>0,直接退出(因爲排過序了)
3、如果list[i]==list[i-1],continue
4、定義b =i+1 ;e=len(list)。然後b++,e- -
5、b 和 e 也不能相同,如果用過了(因爲題目要求唯一三元組)

    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()
        all = []
        for i in range(len(nums)-2):
            if nums[i]>0:
                break
            if i !=0 and nums[i]==nums[i-1]:
                continue
            b = i +1
            e = len(nums)-1
            while b<e:
                sum = nums[b]+nums[e]+nums[i]
                if sum>0:
                    e -=1
                elif sum<0:
                    b +=1
                else:
                    all.append([nums[i],nums[b],nums[e]])
                    while b<e and nums[b]==nums[b+1]:
                        b +=1
                    while b<e and nums[e]==nums[e-1]:
                        e -=1
                    b +=1
                    e -=1
        return all

16. 3Sum Closest

給定n個整數和整數目標的數組nums,在nums中找到三個整數,使得總和最接近目標。返回三個整數的總和。您可以假設每個輸入都只有一個解決方案。

思路:
1、和15題解題方案有點像,只不過只需要一個輸出

    def threeSumClosest(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        out = nums[0]+nums[1]+nums[2]
        nums.sort()
        for i in range(len(nums)-2):
            b = i+1
            e = len(nums)-1
            while b<e:
                sum = nums[i]+nums[b]+nums[e]
                if abs(sum-target)<abs(out-target):
                    out = sum
                if sum-target>0:
                    e -=1
                elif sum-target<0:
                    b +=1
                else:
                    return out
        return out

17. Letter Combinations of a Phone Number(Medium)

給定包含2-9(含)的數字的字符串,返回該數字可能表示的所有可能的字母組合。(不包含1)
在這裏插入圖片描述

思路:
1、使用遞歸
2、將當前的和之後生成的進行組合

    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        mapping = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', 
           '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'}
        if len(digits)==0:
            return []
        if len(digits) ==1:
            return list(mapping[digits[0]])
        l = self.letterCombinations(digits[:-1])
        
        return [a+c for a in l for c in mapping[digits[-1]]]

18. 4Sum(Medium)

給定n個整數和整數目標的數組nums,是否有元素a,b,c和d在nums中,a + b + c + d = target?找到數組中所有唯一的四元組,它們給出了目標的總和。

思路:
和3sum差不多,只不過多了一層循環

    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        nums.sort()
        all =[]
        for i in range(len(nums)-3):
            if i>0 and nums[i-1]==nums[i]:
                continue
            for j in range(i+1,len(nums)-2):
                if j!=i+1 and nums[j-1]==nums[j]:
                    continue
                b =j+1
                e = len(nums)-1
                while b<e:
                    sum = nums[i]+nums[j]+nums[e]+nums[b]
                    if sum>target:
                        e -=1
                    elif sum<target:
                        b +=1
                    else:
                        all.append([nums[i],nums[j],nums[b],nums[e]])
                        while b<e and nums[b]==nums[b+1]:
                            
                            b +=1
                        while b<e  and nums[e]==nums[e-1]:
                            e -=1
                        b+=1
                        e-=1
        return all

19. Remove Nth Node From End of List

給定鏈接列表,從列表末尾刪除第n個節點並返回其頭部。

思路:
1、定義兩個指針,相隔n個

    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        pre = head
        cur = head
        for i in range(n):
            cur = cur.next
        if cur==None:
            return head.next
        while cur.next!=None:
            cur = cur.next
            pre = pre.next
        pre.next = pre.next.next
        return head

20. Valid Parentheses有效括號(Easy)

Given a string containing just the characters ‘(’, ‘)’, ‘{’, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets.
Open brackets must be closed in the correct order.
Note that an empty string is also considered valid.

思路:
1、使用壓棧出棧的方法

    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        dict = {')':'(','}':'{',']':'['}
        parentheses = ""
        for i in s:
            if dict.get(i) ==None:
                parentheses +=i
            elif (len(parentheses)!=0) and (parentheses[-1] == dict.get(i)):
                parentheses = parentheses[:-1]    
            else:
                return False
        if parentheses =='':
            return True
        else:
            return False

21. Merge Two Sorted Lists(Easy)

合併兩個已排序的鏈接列表並將其作爲新列表返回。新列表應該通過拼接前兩個列表的節點來完成。

思路:
1、就是合併排序的merge的實現

    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        head = ListNode(0)
        cur = head
        while l1!=None and l2!=None:
            if l1.val>l2.val:
                cur.next = l2
                l2 = l2.next
                
            else:
                cur.next = l1
                l1 = l1.next
            cur = cur.next
        while l1!=None:
            cur.next = l1
            l1 = l1.next
            cur = cur.next
        while l2!=None:
            cur.next = l2
            l2 = l2.next
            cur= cur.next
        return head.next

22. Generate Parentheses(Medium)

給定n對括號,編寫一個函數來生成格式正確的括號的所有組合。

思路:
1、設定兩個變量,代表左邊和右邊的括號數量
2、使用遞歸

    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        def calculate(s,l,r):
            if l==0 and r==0:
                all_s.append(s)
            if l>0:
                calculate(s+'(',l-1,r)
            if l<r:
                calculate(s+')',l,r-1)

        all_s =[]
        if n>0:
            calculate('',n,n)

        return all_s

23. Merge k Sorted Lists(Hard)

合併k個已排序的鏈表並將其作爲一個排序列表返回。分析並描述其複雜性。

思路:
1、將list中的每個元素的值存入list中
2、將list進行排序,然後建立node,加入next


        def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        all_list = []
        head = ListNode(0)
        cur = head
        for i in lists:
            while i:
                all_list.append(i.val)
                i = i.next
        for i in sorted(all_list):
            cur.next = ListNode(i)
            cur = cur.next
        return head.next

24. Swap Nodes in Pairs(Medium)

給定鏈表,交換每兩個相鄰節點並返回其頭部。 您可能無法修改列表節點中的值,只能更改節點本身。

思路:
主要是搞清楚交換的點

    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre,pre.next = self,head
        cur = pre
        while cur.next!=None and cur.next.next !=None:
            a = cur.next
            b = a.next
            cur.next, b.next, a.next = b, a, b.next
            cur = a
        return pre.next

26. Remove Duplicates from Sorted Array(Easy)

給定排序的數組nums,就地刪除重複項,使每個元素只出現一次並返回新的長度。
不要爲另一個數組分配額外的空間,必須通過使用O(1)額外內存修改輸入數組來實現此目的。

思路:使用del

    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        i = 0
        while i < len(nums)-1:
            if nums[i+1] == nums[i]:
                del nums[i+1]
            else:
                i += 1
        return len(nums)

27. Remove Element(Easy)

給定數組nums和值val,在適當位置刪除該值的所有實例並返回新長度。

思路:不需要使用排序,如果等於該值,則將n-1的值賦給i,然後n = n - 1

    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        i = 0
        n = len(nums)
        while(i<n):
            if (nums[i] ==val):
                nums[i]= nums[n-1]
                n -=1
            else:
                i+=1
        return n

28. Implement strStr() (Easy)

返回haystack中第一次出現針的索引,如果針不是haystack的一部分,則返回-1。
在這裏插入圖片描述

思路:
思路一:
使用循環

    def strStr(self, haystack, needle):
    """
    :type haystack: str
    :type needle: str
    :rtype: int
    """
    for i in range(len(haystack) - len(needle)+1):
        if haystack[i:i+len(needle)] == needle:
            return i
    return -1

思路二:
經典的KMP算法 時間複雜度O(m+n)
假設現在文本串S匹配到 i 位置,模式串P匹配到 j 位置

  • 如果j = -1,或者當前字符匹配成功(即S[i] == P[j]),都令i++,j++,繼續匹配下一個字符;
  • 如果j != -1,且當前字符匹配失敗(即S[i] != P[j]),則令 i 不變,j = next[j]。此舉意味着失配時,模式串P相對於文本串S向右移動了j - next [j] 位。
  • next 代表當前字符串之前有多大長度的相同前綴後綴,next就是找最大對稱長度的前綴後綴,然後整體右移一位,初值賦爲-1

已知next [0, …, j],如何求出next [j + 1]

  • 若p[k] == p[j],則next[j + 1 ] = next [j] + 1 = k + 1;
  • 若p[k ] ≠ p[j],如果此時p[ next[k] ] == p[j ],則next[ j + 1 ] = next[k] + 1,否則繼續遞歸前綴索引k = next[k],而後重複此過程。
  • 此過程可以看july寫的例子

改進next

  • 當p[j] != s[i] 時,下次匹配必然是p[ next [j]] 跟s[i]匹配,如果p[j] = p[ next[j] ],必然導致後一步匹配失敗(因爲p[j]已經跟s[i]失配,然後你還用跟p[j]等同的值p[next[j]]去跟s[i]匹配,很顯然,必然失配),所以不能允許p[j] = p[ next[j ]]。如果出現了p[j] = p[ next[j] ]咋辦呢?如果出現了,則需要再次遞歸,即令next[j] = next[ next[j] ]。

尋找next的代碼

    def find_next(self,patten):
        next = [0]*len(patten)
        next[0] = -1
        j = 0
        k = -1
        while j<len(patten) - 1:
            # p[k]表示前綴,p[j]表示後綴
            #如果前綴和後綴的字符相同,則next[j] = k
            if (k ==-1 or patten[j] == patten[k]):
                j+=1
                k+=1
                #爲了防止patten[j+1] == patten[k+1],這樣會重複驗證,必定失敗
                if patten[j]!=patten[k]:
                    next[j] = k #未改進之前只需要這一步
                else:
                    next[j] = next[k]
            
            else:
                k = next[k]
        return next

查找P在S中的位置

    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        # 考慮邊界問題
        if len(needle)==0:
            return 0
        #計算next數組
        next = self.find_next(needle)
        i = 0
        j = 0
        while(i<len(haystack) and j<len(needle)):
            #如果j=-1 或者當前字符匹配成功(s[i] == p[j]),則i++,j++
            if (j ==-1 or haystack[i] == needle[j]):
                i +=1
                j +=1
            #如果匹配失敗,則令i不變,j = next[j]
            else:
                j = next[j]
        if j == len(needle):
            return i-j
        else:
            return -1

還有BM算法和Sunday算法,是比KMP算法更快的算法

29. Divide Two Integers(Medium)

給定兩個整數除數和被除數,除去兩個整數而不使用乘法,除法和mod運算符。 將除數除以除數後返回商。 整數除法應截斷爲零。

思路:
1、先判斷除數和被除數時候有其中一個爲負(((dividend^divisor)>>31)
2、利用左移操作來實現出發過程。將一個數左移等於將一個數×2,取一個tmp = divisor,所以將除數tmp不斷左移,直到其大於被除數dividend,然後得到dividend - tmp,重複這個過程。
3、返回 return max(-res,-2147483648) if ((dividend^divisor)>>31) else min(res,2147483647)

        if abs(dividend) < abs(divisor):
            return 0

        ans = 0
        while dividend >= divisor:
            cnt = 1
            tmp = divisor

            while tmp << 2 < dividend:
                cnt <<= 2 
                tmp <<= 2
            ans += cnt
            dividend -= tmp
        return max(-res,-2147483648) if ((dividend^divisor)>>31) else min(res,2147483647)

30. Substring with Concatenation of All Words(Hard)

您將獲得一個字符串s , 以及一個長度相同的單詞words。在s中查找substring(s)的所有起始索引,它們是單詞中每個單詞的串聯,只有一次,沒有任何插入字符。(單詞可以不按順序)
Input:
s = “barfoothefoobarman”,
words = [“foo”,“bar”]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are “barfoor” and “foobar” respectively.
The output order does not matter, returning [9,0] is fine too.

思路:
1、先將words存入字典,統計每個單詞的個數
2、for循環,while尋找
3、還需要一個字典存儲已經有的詞

    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        numword = len(words)
        if numword ==0 or len(s)==0:
            return []
        dict ={}
        for i in words:
            if i not in dict:
                dict[i] =1
            else:
                dict[i] +=1
        
        j = 0
        lw = len(words[0])
        res =[]
        for i in range(len(s)-lw*numword+1):
            count_word ={}
            j=0
            while (j<numword):
                temp = s[i+j*lw:i+(j+1)*lw]
                if temp not in dict:
                    break
                if temp not in count_word:
                    count_word[temp] = 1
                else:
                    count_word[temp] +=1
                if count_word[temp]>dict[temp]:
                    break
                j+=1
            if j == numword:
                res.append(i)
        return res

31. Next Permutation(Medium)

產生下一個序列,對給定序列進行重排,生成一個字母順序比它更大的下一個序列。
如果給定的序列已經是按字母順序排列中最大的一個了,則進行逆序排列。
算法在數組內進行,不要使用額外空間。

思路:
i = len -2 j = len-1
1、從後往前遍歷,i 找到第一個不滿足升序的元素;如果都是升序,則i爲-1(從後往前看的升序)
2、當 j>i 時,找到一個 j 的值大於 i 的,然後和 i 交換
3、將 i 之後的元素進行排序操作

    def nextPermutation(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        if not nums: return nums
        l = len(nums)
        i, j = l - 2, l - 1
        while i >= 0 and nums[i] >= nums[i+1]:
            i -= 1
        while j > i and nums[j] <= nums[i]:
            j -= 1
        nums[i], nums[j] = nums[j], nums[i]
        nums[i+1:] = sorted(nums[i+1:])

32. Longest Valid Parentheses(Hard)

給定一個只包含字符’(‘和’)'的字符串,找到最長的有效(格式良好)括號子字符串的長度。

思路:
1、使用DP算法
2、遇到 ‘(’ 不一定合法
3、當i = ’)’ 時:分兩種情況
當 i-1 = ‘(‘時,dp[i] = dp[i-2] +2
當 i-1 = ‘)’ 時,要找到 s[i - 1 - dp[i - 1]] 這個字符,判斷它是否==’(’ 。且要加上dp[i-dp[i-1]-2]上的值

    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        if len(s)==0:
            return 0
        dp = [0]*len(s)
        for i in range(len(s)):
            if i-1>=0 and s[i]==')':
                if s[i-1]=='(':
                    if i-2>0:
                        dp[i] = dp[i-2]+2
                    else:
                        dp[i] = 2
                elif s[i-1]==')':
                    if i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=='(':
                        if i-dp[i-1]-2>=0:
                            dp[i] = dp[i-dp[i-1]-2]+dp[i-1]+2
                        else:
                            dp[i] = dp[i-1]+2
        return max(dp)

33. Search in Rotated Sorted Array(Medium)

按升序排序的數組在事先未知的某個樞軸處旋轉。 (即[0,1,2,4,5,6,7]可能變爲[4,5,6,7,0,1,2])。
您將獲得要搜索的目標值。如果在數組中找到則返回其索引,否則返回-1。

思路:使用二分法,如果中間的點比右邊的點小,說明右邊時有序的,否則左邊時有序的
然後分右邊有序和左邊有序兩種情況進行討論。

    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        l = 0
        r = len(nums)-1
        while(l<=r):
            middle = int((l+r)/2)
            print(middle)
            if nums[middle]==target:
                return middle
            # mean right is in order
            if nums[middle]<nums[r]:
                if target>nums[middle] and target<=nums[r]:
                    l = middle+1
                else:
                    r = middle-1
                    print(l,r)
            else:
                if target<nums[middle] and target>=nums[l]:
                    r = middle -1
                else:
                    l = middle +1
        return -1

34. Find First and Last Position of Element in Sorted Array(Medium)

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
在這裏插入圖片描述
思路:
1、使用二分法
2、判斷邊界

    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        low = 0
        high = len(nums)-1
        if high <0 or target<nums[low] or target>nums[high]:
            return [-1,-1]
        while(low<=high):
            middle = int((low+high)/2)
            if nums[middle]>target:
                high = middle-1
            elif nums[middle]<target:
                low = middle+1
            else:
                low = high = middle
                while(low>0 and nums[low-1]==target):
                    low -=1
                while(high<len(nums)-1 and nums[high+1]==target):
                    high +=1
                break
        
        if nums[low]==target:
            return [low,high]
        else:
            return [-1,-1]

35. Search Insert Position(Easy)

給定排序數組和目標值,如果找到目標,則返回索引。如果沒有,請返回索引按順序插入的索引。 您可以假設數組中沒有重複項。
在這裏插入圖片描述

思路:
1、使用二分法
2、當end-start <=1時退出
3、 當target<=start,return start
elif 當target>end, return end +1
else 當target<=end ,return end

    def searchInsert(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        start = 0
        end = len(nums)-1
        
        while(end-start >1):
            middle = int((start+end)/2)
            if nums[middle]>target:
                end = middle
            elif nums[middle]==target:
                return middle
            else:
                start = middle
        
        if target<=nums[start]:
            return start
        elif target>nums[end]:
            return end+1
        else:
            return end

36.有效的數獨

橫豎不能包含相同數字,每個小的九宮格里面不能包含相同數字
給定一個九宮格,判斷是不是合法的數獨

思路:
1、使用一個set來存儲已經存在的元素
2、使用(i/3,j/3)來表示小的九宮格

        big = set()
        for i in xrange(0,9):
            for j in xrange(0,9):
                if board[i][j]!='.':
                    #cur is string
                    cur = board[i][j]
                    if (i,cur) in big or (cur,j) in big or (i/3,j/3,cur) in big:
                        return False
                    big.add((i,cur))
                    big.add((cur,j))
                    big.add((i/3,j/3,cur))
        return True

37.數獨解算器

思路:
1、需要有個判別器,判別加入元素後會不會是合法的數獨,判斷小九宮格有點困難
2、接着使用遞歸,加入元素

def solveSudoku(self, board):
    """ 
    :type board: List[List[str]]
    :rtype: None Do not return anything, modify board in-place instead.
    """
    def isVaild(i,j,c):
        for k in range(9):
            if (board[i][k]==c): return  False
            if (board[k][j]==c): return False
            if (board[3 * (i / 3) + k / 3][3 * (j / 3) + k % 3]==c): return False
        return True
    def slove():
        for i in range(9):
            for j in range(9):
                if board[i][j] =='.':
                    for c in range(1,10):
                        if (isVaild(i,j,str(c))):
                            board[i][j] = str(c)
                        else:
                            continue
                        if (slove()==False):
                            board[i][j] = '.'
                        else:
                            return True
                    return False
        return True
                            
                
    slove()

38. Count and Say(Easy)

The count-and-say sequence is the sequence of integers with the first five terms as following:
1
11
21
1211
111221
1 is read off as “one 1” or 11.
11 is read off as “two 1s” or 21.
21 is read off as “one 2, then one 1” or 1211.
Given an integer n where 1 ≤ n ≤ 30, generate the nth term of the count-and-say sequence.

def countStr(self,s):
    count = 0;ans = "";tmp = s[0]
    for i in range(len(s)):
        if s[i] == tmp:
            count += 1
        else:
            ans += str(count) + tmp
            tmp = s[i];count = 1
    ans += str(count) + tmp
    return ans
def countAndSay(self, n):
    """
    :type n: int
    :rtype: str
    """
    ans = '1'
    while n > 1:
        ans = self.countStr(ans)
        n -= 1
    return ans

39. Combination Sum(Medium)

給定一組候選數字(候選者)(沒有重複)和目標數量(目標),找到候選人數總和目標的候選人中的所有獨特組合。
可以從候選者無限次數中選擇相同的重複數字。
注意: 所有數字(包括目標)都是正整數。 解決方案集不得包含重複的組合。
在這裏插入圖片描述

思路:
1、使用DFS
2、記得排序

def combinationSum(self, candidates, target):
    """
    :type candidates: List[int]
    :type target: int
    :rtype: List[List[int]]
    """
    def dfs(target,path,k):
        if target<0:
            return
        if target==0:
            res.append(path)
            return
        for i in range(k,len(candidates)):
            dfs(target-candidates[i],path+[candidates[i]],i)
            if target-candidates[i]<=0:
                break
    res = []
    candidates.sort()
    dfs(target,[],0)
    return res

40. Combination Sum II(Medium)

給定候選數字(候選者)和目標數量(目標)的集合,找到候選人數量總和爲目標的候選人中的所有獨特組合。
候選人中的每個號碼只能在組合中使用一次。 注意: 所有數字(包括目標)都是正整數。 解決方案集不得包含重複的組合。

思路:要判斷當i>k時 並且candidates[i-1] == candidates[i],要退出
其它和39題類似

    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        def dfs(path,target,k):
            if target<0:
                return
            if target==0:
                # if path not in res:
                res.append(path)
                return
            for i in range(k,len(candidates)):
                if i>k and candidates[i-1] == candidates[i]:
                    continue
                dfs(path+[candidates[i]],target-candidates[i],i+1)
                if target-candidates[i]<=0:
                    break
        
        res = []
        candidates.sort()
        dfs([],target,0)
        
        return res

41. First Missing Positive(Hard)

給定未排序的整數數組,找到最小的缺失正整數。您的算法應該在O(n)時間運行並使用恆定的額外空間。
在這裏插入圖片描述

思路:
1、需要時間複雜度爲n
2、並且是尋找的最小的缺失正整數
3、首先將num[i] 放置在 num[num[i]-1]上,首要要保證num[i]-1<len(num)
4、使用while知道num[i]放到適當的位置,因爲for循環,i會直接跳過,如果不用while
5、找到第一個 nums[i] 不等於i+1,如果沒有,返回 len +1

    def firstMissingPositive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        for i in range(len(nums)):
            while 0<=nums[i]-1<len(nums) and nums[nums[i]-1] != nums[i]:
                temp = nums[i]-1
                nums[temp],nums[i] = nums[i],nums[temp]
        for i in range(len(nums)):
            if nums[i]!=i+1:
                return i+1
        return len(nums)+1

42. Trapping Rain Water(Hard)

給定n個非負整數表示每個柱的寬度爲1的高程圖,計算下雨後能夠捕獲的水量。
在這裏插入圖片描述

思路:
(1)從左向右進行掃描,獲取每個位置的左邊最高的邊。
(2)從右向左進行掃描,獲取每個位置的右邊最高的邊。
(3)再遍歷一邊,找出left[i]和right[i]最小的一個,減去當前值,累加

    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        if len(height)==0:return 0
        left = [0]*len(height)
        left[0] = height[0]
        for i in range(1,len(height)):
            left[i] = max(left[i-1],height[i])
        right = [0]*len(height)
        right[-1] = height[-1]
        for i in range(len(height)-2,-1,-1):
            right[i] = max(right[i+1],height[i])
        res = 0
        for i in range(len(height)):
            res += min(left[i],right[i])-height[i]
        return res

43. Multiply Strings(Medium)

兩個用字符串表示的非負數字,用字符串的方式返回他們的乘積。
Input: num1 = “123”, num2 = “456”
Output: “56088”

思路:
1、定義一個長度爲len(num1)+len(num2),值爲0的list
2、用嵌套for循環,注意進位可能大於10(進位包括前面運算出來的),要再用% and /
3、把s前面的0都去掉,最後把s join一下

    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        if num1=='0' or num2=='0':
            return '0'
        s =[0]*(len(num1)+len(num2))
        for i in range(len(num2)-1,-1,-1):
            add = 0
            for j in range(len(num1)-1,-1,-1):
                a = int(num2[i])*int(num1[j])+add
                add = a/10 + (a%10+s[i+j+1])/10
                s[i+j+1] = (a%10 +s[i+j+1])%10
            s[i] = add
        for i in range(len(s)):
            if s[i] !=0:
                s = s[i:]
                break
        return ''.join(str(i) for i in s)

44. Wildcard Matching(Hard)

Given an input string (s) and a pattern §, implement wildcard pattern matching with support for ‘?’ and ‘’.
‘?’ Matches any single character.
'
’ Matches any sequence of characters (including the empty sequence).

思路:使用迭代
如果遇到了多個*,只用返回最後一個星。還要記錄star的位置和s當前位置
1、使用兩個變量分別記錄最後一個星的位置和當時s的位置
2、四個條件:如果一對一匹配,都加一;如果p爲*,記錄;如果無法匹配且前面有*,P重來,S加一;如果都不匹配,False
3、如果j結束了,P後面應該都要*

    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        i =0
        j =0
        jIndex = -1
        starIndex = -1
        while(j<len(s)):
            ##一對一匹配,都加一
            if (i<len(p) and (s[j]==p[i] or p[i]=='?')):
                i+=1
                j+=1
            ## p爲*,記錄下p和s的索引。P到下一個位置
            elif (i<len(p) and (p[i]=='*')):
                jIndex = j
                starIndex = i
                i+=1
            ## 如果不匹配,則判斷前面是不是有*,同時jIndex前進一步,P則重新來
            elif (starIndex!=-1):
                j = jIndex+1
                i = starIndex+1
                jIndex +=1
            ##如果都不對,返回False
            else:
                return False
        ## j如果結束了,p沒結束,p必須後面都是*
        while(i<len(p)and p[i]=='*'):
            i+=1
        return i==len(p)

45. Jump Game II(Hard)

每次可以向後面跳躍的格子數等於當前的點數。求最少需要多少步就能調大最後的格子。
Input: [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
Jump 1 step from index 0 to 1, then 3 steps to the last index.

思路:
要記錄當前一跳所能到達的最遠距離cur、上一跳所能到達的最遠距離last,和當前所使用跳數
如果i<last,則表示從last這個位置可以直接到達i的位置,res就不需要加1;如果i>last,則表示從last到不了該位置,這一步就是必須的,res就要加1。同時要更新last的值。而cur記錄當前位置可以到達的最大位置,用以更新last的值。

    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # cur表示當前步能到達的最遠位置
        cur=0
        # last表示上一次能到達的最遠位置
        last = 0
        # 記錄總共跳了多少步
        res = 0
        for i in range(len(nums)):
            if i>last:
                last = cur
                res +=1
            if cur<i+nums[i]:
                cur = i+nums[i]
        return res if cur>=len(nums)-1 else 0

46. Permutations(Medium)

全排列問題
Given a collection of distinct integers, return all possible permutations.
在這裏插入圖片描述

思路:使用遞歸dfs,沒啥難度

    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        def dfs(nums,path):
            if len(nums)==0:
                res.append(path)
            for i in range(len(nums)):
                dfs(nums[:i]+nums[i+1:],path+[nums[i]])
        res = []
        dfs(nums,[])
        return res

47. Permutations II(Medium)

全排列問題,加上了有重複數字

思路:首先先排序,使用遞歸之後,加上判斷,如果後一個與前一個相同,則跳過

    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        def dfs(nums,path):
            if len(nums)==0:
                res.append(path)
            for i in range(len(nums)):
                if i>0 and nums[i]==nums[i-1]:
                    continue
                dfs(nums[:i]+nums[i+1:],path+[nums[i]])
        nums.sort()
        res = []
        dfs(nums,[])
        return res

48. Rotate Image(Medium)

旋轉 n*n 矩陣
Rotate the image by 90 degrees (clockwise).

思路:沿着副對角線對摺,然後沿着中線對摺 or 沿着中線對摺,然後沿着對角線對摺

matrix[i][j],matrix[n-j-1][n-i-1] = matrix[n-j-1][n-i-1],matrix[i][j]
        n = len(matrix[0])
        #沿着副對角線對摺
        for i in range(len(matrix)):
            for j in range(len(matrix)-i-1):
                matrix[i][j],matrix[n-j-1][n-i-1] = matrix[n-j-1][n-i-1],matrix[i][j]
        #沿着水平線對摺
        for i in range(len(matrix)/2):
            for j in range(len(matrix[0])):
                matrix[i][j],matrix[n-i-1][j] = matrix[n-i-1][j],matrix[i][j]

49. Group Anagrams(Medium)

給定一個字符串數組,將字謎組合在一起。
Input: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
Output:[[“ate”,“eat”,“tea”],[“nat”,“tan”],[“bat”]]

思路:
1.將字符排序,然後存到字典裏O(NKlogK) (因爲涉及排序)
2.算字符的個數,然後存到字典 O(NK)

    def groupAnagrams(self, strs):
        """
        :type strs: List[str]
        :rtype: List[List[str]]
        """
        a = collections.defaultdict(list)
        for s in strs:
            count = [0]*26
            for c in s:
                count[ord(c)-ord('a')] +=1            
            a[tuple(count)].append(s)
        return a.values()

50. Pow(x, n)(Medium)

自己實現一個pow

思路:
使用連乘的方式會超時,所以使用右移的方式

        m = abs(n)
        ans = 1.0
        while m:
            if m &1:
                ans *=x
            x *=x
            m >>=1
        return ans if n>0 else 1/ans

51 52. N-Queens(Hard)

思路:用DFS實現,重要的是定義一個index,循環一次nums[index] == i
還有一個判斷條件,斜對角絕對值之差!=index-i
定義一個1維長度爲n的向量,用來存儲列的值

51. N-Queens(Hard)

給定整數n,返回n-queens拼圖的所有不同解。

思路:(只需要一維的向量)
1、(判斷斜對角沒有那麼簡單)abs(nums[i]-nums[n])==n-i
2、可以每一行的添加元素,這樣就只需要一個循環,而且不用判斷每一行有沒有一樣的
3、可以使用遞歸來做

    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        def is_vaild(nums,n):
            for i in range(n):
                if abs(nums[i]-nums[n])==n-i or nums[i]==nums[n]:
                    return False
            return True
                
        def dfs(nums,path,index):
            if len(nums)==index:
                res.append(path)
                return
            for i in range(len(nums)):
                nums[index] = i
                if is_vaild(nums,index):
                    temp = '.'*len(nums)
                    dfs(nums,path+[temp[:i]+'Q'+temp[i+1:]],index+1)
                    
            
            
        nums = [0]*n
        res = []
        dfs(nums,[],0)
        return res

52. N-Queens II(Hard)

給定整數n,返回n-queens拼圖的不同解的數量。

思路:和51的思路一樣,但是無需存儲路徑

    def totalNQueens(self, n):
        """
        :type n: int
        :rtype: int
        """
        def is_vaild(nums,index):
            for i in range(index):
                if abs(nums[i]-nums[index])==index-i or nums[i]==nums[index]:
                    return False
            return True
        def dfs(nums,index):
            if index ==len(nums):
                self.res +=1
                return
            for i in range(len(nums)):
                nums[index] = i
                if is_vaild(nums,index):
                    dfs(nums,index+1)
        nums = [0]*n
        self.res = 0
        dfs(nums,0)
        return self.res

53. Maximum Subarray(Easy)

給定整數數組nums,找到具有最大總和並返回其總和的連續子數組(包含至少一個數字)。
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

思路:
通過後一個加上前一個的和,如果前一個是正的話。

    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        for i in range(1,len(nums)):
            if nums[i-1]>0:
                nums[i] +=nums[i-1]
        return max(nums)

54. Spiral Matrix(Medium)

給一個矩陣,輸出其螺旋結果

定義rowBegin,rowEnd ,colBegin,colEnd
然後循環.
注意: 當往上走的時候,和往左走的時候,記得判斷該行或該列符不符合要求(即判斷rowB<=rowE or colB<=colE)

    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        if len(matrix)==0:
            return []
        rowB =0
        rowE = len(matrix)-1
        colB = 0
        colE = len(matrix[0])-1
        res =[]
        while(rowB<=rowE and colB<=colE):
            #right
            for i in range(colB,colE+1):
                res.append(matrix[rowB][i])
            rowB +=1
            
            #down
            for i in range(rowB,rowE+1):
                res.append(matrix[i][colE])
            colE -=1
            
            if rowB<=rowE:
                #left
                for i in range(colE,colB-1,-1):
                    res.append(matrix[rowE][i])
            rowE -=1
            
            #up
            if colB<=colE:
                for i in range(rowE,rowB-1,-1):
                    res.append(matrix[i][colB])
            colB +=1
        return res

55. Jump Game(Medium)

跳棋,給一個list,查看能否到達最後一個
給定一個非負整數數組,您最初定位在數組的第一個索引處。 數組中的每個元素表示該位置的最大跳轉長度。 確定您是否能夠到達最後一個索引。
在這裏插入圖片描述

思路:
給個判斷條件i<cur

        cur = 0
        for i in range(len(nums)):
            if i>cur:
                return False
            cur = max(cur,i+nums[i])
        return True

56. Merge Intervals(Medium)

給定間隔的集合,合併所有重疊的間隔。
在這裏插入圖片描述

思路:
要使用sorted(key = lambda)函數

for k in sorted(intervals,key = lambda i:i.start):
    def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        out = []
        for k in sorted(intervals,key = lambda i:i.start):
            if out and k.start<=out[-1].end:
                out[-1].end = max(out[-1].end,k.end)
            else:
                out.append(k)
        return out

57. Insert Interval(Hard)

給定一組非重疊間隔,在間隔中插入新間隔(必要時合併)。 您可以假設間隔最初是根據其開始時間排序的。

Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].

思路:主要是想清楚判斷條件,要新建一個數組用來存儲
如果插入的數組在兩個數組之間,則要判斷誰的start、end小和大

    def insert(self, intervals, newInterval):
        """
        :type intervals: List[Interval]
        :type newInterval: Interval
        :rtype: List[Interval]
        """
        i =0
        all =[]
        start = newInterval.start
        end = newInterval.end
        while i<len(intervals):
            if intervals[i].end>=start:
                if intervals[i].start>end:
                    break
                start = min(start,intervals[i].start)
                end = max(end,intervals[i].end)
            else:
                all.append(intervals[i])
            i+=1
        all.append(Interval(start,end))
        all += intervals[i:]
        return all

58. Length of Last Word(Easy)

給定字符串s由大寫/小寫字母和空格字符’‘組成,返回字符串中最後一個單詞的長度。
rstrip(’ ') 是指去除末尾的空格
在這裏插入圖片描述

    def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """
        dict = {}
        for i in s:
            if i not in dict:
                dict[i] =1
            else:
                dict[i]+=1
        for i,c in enumerate(s):
            if dict[c] ==1:
                return i
        return -1

59. Spiral Matrix II(Medium)

給定正整數n,以螺旋順序生成填充有從1到n2的元素的方陣。
Input: 3
Output: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

思路:和前面的題類似,用上下左右四個指針

    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        res = [[0 for _ in range(n)] for i in range(n)]
        left =0
        right=n-1
        down =n-1
        up =0
        #left
        j =1
        while(left<=right and up<=down):
            #left
            for i in range(left,right+1):
                res[up][i] = j
                j +=1
            up +=1

            #down
            for i in range(up,down+1):
                res[i][right] = j
                j+=1
            right -=1   
        #right
            for i in range(right,left-1,-1):
                res[down][i] = j
                j +=1
            down -=1

        #up
            for i in range(down,up-1,-1):
                res[i][left] = j
                j+=1
            left +=1
        
        return res

60. Permutation Sequence(Medium)

Given n and k, return the kth permutation sequence.

思路:
在這裏插入圖片描述

    def getPermutation(self, n, k):
        nums = [str(i) for i in range(1,n+1)]
        k -=1
        factor = 1
        res = []
        #計算排列
        for i in range(1,n):
            factor *=i
        for i in reversed(range(n)):
            res.append(nums[k/factor])
            nums.remove(nums[k/factor])
            if i!=0:
                k %=factor
                factor /=i
        return ''.join(res)

61. Rotate List(Medium)

給定鏈表,將列表向右旋轉k個位置,其中k爲非負數。
Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL 右移k位

思路:先找出有多少個,趁前面不注意,然後一次將後面幾個移到前面。

    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        start = head
        end = head
        if end ==None or end.next ==None:
            return head
        i=1
        while(end.next!=None):
            i+=1
            end = end.next
        ##免得走多了一個輪迴
        k%=i
        for j in range(i-k-1):
            start = start.next        
        end.next = head
        head = start.next
        start.next = None
        return head

62. Unique Paths(Medium)

一個人從矩陣的左頂點走到右底點有幾種方式

思路:使用dfs方式會超時,使用DP

dp[i][j] = dp[i-1][j] +dp[i][j-1]
        dp = [[1 for _ in range(n)] for _ in range(m)]
        for i in range(1,m):
            for j in range(1,n):
                dp[i][j] = dp[i-1][j]+dp[i][j-1]
        return dp[-1][-1]

63. Unique Paths II(Medium)

62 題,然後再加上障礙物

思路:首先先用兩個循環,橫向和豎向走一遍,遇到1,則邊0。後一個根據前一個來
然後再用 dp[i][j] = dp[i-1][j] +dp[i][j-1]

        if obstacleGrid[0][0] ==1:
            return 0
        obstacleGrid[0][0] = 1
        for i in range(1,len(obstacleGrid)):
            if obstacleGrid[i][0]!=0:
                obstacleGrid[i][0] =0
            else:
                obstacleGrid[i][0] = obstacleGrid[i-1][0]
        for j in range(1,len(obstacleGrid[0])):
            if obstacleGrid[0][j]!=0:
                obstacleGrid[0][j] =0
            else:
                obstacleGrid[0][j] =obstacleGrid[0][j-1]
                
            
        for i in range(1,len(obstacleGrid)):
            for j in range(1,len(obstacleGrid[0])):
                if obstacleGrid[i][j] ==0:
                    obstacleGrid[i][j] = obstacleGrid[i-1][j]+obstacleGrid[i][j-1]
                else:
                    obstacleGrid[i][j] = 0
        return obstacleGrid[-1][-1]

64. Minimum Path Sum(Medium)

與63題相似
給定m x n網格填充非負數,找到從左上到右下的路徑,最小化了沿其路徑的所有數字的總和。

思路相同

    def minPathSum(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        for i in range(1,len(grid)):
            grid[i][0] += grid[i-1][0]
        for j in range(1,len(grid[0])):
            grid[0][j] +=grid[0][j-1]
        
        for i in range(1,len(grid)):
            for j in range(1,len(grid[0])):
                grid[i][j] +=min(grid[i-1][j],grid[i][j-1])
        return grid[-1][-1]

65.Valid Number(Hard)

判斷是不是合法的數字

使用狀態機來做(num,dot,exp)分別用來表示前面有沒有數字,點,科學記數法e

    def isNumber(self, s):
        """
        :type s: str
        :rtype: bool
        """
        #可以使用狀態機來做 https://blog.csdn.net/weixin_38314447/article/details/79075851
        begin, last = 0,len(s)-1
        #將字符串前後的空格去掉
        while begin<=last and s[begin] == ' ':
            begin +=1
        while begin<=last and s[last] == " ":
            last -=1
            
        #數字前爲正號或者負號的情況,首位後移
        if begin< last and (s[begin]=='+' or s[begin] == '-'):
            begin +=1
        num,dot,exp =False,False,False
        
        while begin<=last:
            # 該字符爲數字
            if s[begin]>='0' and s[begin]<='9':
                num = True
            #若首位爲'.'則返回False, 否則標記爲小數
            elif s[begin]=='.':
                if dot or exp:
                    return False
                dot = True
            #若首位爲'e',則返回False,否則記作科學計數
            elif s[begin] =='e' or s[begin] == 'E':
                if exp or not num:
                    return False
                exp,num = True,False#後面必須要有數字才行
            #若遇到正負號,則判斷前一位是否爲‘e'
            elif s[begin]=='+' or s[begin]=='-':
                if s[begin-1] !='e':
                    return False
            else:
                return False
            begin +=1
        return num

66. Plus One(Easy)

給定表示非負整數的非空數字數組,加上整數的1。
存儲數字使得最高有效數字位於列表的開頭,並且數組中的每個元素包含單個數字。
您可以假設整數不包含任何前導零,除了數字0本身。
在這裏插入圖片描述
思路:
1、首先判斷末尾是不是9,如果是,則變爲0,i+1
2、如果不是9,則加一,返回
3、如果最後都是9,那就插入1在最前面

    def plusOne(self, digits):
        """
        :type digits: List[int]
        :rtype: List[int]
        """
        i = 1
        while i<=len(digits):
            if digits[-i] ==9:
                digits[-i] =0
                i+=1
            else:
                digits[-i] +=1
                return digits
        digits.insert(0,1)
        return digits

67. Add Binary(Easy)

給定兩個二進制字符串,返回它們的總和(也是二進制字符串)。
在這裏插入圖片描述
思路:
1、先將a,b加在一起轉化爲str
2、倒過來,判斷是不是大於2,如果大於,則carry =1
3、循環完,記得判斷carry是不是大於0,大於,則要在最前面加1

    def addBinary(self, a, b):
        """
        :type a: str
        :type b: str
        :rtype: str
        """
        a = int(a)
        b = int(b)
        c = str(a+b)
        d = ''
        carry = 0
        print(c)
        for i in reversed(c):
            num = int(i)+carry
            print(num)
            if num>=2:
                # print(num)
                num -=2
                carry =1
            else:
                carry = 0
            d = str(num)+d
        if carry ==1:
            d = '1'+d
            
        return d

68. Text Justification(Hard)

給定一個單詞數組和一個寬度maxWidth,格式化文本,使每行具有正確的maxWidth字符,並且完全(左和右)對齊。
在這裏插入圖片描述

    #分爲兩種情況,末行和非末行
    #末行,所有單詞中間只有一個空格,後面全部補空格
    #非末行,只有一個單詞,靠左放,其它補空格,
    #多個單詞,計算幾個num和幾個多餘的空格前
    #每個間隔再多方extra/num個,前extra%num個間隔再多放個空格。

n = len(words)
i = 0
res = []
while(i<n):
    j = i+1
    len_words = len(words[i])
    while j<n and len_words+1+len(words[j])<=maxWidth:
        len_words +=1+len(words[j])
        j +=1
    line = words[i]
    if j==n:
        for k in range(i+1,n):
            line +=' ' +words[k]
        while(len(line)<maxWidth):
            line +=' '
    else:
        nums = j-i-1
        if j == i+1:
            while(len(line)<maxWidth):
                line += ' '
        else:
            extraspace = maxWidth -len_words
            for k in range(i+1,j):
                line += ' '
                for l in range((extraspace/nums)):
                    line +=' '
                if (k-i<=extraspace%nums):
                    line +=' '
                line +=words[k]
    res.append(line)
    i =j
for k in res:
    print(len(k))
return res

69. Sqrt(x)(Easy)

計算並返回x的平方根,其中x保證爲非負整數。 由於返回類型是整數,因此將截斷十進制數字,並僅返回結果的整數部分。

思路:
使用二分法來找,使用middle的平方來找

 (x/2+1)^2>x
    def mySqrt(self, x):
        """
        :type x: int
        :rtype: int
        """
        #because (x/2+1)^2>x
        min_x =0
        max_x = int((x/2) + 1)
        while (max_x-min_x>=0):
            middle  = int((min_x+max_x)/2)
            if middle**2 == x:
                return middle
            elif middle**2 <x:
                min_x = middle+1
            else:
                max_x = middle-1
        return max_x

70. Climbing Stairs(Easy)

你正在爬樓梯。它需要n步才能達到頂峯。 每次你可以爬1或2步。您可以通過多少不同的方式登頂?

思路:f(1)=1 f(2)=2
1、假如第一次跳一級臺階,剩下還有n-1級臺階,有f(n-1)種跳法
2、假如第一次條2級臺階,剩下n-2級臺階,有f(n-2)種跳法。
f(n)=f(n-1)+f(n-2)

    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n<=1:
            return 1
        res = [1,1]
        for i in range(n-1):
            sum = res[-1]+res[-2]
            res.append(sum)
        return res[-1]

71. Simplify Path(Medium)

給定文件的絕對路徑(Unix風格),簡化它。或者換句話說,將其轉換爲規範路徑。
請注意,返回的規範路徑必須始終以斜槓/開頭,並且兩個目錄名之間必須只有一個斜槓/。最後一個目錄名稱(如果存在)不得以尾隨/結尾。
Input: “/a//b////c/d//././/…”
Output: “/a/b/c”

先將絕對路徑按照’/‘分開,然後利用stack

    def simplifyPath(self, path):
        """
        :type path: str
        :rtype: str
        """
        p = [i for i in path.split('/') if i!='' and i!='.']
        res =[]
        for i in p:
            if i =='..':
                if res ==[]:
                    continue
                else:
                    res.pop()
            else:
                res.append(i)
        return '/'+'/'.join(res)

72. Edit Distance(Hard)

給定兩個單詞word1和word2,找到將word1轉換爲word2所需的最小操作數。 您對單詞允許以下3個操作:
1、插入一個角色 2、刪除一個字符 3、替換一個角色
在這裏插入圖片描述

思路:
1.如果str1的第i個,也就是str1[i-1]和str2的第j個也就是str2[j-1]相等的話,那麼 dis[i][j] = dis[i-1][j-1]

2.如果str[i-1] != str2[j-1]

2.1 通過替換操作把str[i-1]替換成str2[j-1],那麼

dis[i][j] = dis[i-1][j-1] + 1;

2.2 通過插入操作在str1後面插入str2[j-1], 那麼就相當於計算

dis[i][j] = dis[i][j-1] + 1;

2.3 通過插入操作在str2後面插入str1[i-1],那麼就是

dis[i][j] = dis[i-1][j] + 1;

在上述三個中選一個最小的。迭代更新。

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        dp = [[0 for _ in range(len(word2)+1)] for _ in range(len(word1)+1)]
        for i in range(len(word1)+1): dp[i][0] = i
        for j in range(len(word2)+1): dp[0][j] = j
        
        for i in range(1,len(word1)+1):
            for j in range(1,len(word2)+1):
                if word1[i-1] == word2[j-1]:
                    dp[i][j] = dp[i-1][j-1]
                else:
                    dp[i][j] = min(dp[i-1][j-1]+1,min(dp[i-1][j]+1,dp[i][j-1]+1))
        return dp[-1][-1]

73. Set Matrix Zeroes

給定m×n矩陣,如果元素爲0,則將其整個行和列設置爲0.就地執行。
在這裏插入圖片描述

思路:
#不需要空間的做法
#首先判斷第一行和第一列有沒有0,用bool保存
#利用第一行和第一列來存儲

def setZeroes(self, matrix):
    """
    :type matrix: List[List[int]]
    :rtype: None Do not return anything, modify matrix in-place instead.
    """
    #不需要空間的做法
    #首先判斷第一行和第一列有沒有0,用bool保存
    #利用第一行和第一列來存儲
    first_row = False
    first_col = False
    for i in range(len(matrix)):
        if matrix[i][0]==0:
            first_row = True
    for j in range(len(matrix[0])):
        if matrix[0][j]==0:
            first_col = True
    
    for i in range(1,len(matrix)):
        for j in range(1,len(matrix[0])):
            if matrix[i][j] ==0:
                matrix[0][j] = matrix[i][0] = 0 
    
    for i in range(1,len(matrix)):
        for j in range(1,len(matrix[0])):
            if matrix[0][j]==0 or matrix[i][0] ==0:
                matrix[i][j] =0
    
    if first_row:
        for i in range(len(matrix)):
            matrix[i][0] =0
    if first_col:
        for j in range(len(matrix[0])):
            matrix[0][j] =0

74. Search a 2D Matrix(Medium)

編寫一個有效的算法,搜索sorted m×n矩陣中的值。
每行中的整數從左到右排序。 每行的第一個整數大於前一行的最後一個整數。
在這裏插入圖片描述

先找到值再哪一行,然後再用中值查詢

def searchMatrix(self, matrix, target):
    """
    :type matrix: List[List[int]]
    :type target: int
    :rtype: bool
    """
    i =0
    if matrix ==[] or matrix[0]==[]:
        return False
    while(i<len(matrix)):
        if matrix[i][-1]<target:
            i+=1
            continue
        elif matrix[i][-1]>target:
            left = 0
            right = len(matrix[i])-1
            while left<=right:
                middle = (left+right)/2
                if matrix[i][middle]<target:
                    left = middle+1
                elif matrix[i][middle]>target:
                    right = middle-1
                else:
                    return True
            return False
        else:
            return True
    return False

75. Sort Colors(Medium)

給定一個具有紅色,白色或藍色的n個對象的數組,對它們進行就地排序,使相同顏色的對象相鄰,顏色順序爲紅色,白色和藍色。

def sortColors(self, nums):
    """
    :type nums: List[int]
    :rtype: None Do not return anything, modify nums in-place instead.
    """
    # 使用快排.  [0,i) [i, j) [j, k) are 0s, 1s and 2s
    i =0
    j=0
    for k in range(len(nums)):
        l = nums[k]
        nums[k] =2
        if l<2:
            nums[j] = 1
            j +=1
        if l ==0:
            nums[i] = 0
            i +=1

76. Minimum Window Substring(Hard)

給定一個字符串S和一個字符串T,找到S中的最小窗口,它將包含複雜度爲O(n)的T中的所有字符。
在這裏插入圖片描述

  1. 先統計t中字符串的數量
  2. 定義left、right、min_len指針,left用來收縮,right用來擴張,min_len用來存儲最小字符串
  3. 定義set(len_t),當dict[s[right]]==0時,set(len_t)-=1
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        len_s = len(s)
        len_t = len(t)

        if len_t>len_s or len_s==0 or len_t ==0:
            return ''

        countT1 = {}
        for i in t:
            if i in countT1:
                countT1[i] +=1
            else:
                countT1[i] =1
        left =0
        min_len = (0,100000)
        len_t = len(set(t))
        for right in range(len(s)):
            if s[right] in countT1:
                countT1[s[right]] -=1
                if countT1[s[right]] ==0:
                    len_t -=1
                if len_t ==0:
                    while True:
                        if s[left] not in countT1:
                            left+=1
                        else:
                            #如果最左邊是t的值的話,則值加一,然後左移一位,退出循環繼續找
                            countT1[s[left]] +=1
                            ##很有可能出現某個單詞次數小於0的情況,直到其中一個大於0時,統計
                            if countT1[s[left]]>0:
                                len_t +=1
                                if (min_len[1]-min_len[0])>right -left:
                                    min_len = (left,right)
                                left +=1
                                break
                            left +=1
        if min_len[1]==100000:
            return ''
        return s[min_len[0]:min_len[1]+1]

77. Combinations(Medium)

Given two integers n and k, return all possible combinations of k numbers out of 1 … n.

利用遞歸

    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        res = []
        def dfs(begin,end,k,path):
            if len(path)==k:
                res.append(path)
                return
            for i in range(begin,end):
                dfs(i+1,end,k,path+[i])
        dfs(1,n+1,k,[])
        return res

78. Subsets(Medium)

給定一組不同的整數,nums,返回所有可能的子集(冪集)。

使用遞歸,還無需判斷條件

    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        def dfs(nums,path,begin):
            res.append(path)
            for i in range(begin,len(nums)):
                dfs(nums,path+[nums[i]],i+1)
        res = []
        dfs(nums,[],0)
        return res

79. Word Search(Medium)

Given a 2D board and a word, find if the word exists in the grid.
在這裏插入圖片描述

使用dfs,記得訪問過的要標註

    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        if not board:
            return False
        for i in xrange(len(board)):
            for j in xrange(len(board[0])):
                if self.dfs(board, i, j, word):
                    return True
        return False

    # check whether can find word, start at (i,j) position    
    def dfs(self, board, i, j, word):
        if len(word) == 0: # all the characters are checked
            return True
        if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or word[0]!=board[i][j]:
            return False
        tmp = board[i][j]  # first character is found, check the remaining part
        board[i][j] = "#"  # avoid visit agian 
        # check whether can find "word" along one direction
        res = self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) \
        or self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:])
        board[i][j] = tmp
        return res

80. Remove Duplicates from Sorted Array II(Medium)

給定排序的數組nums,就地刪除重複項,使重複項最多出現兩次並返回新的長度。
在這裏插入圖片描述
思路:使用單層循環,

def removeDuplicates(self, nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    i = 0
    for n in range(len(nums)):
        if i<2 or nums[n]>nums[i-2]:
            nums[i] = nums[n]
            i +=1
    return i

81. Search in Rotated Sorted Array II

假設按升序排序的數組在事先未知的某個樞軸處旋轉。 (即[0,0,1,2,2,5,6]可能成爲[2,5,6,0,0,1,2])。
相較於Ⅰ,多了重複元素。

思路:程序差不多,只不過多了一個判斷,當l ==l+1,l +=1
當middle<right 說明右邊是有序的

    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: bool
        """
        l = 0 
        r = len(nums)-1
        while(l<=r):
            while(l<r and nums[l] == nums[l+1]):
                l +=1
            middle = (l+r)/2
            if nums[middle] == target:
                return True
            if nums[middle]<=nums[r]:
                if nums[middle]<target and target<=nums[r]:
                    l = middle +1
                else:
                    r = middle -1
            else:
                if nums[middle]>target and target>=nums[l]:
                    r = middle -1
                else:
                    l = middle +1
        return False

82. Remove Duplicates from Sorted List II(Medium)

給定已排序的鏈接列表,刪除所有具有重複數字的節點,只留下原始列表中的不同數字。

難度不大,就是給指針判斷

    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre = ListNode(0)
        pre.next = head
        cur = pre
        while cur.next and cur.next.next:
            if cur.next.val ==cur.next.next.val:
                while cur.next.next and cur.next.val ==cur.next.next.val:
                    cur.next.next = cur.next.next.next
                cur.next = cur.next.next
            else:
                cur = cur.next
        return pre.next

83. Remove Duplicates from Sorted List(Easy)

Given a sorted linked list, delete all duplicates such that each element appear only once.

def deleteDuplicates(self, head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if head ==None:
        return head
    cur = head
    while cur.next !=None:
        if cur.val == cur.next.val:
            cur.next = cur.next.next
        else:
            cur = cur.next
            
    return head

84. Largest Rectangle in Histogram***(Hard)

給定n個非負整數表示直方圖的條形高度,其中每個條形的寬度爲1,找到直方圖中最大矩形的區域。

在這裏插入圖片描述
思路:題型和11題類似,但是解法不同。
此題用stack的思想O(n),重要的幾個trick
1、stack = [-1] height.append(0) #在最後面添加一個最小數
2、循環當矩陣不是遞增的時候,彈出末尾的元素,然後算面積。否則stack.append(i)(注:是加入索引)

用棧來模擬,遍歷heights數組,如果大於棧頂元素,就push進去;否則,持續彈棧來計算從棧頂點到降序點的矩陣大小。然後將這一部分全部替換爲降序點的值,即做到了整體依然是有序非降的。
整個過程中,即把所有的局部最大矩陣計算過了,又在寬度範圍內保留了全部的場景。
舉例,2,1,5,6,3的場景。
先加入一個0,方便最後可以全部彈棧出來。變成:2,1,5,6,3,0.
2進棧,1比棧頂小,對2進行出棧,area = 2;
5,6都是非降的,繼續進棧,棧爲1,5,6;
遇到3,是一個降序點;開始彈棧,6出棧,對應area=61; 5出棧對應area=52;下一個1比3小,不需要彈棧。然後將5、6的彈棧後的空位壓棧爲3,這是棧爲1,1,3,3,3;
下一步遇到0,開始依次出棧,得到area=31,32,33,14,1*5。
遍歷結束。整個過程中max的area爲10.

    def largestRectangleArea(self, height):
        #在最後面添加一個最小數
        height.append(0)
        stack = [-1]
        ans = 0
        for i in range(len(height)):
            while height[i]<height[stack[-1]]:
                h = height[stack.pop()]
                w = i - stack[-1] -1
                ans = max(ans,h*w)
                print(ans)
            stack.append(i)
        return ans

85. Maximal Rectangle(Hard)

給定填充0和1的2D二進制矩陣,找到僅包含1的最大矩形並返回其區域。

Input:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
Output: 6

思路:橫着看,根據每一行的計算,然後使用84題的思路

    def maximalRectangle(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if matrix==[] or matrix[0]==[]:
            return 0
        matrix1 = [0 for _ in range(len(matrix[0])+1)]
        max_sum = 0
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                if i ==0:
                    matrix1[j] = int(matrix[i][j])
                else:
                    if matrix[i][j]!='0':
                        matrix1[j] +=  1
                    else:
                        matrix1[j] =0
            stack = [-1]
            for i in range(len(matrix1)):
                while matrix1[i]<matrix1[stack[-1]]:
                    h = matrix1[stack.pop()]
                    w = i-stack[-1] -1
                    max_sum = max(max_sum,h*w)
                stack.append(i)
        return max_sum

86. Partition List(Medium)

給一個鏈表,將小於值x的結點放到所有大於等於值x的結點的前面,不要改變結點之間的順序(例如1,4,3,2,5,2 將2結點提到至4的前面,但4,3,5的順序不變);
在這裏插入圖片描述
思路:設置一個變量,記錄下鏈表中第一次出現大於等於值x結點的位置insertPos。之後遍歷鏈表,將所有小於值x的結點提到這個位置上
(好像還有更好的解法)

    def partition(self, head, x):
        """
        :type head: ListNode
        :type x: int
        :rtype: ListNode
        """
        pre = ListNode(0)
        pre.next = head
        start = pre
        while start.next != None:
            if start.next.val >=x:
                break
            start = start.next
        cur = start
        while cur.next !=None:
            if cur.next.val < x:
                print(cur.val,cur.next.val,start.val,start.next.val)
                cur.next,start.next,start.next.next = cur.next.next,cur.next,start.next
                start = start.next
                # print(cur.val,cur.next.val,start.val,start.next.val)
            else:
                cur = cur.next
            if cur ==None:
                break
        return pre.next

87. Scramble String(Hard)

判斷一個字符串是否爲另一個字符串“亂序”得到,使用樹結構,通過葉子對調的形式
在這裏插入圖片描述
思路:使用dfs,自然要循環所有從i位置切斷的樹。
一步步縮小,(左邊和左邊相同,右邊和右邊相同) 或者(左邊和右邊相同,右邊和左邊相同)
s[:i]==s[-i:] and s[i:]==s[:-i]

    def isScramble(self, s1, s2):
        """
        :type s1: str
        :type s2: str
        :rtype: bool
        """
        if len(s1)!=len(s2) or sorted(s1)!=sorted(s2):
            return False
        if len(s1)<4 or s1==s2:
            return True
        
        for i in range(1,len(s1)):
            if (self.isScramble(s1[:i],s2[:i]) and self.isScramble(s1[i:],s2[i:])) or (self.isScramble(s1[:i],s2[-i:]) and self.isScramble(s1[i:],s2[:-i])):
                return True
        return False

88. Merge Sorted Array(Easy)

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
在nums1和nums2中初始化的元素數分別爲m和n。 您可以假設nums1有足夠的空間(大小大於或等於m + n)來保存nums2中的其他元素。

思路:
1、用nums2來循環,當num1的值大於i時,插入
2、使用一個m變量來存儲當前數組有多大

    def merge(self, nums1, m, nums2, n):
        """
        :type nums1: List[int]
        :type m: int
        :type nums2: List[int]
        :type n: int
        :rtype: void Do not return anything, modify nums1 in-place instead.
        """
        j = 0
        for i in range(n):
            while j<m and nums1[j]<=nums2[i]:
                j+=1
            nums1.insert(j,nums2[i])
            m+=1
            j+=1
        del nums1[m:]

89. Gray Code(Medium)

格雷碼是二進制數字系統,其中兩個連續值僅在一位上不同。 給定代表代碼中總位數的非負整數n,打印格雷碼序列。格雷碼序列必須以0開頭。
Input: 2
Output: [0,1,3,2]
Explanation:
00 - 0
01 - 1
11 - 3
10 - 2

思路:使用 i^(i>>1) 異或
1、有n個bit ,總共 1<<n 個數字

    def grayCode(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        res =[]
        for i in range(1<<n):
            print(i,i>>1,i^(i>>1))
            res.append(i^(i>>1))
        print(res)
        return res

90.Subsets II(Medium)

給定可能包含重複項,nums的整數集合,返回所有可能的子集(冪集)。

思路:
1、使用遞歸,當出現有重複元素,使用判斷if k>i and nums[k]==nums[k-1]
2、記得要對元素進行排序

    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums.sort()
        def dfs(i, path):
            res.append(path)
            for k in range(i,len(nums)):
                if k>i and nums[k-1]==nums[k]:
                    continue
                dfs(k+1,path +[nums[k]])
                
        dfs(0,[])
        return res

91. Decode Ways(Medium)

Input: “12”
Output: 2
Explanation: It could be decoded as “AB” (1 2) or “L” (12).

思路:
因爲dp[i] = dp[i-1] +(dp[i-2] if 0<s[i-1:i+1]<=26)所以只需使用兩個變量存儲(可覆蓋)
一定要注意0不與任何數組成數字的時候,return 0

    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        #使用dp操作
        if len(s)==0 or s[0] =='0':
            return 0
        dp1 = 1
        dp2 = 1
        for i in range(1,len(s)):
            cur = dp2
            #當前面不是0,並且小於26
            if int(s[i-1])!=0 and int(s[i-1:i+1])<=26:
                cur +=dp1
            #如果當前i=0,並且不滿足上面的條件。不是合法的
            if int(s[i])==0 and cur ==dp2:
                return 0
            #如果當前i=0,則只能當成一個元素看
            elif int(s[i]) ==0:
                cur -=dp2
            dp1,dp2 = dp2,cur
        return dp2

92. Reverse Linked List II(Medium)

Reverse a linked list from position m to n. Do it in one-pass.
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL

思路:先把m給找到,然後從m開始到n先調轉,然後再頭尾對應的連上

    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        if m ==n:
            return head
        pre = ListNode(0)
        pre.next = head
        cur = pre
        i = 1
        while i<m:
            cur = cur.next
            i+=1
        #使用m_cur記住reversed的前面一個
        m_cur = cur
        cur = cur.next
        Reversed = None
        #要reverse的自己內部先轉,然後再與外部鏈接
        while i<=n:
            next = cur.next
            cur.next = Reversed
            Reversed = cur
            cur = next
            i+=1
        m_cur.next.next = cur
        m_cur.next = Reversed
        return pre.next
        

93. Restore IP Addresses(Medium)

給定僅包含數字的字符串,通過返回所有可能的有效IP地址組合來恢復它。
在這裏插入圖片描述
思路:
1、使用遞歸,不斷的縮小範圍
2、當point*3<len(s) 不符合。當len(s)==0 and num_point !=0 不符合
3、當字符大於1的時候,要判斷首位不爲0,當字符大於2時,要判斷數值不可大於255

        def dfs(s,num_point,path):
            if len(s)==0:
                if num_point ==0:
                    res.append(path[:-1])
                return
            elif num_point*3 <len(s):
                return
            dfs(s[1:],num_point-1,path +s[0]+'.')
            if 1<len(s) and s[0]!='0':
                dfs(s[2:],num_point-1,path+s[:2]+'.')
            if 2<len(s) and s[0]!='0':
                if int(s[:3])<=255:
                    dfs(s[3:],num_point-1,path +s[:3]+'.')
                else:
                    return
        res =[]
        dfs(s,4,'')
        return res

94. Binary Tree Inorder Traversal(Medium)

樹的中序遍歷

思路:
遞歸很容易實現
使用遍歷的方法左-》中-》右

    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        stack = []
        res = []
        cur = root
        while(cur!=None or stack!=[]):
            if cur!=None:
                stack.append(cur)
                if cur.left !=None:
                    cur = cur.left
                    continue
            cur = stack.pop()
            res.append(cur.val)
            cur = cur.right
        return res

95. Unique Binary Search Trees II(Medium)

給定整數n,生成存儲值1 … n的所有結構上唯一的BST(二叉搜索樹)。
在這裏插入圖片描述

使用遞歸,終止條件:left>right

def generateTrees(self, n):
    """
    :type n: int
    :rtype: List[TreeNode]
    """
    def dfs(left,right):
        if left>right:
            return [None]
        cur = []
        for i in range(left,right+1):
            left_node = dfs(left,i-1)
            right_node = dfs(i+1,right)
            for j in left_node:
                for k in right_node:
                    root = TreeNode(i)
                    root.left = j
                    root.right = k
                    cur.append(root)
        return cur
    if n==0:
        return []
    return dfs(1,n)

96. Unique Binary Search Trees(Medium)

Given n, how many structurally unique BST’s (binary search trees) that store values 1 … n?
在這裏插入圖片描述

思路:
使用dp算法

//由1,2,3,...,n構建的二叉查找樹,以i爲根節點,左子樹由[1,i-1]構成,其右子樹由[i+1,n]構成。
//定義f(i)爲以[1,i]能產生的Unique Binary Search Tree的數目
//若數組爲空,則只有一種BST,即空樹,f(0)=1;
//若數組僅有一個元素1,則只有一種BST,單個節點,f(1)=1;
//若數組有兩個元素1,2,則有兩種可能,f(2)=f(0)*f(1)+f(1)*f(0);
//若數組有三個元素1,2,3,則有f(3)=f(0)*f(2)+f(1)*f(1)+f(2)*f(0)
//由此可以得到遞推公式:f(i)=f(0)*f(i-1)+...+f(k-1)*f(i-k)+...+f(i-1)*f(0)

代碼:

    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        res = [0 for _ in range(n+1)]
        res[0] =1
        res[1] =1
        for i in range(2,n+1):
            for j in range(0,i):
                res[i] += res[j]*res[i-j-1]
        return res[n]

97. Interleaving String(Hard)

給定s1,s2,s3,找出s3是否由s1和s2的交織形成。

思路:(用遞歸回超時)
字符串的子序列或是匹配問題直接就上動態規劃
還可以使用一維dp,不需要兩維,因爲i依賴於前面的i
1、首先判斷橫豎的邊界條件

        for i in range(1,len(s2)+1):
            dp[0][i] = True if s2[i-1]==s3[i-1] and dp[0][i-1] else False
        for i in range(1,len(s1)+1):
            dp[i][0] = True if s1[i-1] == s3[i-1] and dp[i-1][0] else False

2、其次判斷i,j

	(dp[i-1][j] and s1[i-1]==s3[i-1+j]) or (dp[i][j-1] and s2[j-1]==s3[j-1+i])
# ##上動態規劃
    def isInterleave(self, s1, s2, s3):
        if len(s1)+len(s2)!=len(s3):
            return False
        dp=[[False for _ in range(len(s2)+1)] for _ in range(len(s1)+1)]
        dp[0][0] = True
        for i in range(1,len(s2)+1):
            dp[0][i] = True if s2[i-1]==s3[i-1] and dp[0][i-1] else False
        for i in range(1,len(s1)+1):
            dp[i][0] = True if s1[i-1] == s3[i-1] and dp[i-1][0] else False
        
        for i in range(1,len(s1)+1):
            for j in range(1,len(s2)+1):
                dp[i][j] = True if (dp[i-1][j] and s1[i-1]==s3[i-1+j]) or (dp[i][j-1] and s2[j-1]==s3[j-1+i]) else False
        return dp[len(s1)][len(s2)]

98. Validate Binary Search Tree(Medium)

Given a binary tree, determine if it is a valid binary search tree (BST).

思路:
使用遞歸,怎麼設定這個子樹的最大最小值是關鍵(要均在最大最小值之間)。對於沒有最大最小值用None來表示

    def isValidBST(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """  
        if not root:
            return True

        def dfs(root,lower,upper):
            if lower !=None and root.val<= lower:
                return False
            if upper !=None and root.val>=upper:
                return False
            
            left = dfs(root.left,lower,root.val) if root.left else True
            if (left):
                right = dfs(root.right,root.val,upper) if root.right else True
                return right
            else:
                return False
        return dfs(root,None,None)

99. Recover Binary Search Tree(Hard)

Two elements of a binary search tree (BST) are swapped by mistake.Recover the tree without changing its structure.

思路:
使用中序遍歷遞歸(是遞增序列),用pre來存儲中序遍歷的前一個變量(全局的)總共有兩種情況:
1,相鄰的換(只出現一個逆序對)只需將前後兩個值記下,然後進行交換
2,不相鄰的換(出現兩個逆序對)需要記下第一次的第一個,和第二次的第二個值,然後交換

    def recoverTree(self, root):
        """
        :type root: TreeNode
        :rtype: None Do not return anything, modify root in-place instead.
        """
        self.first=None
        self.second = None
        self.pre = None
        
        def dfs(root):
            if root ==None:
                return
            dfs(root.left)
            if self.pre and self.pre.val>root.val:
                if self.first ==None:
                    self.first,self.second = self.pre,root
                else:
                    self.second = root
            self.pre = root
            dfs(root.right)
        dfs(root)
        self.first.val,self.second.val = self.second.val,self.first.val

100. Same Tree(Easy)

給定兩個二叉樹,編寫一個函數來檢查它們是否相同。 如果兩個二叉樹在結構上相同並且節點具有相同的值,則認爲它們是相同的。

思路:
均使用遞歸來判斷

    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        if not p and not q:
            return True
        if not p or not q:
            return False
        if p.val !=q.val:
            return False
        return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)

101. Symmetric Tree(Easy)

給定二叉樹,檢查它是否是自身的鏡像(即,圍繞其中心對稱)。
在這裏插入圖片描述

思路:
1、使用遞歸
2、每次判斷左子樹和右子樹是不是對稱的,再判斷左子樹和右子樹的值是否相同

    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if not root:
            return True
        def check(r1,r2):
            if not r1 and not r2:
                return True
            if not r1 or not r2:
                return False
            a1= check(r1.left,r2.right)
            a2 = check(r1.right,r2.left)
            
            return a1 and a2 and (r1.val==r2.val)
        
        
        return check(root.left,root.right)

102. Binary Tree Level Order Traversal(Medium)

給定二叉樹,返回其節點值的級別順序遍歷。 (即,從左到右,逐級)。
在這裏插入圖片描述

思路:使用兩個數組,其中一個數組存儲當前層次的節點,另一個數組存儲下一個層次的節點

    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if root ==None:
            return []
        res = [root]
        ans = []
        while res:
            temp = []
            ans.append([i.val for i in res])
            for node in res:            
                temp.append(node.left)
                temp.append(node.right)
            res = [i for i in temp if i]
        return ans

103. Binary Tree Zigzag Level Order Traversal(Medium)

給定二叉樹,返回其節點值的Z字形級別遍歷。 (即,從左到右,然後從右到左進行下一級別並在之間交替)。
在這裏插入圖片描述

思路:102題的思想,然後增加一個變量flag=1 每次循環一遍flag*=-1

    def zigzagLevelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        res = [root]
        ans = []
        flag = 1
        while res:
            ans.append([i.val for i in res][::flag])
            temp = []
            
            for node in res:
                temp.append(node.left)
                temp.append(node.right)
            res = [i for i in temp if i]
            flag *=-1
        return ans

104. Maximum Depth of Binary Tree(Easy)

給定二叉樹,找到它的最大深度。
在這裏插入圖片描述

思路:
使用遞歸方法

def maxDepth(self, root):
    """
    :type root: TreeNode
    :rtype: int
    """
    if root is None:
        return 0
    left = self.maxDepth(root.left)
    right = self.maxDepth(root.right)
    return max(left,right)+1

105. Construct Binary Tree from Preorder and Inorder Traversal(Medium)

給定樹的前序和中序,構建樹
在這裏插入圖片描述

思路:

  1. 先序遍歷的從左數第一個爲整棵樹的根節點。
  2. 中序遍歷中根節點是左子樹右子樹的分割點。
    根據這個規則可以使用遞歸來解題,退出遞歸的條件是中序爲空
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            index = inorder.index(preorder.pop(0))
            root = TreeNode(inorder[index])
            root.left = self.buildTree(preorder,inorder[:index])
            root.right = self.buildTree(preorder,inorder[index+1:])
            return root

106. Construct Binary Tree from Inorder and Postorder Traversal(Medium)

給定樹的後序和中序,構建樹

  1. 後序遍歷的從右數第一個爲整棵樹的根節點。
  2. 中序遍歷中根節點是左子樹右子樹的分割點。
    在這裏插入圖片描述
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            index = inorder.index(postorder.pop())
            root = TreeNode(inorder[index])
            root.right = self.buildTree(inorder[index+1:],postorder)
            root.left = self.buildTree(inorder[:index],postorder)
            return root

107. Binary Tree Level Order Traversal II(Easy)

給定二叉樹,返回其節點值的自下而上級別順序遍歷。 (即,從左到右,逐層逐層)。

思路:
和103一樣,只不過最後把數組倒過來就好了

    def levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if root ==None:
            return []
        res = [root]
        ans = []
        while res:
            temp = []
            ans.append([i.val for i in res])
            for node in res:            
                temp.append(node.left)
                temp.append(node.right)
            res = [i for i in temp if i]
        return ans[::-1]

108. Convert Sorted Array to Binary Search Tree(Easy)

給定一個數組,其中元素按升序排序,將其轉換爲高度平衡的BST。

思路:
1、當len(nums)<=2時,賦值返回
2、使用二分法來建立樹

    def sortedArrayToBST(self, nums):
        """
        :type nums: List[int]
        :rtype: TreeNode
        """
        if len(nums)==0:
            return None
        elif len(nums)==1:
            return TreeNode(nums[0])
        elif len(nums)==2:
            root = TreeNode(nums[0])
            root.right = TreeNode(nums[1])
        else:
            middle = int((len(nums)-1)/2)
            root = TreeNode(nums[middle])
            root.left = self.sortedArrayToBST(nums[:middle])
            root.right = self.sortedArrayToBST(nums[middle+1:])
        return root

109. Convert Sorted List to Binary Search Tree(Medium)

給定單個鏈接列表,其中元素按升序排序,將其轉換爲高度平衡的BST。

思路:
1、先將鏈表轉化爲數組
2、然後取數組的中間值,使用遞歸構建樹

def sortedListToBST(self, head):
    """
    :type head: ListNode
    :rtype: TreeNode
    """
    array = []
    while head:
        array.append(head.val)
        head  = head.next
    
    def dfs(l,r):
        if l<=r:
            middle = (l+r)/2
            root = TreeNode(array[middle])
            root.left = dfs(l,middle-1)
            root.right = dfs(middle+1,r)
            return root
    return dfs(0,len(array)-1)

110. Balanced Binary Tree(Easy)

給定二叉樹,確定它是否是高度平衡的。

思路:
1、使用DFS,在傳遞的時候,要加上height
2、如果right、left其中一個是False,就返回False。
3、如果right、left相差大於1,返回False

    def isBalanced(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """   
        if root == None:
            return True
        
        def B(root,height):
            if not root:
                return height-1
            if root.left == root.right ==None:
                return height
            
            lheight = B(root.left,height+1) 
            rheight = B(root.right,height+1)
            if rheight==False or lheight==False:
                return False
            if abs(lheight-rheight)>1:
                return False
            return max(lheight,rheight)
        return True if B(root,1) else False

111. Minimum Depth of Binary Tree(Easy)

給定二叉樹,找到它的最小深度。
在這裏插入圖片描述

思路:
1、使用遞歸
2、左邊和右邊比最小

    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        

        def D(root,minmum):
            if not root:
                return 2**31 -1
            if root.left ==root.right==None:
                return minmum
            lm = D(root.left,minmum+1)
            rm = D(root.right,minmum+1)

            return min(lm,rm)
        if root ==None:
            return 0
        return D(root,1)
        

112. Path Sum(Easy)

給定二叉樹和求和,確定樹是否具有根到葉路徑,使得沿路徑的所有值相加等於給定的總和。

思路:
1、使用遞歸

    def hasPathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: bool
        """
        if root ==None:
            return False
        if (root.left==root.right==None):
            return sum == root.val
        else:
            return self.hasPathSum(root.left,sum-root.val) or self.hasPathSum(root.right,sum-root.val)

113. Path Sum II(Medium)

給定一個二叉樹的總和,發現其中每個路徑的總和等於給定的款項的所有根到葉的路徑。

思路:使用遞歸,難度不大,就是陷阱比較多,注意幾個point

  1. 一定要葉節點爲結尾
  2. 節點的值可能有負數,不能碰到和爲0時,退出
    def pathSum(self, root, sum):
    	res = []
        def dfs(sum,root,path):
            if not root:
                return
            elif sum - root.val ==0:
                if not root.left and not root.right:
                    res.append(path+[root.val])
                    return
            dfs(sum-root.val,root.left,path+[root.val])
            dfs(sum-root.val,root.right,path+[root.val])
        dfs(sum,root,[])
        return res

114. Flatten Binary Tree to Linked List(Medium)

給定二叉樹,將其平鋪到鏈接列表中。
在這裏插入圖片描述

思路:
使用遞歸,將所有元素放在右邊。

    pre = None
    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: None Do not return anything, modify root in-place instead.
        """
        #將其鋪平,無需考慮結果如何

        if root:
            self.flatten(root.right)
            self.flatten(root.left)
            
            root.right = self.pre
            root.left = None
            self.pre = root

115. Distinct Subsequences(Hard)

在S中,能找到幾個T
給定字符串S和字符串T,計算S的不同子序列的數量,其等於T.
Input: S = “rabbbit”, T = “rabbit”
Output: 3
在這裏插入圖片描述

思路:使用動態規劃DP,res[i][j] = res[i][j-1] + (res[i-1][j-1] if s[j-1]==t[i-1] else 0)

    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        res = [[0 for _ in range(len(s)+1)] for _ in range(len(t)+1)]
        res[0][0]=1
        for j in range(1,len(s)+1):
            res[0][j] = 1
        
        for i in range(1,len(t)+1):
            for j in range(1,len(s)+1):
                res[i][j] = res[i][j-1] + (res[i-1][j-1] if s[j-1]==t[i-1] else 0)
        print(res)
        return res[len(t)][len(s)]

116. Populating Next Right Pointers in Each Node(Medium)

您將獲得一個完美的二叉樹,其中所有葉子都在同一級別,每個父級都有兩個孩子。填充每個下一個指針以指向其下一個右側節點。如果沒有下一個右節點,則下一個指針應設置爲NULL。 最初,所有下一個指針都設置爲NULL
在這裏插入圖片描述

思路:

    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        if not root:
            return root
        pre = root
        cur = None
        while(pre.left):
            cur = pre
            while(cur):
                cur.left.next = cur.right
                if cur.next:
                    cur.right.next = cur.next.left
                cur = cur.next
            pre = pre.left
        return root

117.Populating Next Right Pointers in Each Node II(Medium)

在這裏插入圖片描述

思路:
和116一樣,只不過要多加一個判斷,下一行的最左邊的元素

    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        pre = root
        cur = []
        while(pre):
            #加一個判斷,判斷最左邊的元素
            cur = pre
            now = None
            while not now and cur:
                if cur.left !=None:
                    now = cur.left
                elif cur.right !=None:
                    now = cur.right
                else:
                    cur = cur.next
            pre = now
            while cur:
                if cur.left and cur.left !=now:
                    now.next = cur.left
                    now = cur.left
                if cur.right and cur.right !=now:
                    now.next = cur.right
                    now = cur.right
                cur = cur.next
        return root

118. Pascal’s Triangle(Easy)

給定非負整數numRows,生成Pascal三角形的第一個numRows。
Input: 5
Output:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]

    def generate(self, numRows):
        """
        :type numRows: int
        :rtype: List[List[int]]
        """
        total = []
        if numRows == 0:
            return total
        total =[[1]]
        if numRows==1:
            return total
        total = [[1],[1,1]]
        if numRows==2:
            return total
        for i in range(3,numRows+1):
            total.append([])
            for j in range(i):
                if j ==0 or j == i-1:
                    total[-1].append(1)
                else:
                    total[-1].append(total[i-2][j-1]+total[i-2][j])
        return total

119. Pascal’s Triangle II(Easy)

給定非負索引k,其中k≤33,返回Pascal三角形的第k個索引行。

思路:
1、使用遞歸,直到遞歸到那一層

    def getRow(self, rowIndex):
        """
        :type rowIndex: int
        :rtype: List[int]
        """
        if rowIndex == 0:
            return [1]
        if rowIndex == 1:
            return [1,1]
        prerow = self.getRow(rowIndex-1)
        return [1]+[prerow[i]+prerow[i+1] for i in range(len(prerow)-1)]+[1]

120. Triangle(Medium)

給定一個三角形,找到從上到下的最小路徑總和。您可以移動到下面一行中相鄰數字的每一步。

如果從上到下,需要用到O(n2)的空間
從下到上,我們只需要覆蓋上一層就可以了,因爲上一層沒有用了

def minimumTotal(self, triangle):
    """
    :type triangle: List[List[int]]
    :rtype: int
    """
    min_path = triangle[-1]
    for layer in range(len(triangle)-2,-1,-1):
        for i in range(len(triangle[layer])):
            min_path[i] = min(min_path[i+1],min_path[i])+ triangle[layer][i]
    return min_path[0]

121. Best Time to Buy and Sell Stock(Easy)

假設您有一個數組,其中第i個元素是第i天給定股票的價格。 如果您只被允許完成最多一筆交易(即買入並賣出一股股票),請設計一個算法以找到最大利潤。

思路:
找出最大值(-1)和最小值float(‘inf’)

    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        min_p = float('inf')
        sum_o = 0
        for i in range(len(prices)):
            min_p = min(min_p,prices[i])
            p = prices[i]-min_p
            sum_o = max(p,sum_o)
        return sum_o

122. Best Time to Buy and Sell Stock II(Easy)

設計算法以找到最大利潤。您可以根據需要完成儘可能多的交易(即,多次買入並賣出一股股票)。
您不得同時進行多筆交易(即,您必須在再次購買之前賣出股票)。

思路:
1、可以找到谷峯和低窪,然後相減
2、完全可以不用理谷峯和低窪,如果值遞增的只要前後相減就可以了,避免了找谷峯和低窪

    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        total = 0;
        for i in range(len(prices)-1):
            if prices[i+1]>prices[i]:
                total += prices[i+1]-prices[i]
        return total

123. Best Time to Buy and Sell Stock III(Hard)

假設您有一個數組,其中第i個元素是第i天給定股票的價格。 設計算法以找到最大利潤。您最多可以完成兩筆交易。

思路:
使用DP
計算某一天極其之前所有時間內的最大利益
計算某一天極其之後所有時間內價格的最利益

    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        #使用DP好了,另一個實在看不懂
        n = len(prices)
        if n ==0:
            return 0
        p1 = [0]*n
        p2 = [0]*n
        
        ##計算某一天極其之前所有時間內的最大利益
        min_price = prices[0]
        for i in range(1,n):
            min_price = min(prices[i],min_price)
            p1[i] = max(p1[i-1],prices[i]-min_price)
        
         ##計算某一天極其之後所有時間內價格的最利益
        max_price = prices[-1]
        for i in range(n-2,-1,-1):
            max_price = max(prices[i],max_price)
            p2[i] = max(p2[i+1],max_price-prices[i])
        ans = 0
        ## 計算最大收益
        for i in range(n):
            ans = max(ans,p1[i]+p2[i])
        return ans

124. Binary Tree Maximum Path Sum(Hard)

給定非空二叉樹,找到最大路徑總和。
對於此問題,路徑定義爲沿着父子連接從樹中的某個起始節點到任何節點的任何節點序列。該路徑必須至少包含一個節點,並且不需要通過根節點。在這裏插入圖片描述

思路:
1、使用遞歸,需要設置一個全局變量,用來隨時更新最大值(這個最大值是根節點加上左右節點)
2、返回當前節點加上左右其中一個最大值。(這個最大值是根節點,加上左右其中一個)
3、注意:全局變量剛開始不能設爲0,因爲可能出現所有節點都爲負的情況,然後題目要求至少要輸出一個節點

    def maxPathSum(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        def dfs(root):
            if not root:
                return 0
            left = dfs(root.left)
            right = dfs(root.right)
            self.max = max(self.max,root.val+left+right)
            return max(0,root.val+max(left,right))
        ##self.max 不能設爲0,因爲可能只有root.val = -3的情況
        self.max = None
        dfs(root)
        return self.max

125. Valid Palindrome(Easy)

給定一個字符串,確定它是否是迴文,只考慮字母數字字符並忽略大小寫。 注意:出於此問題的目的,我們將空字符串定義爲有效的迴文

思路:
1、要使用字符串的isalnum()判斷是否是字母or數字
2、要將所有字母轉化爲小寫

    def isPalindrome(self, s):
        """
        :type s: str
        :rtype: bool
        """
        s = [i.lower() for i in s if i.isalnum()]
        return s ==s[::-1]

126. Word Ladder II(Hard)

給定兩個單詞(beginWord和endWord)和一個字典的單詞列表,找到從beginWord到endWord的所有最短變換序列
Input:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
Output:
[
[“hit”,“hot”,“dot”,“dog”,“cog”],
[“hit”,“hot”,“lot”,“log”,“cog”]
]

思路:
難題,據說是通過率最小的題

使用dfs一個個找和某個單詞相關的(即相差一個字符的)然後存入字典,每次更新字典
1、使用new_layer來記錄下一層要用的
2、將所有隻差一個字母的存到new_layer中,將new_layer賦值給layer

    def findLadders(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: List[List[str]]
        """
        wordList  = set(wordList)
        res = []
        layer = {}
        layer[beginWord] = [[beginWord]]
        #如果endWord不在List中,則直接退出
        if endWord not in wordList:
            return res
        while(layer):
            #用一個新的層來記錄下一步的layer
            new_layer = collections.defaultdict(list)
            for w in layer:
                if w ==endWord:
                    res.extend(i for i in layer[w])
                else:
                    #將所有和w只差一個字母的存起來
                    for i in range(len(w)):
                        for c in 'abcdefghijklmnopqrstuvwxyz':
                            w1 = w[:i]+c+w[i+1:]
                            #如果在list找到了,就添加到new_layer中
                            if w1 in wordList:
                                new_layer[w1] += [j+[w1] for j in layer[w]]
            #將所有已經用過的詞刪除(找出最短的)
            wordList -=set(new_layer.keys())
            layer = new_layer
            print(layer)
        
        return res

127. Word Ladder(Medium)

給定兩個單詞(beginWord和endWord)和一個字典的單詞列表,找到從beginWord到endWord的最短變換序列的長度

思路:只會用和126一樣的方式,不過運行速度有點慢

    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        wordList  = set(wordList)
        res = []
        layer = {}
        layer[beginWord] = [[beginWord]]
        if endWord not in wordList:
            return 0
        while(layer):
            new_layer = collections.defaultdict(list)
            for w in layer:
                if w ==endWord:
                    res.extend(i for i in layer[w])
                    return len(res[0])
                else:
                    for i in range(len(w)):
                        for c in 'abcdefghijklmnopqrstuvwxyz':
                            w1 = w[:i]+c+w[i+1:]
                            if w1 in wordList:
                                new_layer[w1] += [j+[w1] for j in layer[w]]
            wordList -=set(new_layer.keys())
            layer = new_layer
        
        return 0

128. Longest Consecutive Sequence(Hard)

給定未排序的整數數組,找到最長連續元素序列的長度。
在這裏插入圖片描述

思路:
在for循環中加入一些判斷達到O(n)的複雜度

首先判斷元素是不是最小的,然後再開始+1操作,計算長度

    def longestConsecutive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        longest = 0
        
        nums = set(nums)
        for i in nums:
            if i-1 not in nums:
                current_num = i
                current_long = 1
                while current_num+1 in nums:
                    current_num +=1
                    current_long +=1
                
                longest = max(longest,current_long)
        return longest

129. Sum Root to Leaf Numbers(Medium)

Input: [1,2,3]
1
/
2 3
Output: 25
Explanation:
The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.
Therefore, sum = 12 + 13 = 25.
找到所有根到葉數的總和。

使用遞歸

    def sumNumbers(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        def dfs(root,sum_n):
            if root:
                dfs(root.left,sum_n*10+root.val)
                dfs(root.right,sum_n*10+root.val)
                if not root.left and not root.right:
                    self.res += sum_n*10+root.val
        self.res = 0
        dfs(root,0)
        return self.res

130. Surrounded Regions(Medium)

給定包含“X”和“O”(字母O)的2D板,捕獲由“X”包圍的所有區域。 通過將所有’O’翻轉到該周圍區域中的’X’來捕獲區域。
在這裏插入圖片描述

思路:
1、先看邊界,邊界有O加入stack中
2、然後取出stack中的元素,改爲S,如果其上下左右有O,則加入stack,知道stack中沒有點爲止
3、最後將2D板中不是S的元素全部改爲X

def solve(self, board):
    """
    :type board: List[List[str]]
    :rtype: None Do not return anything, modify board in-place instead.
    """
    m = len(board)
    if m==0:
        return
    n = len(board[0])
    stack = []
    for i in range(n):
        if board[0][i]=='O':
            stack.append([0,i])
        if board[m-1][i]=='O':
            stack.append([m-1,i])
    for i in range(1,m-1):
        if board[i][0] =='O':
            stack.append([i,0])
        if board[i][n-1]=='O':
            stack.append([i,n-1])
    while stack:
        print(stack)
        pos = stack.pop(0)
        board[pos[0]][pos[1]] = 'S'
        if pos[0]>0 and board[pos[0]-1][pos[1]] =='O':
            stack.append([pos[0]-1,pos[1]])
        if pos[0]<m-1 and board[pos[0]+1][pos[1]] =='O':
            stack.append([pos[0]+1,pos[1]])
        if pos[1]>0 and board[pos[0]][pos[1]-1] =='O':
            stack.append([pos[0],pos[1]-1])
        if pos[1]<n-1 and board[pos[0]][pos[1]+1] =='O':
            stack.append([pos[0],pos[1]+1])
            
    for i in range(m):
        for j in range(n):
            if board[i][j]=='S':
                board[i][j]='O'
            else:
                board[i][j]='X'

131. Palindrome Partitioning(Medium)

給定字符串s,分區s使得分區的每個子字符串都是迴文。 返回s的所有可能的迴文分區。
在這裏插入圖片描述

思路:
1、使用遞歸
2、每次遞歸前先判斷前面那個字符串是不是迴文

    def dfs(s,path):
        if s=='':
            self.res.append(path)
        for i in range(1,len(s)+1):
            if s[:i]==s[:i][::-1]:
                dfs(s[i:],path + [s[:i]])
    self.res = []
    dfs(s,[])
    return self.res

132. Palindrome Partitioning II(Hard)

給定字符串s,分區s使得分區的每個子字符串都是迴文。 返回s的迴文分區所需的最小割數。

思路:
如果使用遞歸,會超時,考慮使用DP算法
用數組dp[i]記錄從第0位到i位最小割數
使用i-1對第i個位置進行初始化,如果子串s[j:i]是迴文串,則dp[i] = min(dp[i],dp[j]+1)

    def minCut(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        dp = range(-1,n)
        for i in range(1, n + 1):
            for j in range(i):
                tmp = s[j:i]
                if tmp == tmp[::-1]:
                    dp[i] = min(dp[i], dp[j] + 1)
        return dp[n]

133. Clone Graph(Medium)

給定連接的無向圖中的節點的引用,返回圖的深拷貝(克隆)。圖中的每個節點都包含其鄰居的val(int)和列表(List [Node])。
在這裏插入圖片描述

思路:
1、使用DFS遍歷整個網絡
2、如果存在該節點,則直接返回該節點的指針
3、不存在則創建Node,然後遍歷其neighbors

    def cloneGraph(self, node):
        """
        :type node: Node
        :rtype: Node
        """
        if node == None:
            return None
        d = {}
        
        def dfs(node):
            if node in d:
                return d[node]
            ans = Node(node.val,[])
            d[node] = ans
            for i in node.neighbors:
                ans.neighbors.append(dfs(i))
            return ans
        return dfs(node)

134 .Gas Station(Medium)

在一個圈子路線裏面有N個汽油站,i站的汽油有gas[i]汽油。現在有一輛無限容量的車,它從i站開到(i+1)需要耗費cost[i]汽油。如果這輛車可以走完這個圈,那麼返回這個車的起點,否者返回-1.

思路:
1、如果gas的總和大於或等於cost的總和,必然存在一種路線使得走完整個圈子。
2、假設當前剩餘的油量爲diff,若達到站點i的的剩餘油量小於0,則將設置起始站點設爲i;另外設置所有站點的剩餘油量爲total,當total小於0,則不能環繞,否則可以
在這裏插入圖片描述

    def canCompleteCircuit(self, gas, cost):
        """
        :type gas: List[int]
        :type cost: List[int]
        :rtype: int
        """
        if sum(gas)<sum(cost):
            return -1
        index = 0
        diff = 0
        for i in range(len(gas)):
            if gas[i]+diff <cost[i]:
                index = i+1
                diff = 0
            else:
                diff += gas[i]-cost[i]
        return index

135. Candy(Hard)

幾個小孩站一排,每個小孩有個等級值,現在給小孩發糖,發的時候要遵守2個規則:(1)每個小孩至少一顆糖(2)兩個相鄰的小孩中,等級大的小孩一定比等級小的小孩糖多,求發糖的數目的最小值。對於等級序列[1, 2, 2]來說,發糖數目最小值爲4,發糖序列爲[1, 2, 1]。

思路:
1、初始化所有小孩糖數目爲1
2、從前往後掃描,如果第i個小孩等級比第i-1個高,那麼i的糖數目等於i-1的糖數目+1
3、從後往前掃描,如果第i個的小孩的等級比i+1個小孩高,但是糖的數目卻小或者相等,那麼i的糖數目等於i+1的糖數目+1
(第一遍,保證了每一點比他左邊candy更多(如果得分更高的話)。第二遍,保證每一點比他右邊candy更多(如果得分更高的話),同時也會保證比他左邊的candy更多,因爲當前位置的candy只增不減。)

    def candy(self, ratings):
        """
        :type ratings: List[int]
        :rtype: int
        """
        candy = [1 for i in range(len(ratings))]
        for i in range(1,len(ratings)):
            if ratings[i]>ratings[i-1]:
                candy[i] =candy[i-1]+1
        for i in range(len(ratings)-2,-1,-1):
            if ratings[i]>ratings[i+1]and candy[i]<=candy[i+1]:
                candy[i] =candy[i+1]+1
        return sum(candy)

137. Single Number II(Medium)

給定一個非空的整數數組,每個元素出現三次,除了一個,只出現一次。找一個單一的。

思路:python使用異或操作比較難,因爲不存在最大值
使用字典(效率比較好)

        dict ={}
        for i in nums:
            if i not in dict:
                dict[i] =1
            else:
                dict[i]+=1
        for i in dict:
            if dict[i] ==1:
                return i

138. Copy List with Random Pointer(Medium)

複製一個複雜鏈表,這個複雜鏈表是指出了值和next指針外,還有一個random指針可能指向任何位置的鏈表節點或空。
在這裏插入圖片描述

思路:
1、使用字典來創建類型,記得要添加一個dict[None] = None 類型
2、然後next遍歷,賦值

    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
        dict = collections.defaultdict(lambda:Node(0,0,0))
        dict[None] = None
        n = head
        while n:
            dict[n].val = n.val
            dict[n].next = dict[n.next]
            dict[n].random = dict[n.random]
            n = n.next
        return dict[head]

139. Word Break(Medium)

給定一個目標字符串和一組字符串,判斷目標字符串能否拆分成數個字符串,這些字符串都在給定的那組字符串中。
在這裏插入圖片描述

思路:
1、使用動態規劃
2、dp[i] 代表前i個是否滿足條件
3、第二層循環是將問題逐步化小

    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        n,dp = len(s),[True] + [False]*len(s)
        
        for i in range(n):
            for j in range(i+1):
                if dp[j] and s[j:i+1] in wordDict:
                    dp[i+1] = True
                    break
        return dp[n]

140. Word Break II(Hard)

給了一個字典,問給定的字符串s能有多少種被字典構造出來的方式,返回每一種構造方式。
在這裏插入圖片描述

思路:
1、使用DFS + DP
2、使用一個字典,記錄已經切分過的數組,不必要再次重切
3、接下來使用wordDict來循環,判斷是不是

    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: List[str]
        """
        #dfs + dp
        # 使用一個數組記住前面已經切分的
        res = []
        momery = {}
        
        def dfs(s):
            if s in momery:
                return momery[s]
            if s =='':
                return ['']
            res = []
            for word in wordDict:
                if s[:len(word)] == word:
                    for r in dfs(s[len(word):]):
                        res.append(word +('' if not r else ' '+r))
            momery[s] = res
            return res
        return dfs(s)

142. Linked List Cycle II(Medium)

給定鏈表,返回循環開始的節點。如果沒有循環,則返回null。
在這裏插入圖片描述

思路:
在這裏插入圖片描述
第一次相遇時slow走過的距離:a+b,fast走過的距離:a+b+c+b。
因爲fast的速度是slow的兩倍,所以fast走的距離是slow的兩倍,有 2(a+b) = a+b+c+b,
可以得到a=c(這個結論很重要!)。

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

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        first = head
        second = head
        while first and second:
            first = first.next
            if second.next:
                second =second.next.next
            else:
                return None
            if first ==second:
                first = head
                while first != second:
                    first = first.next
                    second = second.next
                return first
        return None

143. Reorder List(Medium)

在這裏插入圖片描述

思路:
1、先找出中間的node
2、將中間後面的給反轉
3、然後兩個鏈表相連

    def reorderList(self, head):
        """
        :type head: ListNode
        :rtype: None Do not return anything, modify head in-place instead.
        """
        if head ==None:
            return head
        
        first,second = head,head
        
        ##找出中間的
        while second.next and second.next.next:
            first = first.next
            second = second.next.next
        
        cur = first.next
        node = first.next = None
        
        ## 反轉後面的
        while cur:
            next = cur.next
            cur.next = node
            node = cur
            cur = next
            
        ##交替相連
        cur1 = head
        cur2 = node
        while cur2:
            next = cur1.next
            cur1.next = cur2
            next2 = cur2.next
            cur2.next = next
            cur2 = next2
            cur1 = next

144 and 145. Binary Tree Postorder Traversal(Hard)

給定二叉樹,返回其節點值的前、後序遍歷。(使用迭代的方法)
在這裏插入圖片描述

思路:
前序遍歷:1.根節點 2.左子樹 3.右子樹
中序遍歷:1.左子樹 2.根節點 3.右子樹
後序遍歷:1.左子樹 2.右子樹 3.根節點
有個前序、中序、後序的迭代操作(只是加入的順序不一樣,後序就差不多是前序的反向操作)
1、定義兩個list,一個存儲結果,一個存儲訪問過的結點
2、後序,在最前面插入結點(中間、右邊、左邊)(相當於前序反過來操作,因爲在最前面插入)

    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = []
        stack = []
        p = root
        while(p!=None or stack!=[]):
            if p!=None:
                result.insert(0,p.val)
                stack.append(p)
                p = p.right
            else:
                p = stack.pop()
                p = p.left
        return result
    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        cur = root
        result = []
        stack = []
        while cur !=None or stack!=[]:
            if cur!=None:
                result.append(cur.val)
                stack.append(cur)
                cur = cur.left
            else:
                cur = stack.pop()
                cur = cur.right
        return result

146. LRU Cache(Hard)

設計並實現最近最少使用(LRU)緩存的數據結構。它應該支持以下操作:get和put。
在這裏插入圖片描述

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

思路:
由於要求時間複雜度爲O(1),定義一個雙向鏈表(自帶一個頭結點和尾結點)
1、init() 包括capacity、字典、頭尾結點
2、get()判斷是否在字典、然後移除該結點,再加入該結點(保證在末尾)
3、set()判斷是否包含關鍵詞,如果有,刪除並更改。如果容量不夠,刪掉最後一個。字典也要記得刪
4、定義node結點和remove函數和add函數

class Node(object):
    def __init__(self,key,value):
        self.key = key
        self.value = value
        self.next = None
        self.pre = None

class LRUCache(object):

    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.capacity = capacity
        self.dict = {}
        self.head = Node(0,0)
        self.tail = Node(0,0)
        self.head.next = self.tail
        self.tail.pre = self.head

    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        if key in self.dict:
            self.remove(self.dict[key])
            self.add(self.dict[key])
            return self.dict[key].value
        return -1
        

    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: None
        """
        if key in self.dict:
            self.remove(self.dict[key])
        n = Node(key,value)
        self.dict[key] = n
        self.add(n)
        if len(self.dict)>self.capacity:
            r = self.head.next
            self.remove(r)
            del self.dict[r.key]
    def remove(self,node):
        next = node.next
        next.pre = node.pre
        node.pre.next = next
    
    def add(self,node):
        pre = self.tail.pre
        pre.next = node
        node.next = self.tail
        node.pre = pre
        self.tail.pre = node

147. Insertion Sort List(Medium)

使用插入排序對鏈接列表進行排序。

思路:
定義一個輔助鏈表頭
然後循環找到合適的位置插入

    def insertionSortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head == None:
            return None
        
        pre=temp= ListNode(0)
        cur = head
        next = None
        while cur:
            while (pre.next!=None and cur.val>pre.next.val):
                pre = pre.next
            next = cur.next
            cur.next = pre.next
            pre.next = cur
            cur = next
            pre = temp
        return pre.next

148. Sort List(Medium)

使用常量空間複雜度在O(n log n)時間內對鏈表進行排序。

思路:
滿足這樣要求的排序算法,我們首先想到快排,合併排序和堆排序。
快排的最壞的時間複雜度是O(n^2),平均複雜度爲O(nlgn)
堆排序實現上過於繁瑣,我們不做考慮

使用歸併
1、首先要將鏈表一步一步縮小(使用遞歸)定義三個變量,pre、slow、fast
2、其次使用歸併操作

    def sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head==None or head.next==None:
            return head
        
        pre = slow = fast = head
        
        while fast!=None and fast.next!=None:
            pre = slow
            slow = slow.next
            fast = fast.next.next
        pre.next = None
        i  = self.sortList(head)
        j  = self.sortList(slow)
        return self.merge(i,j)
    
    def merge(self,i,j):
        cur = tempNode = ListNode(0)
        while i!=None or j!=None:
            if i == None:
                cur.next = j
                j = j.next
            elif j ==None:
                cur.next = i
                i = i.next
            elif i.val>j.val:
                cur.next = j
                j = j.next
            else:
                cur.next = i
                i = i.next
            cur = cur.next
        return tempNode.next

149. Max Points on a Line(Hard)

給定2D平面上的n個點,找到位於同一直線上的最大點數。
在這裏插入圖片描述

思路:
首先他們滿足在同一直線上,即a = (x1-x0)/(y1 - y0) = (x2-x1)/(y2-y1)
1、使用雙層循環進行判斷,定義一個全局變量m來存儲當前最大
2、首先判斷兩個點是不是重疊,是的話,same+1
3、定義一個字典,用來存儲不同a對應的數量,找出最大

from fractions import Fraction
class Solution(object):
    def maxPoints(self, points):
        """
        :type points: List[List[int]]
        :rtype: int
        """
        m = 0
        for i in range(len(points)):
            if m>=len(points)-i:
                break
            dict = {'i':1}
            same = 0
            for j in range(i+1,len(points)):
                if points[i][0] ==points[j][0] and points[j][1]==points[i][1]:
                    same +=1
                    continue
                if points[i][0] == points[j][0]:
                    slop = i
                else:
                    slop = Fraction((points[j][1]-points[i][1]),(points[j][0] - points[i][0]))
                if slop not in dict:
                    dict[slop] = 1
                dict[slop] +=1
            m = max(m,max(dict.values())+same)
        return m

150. Evaluate Reverse Polish Notation(Medium)

在反向波蘭表示法中計算算術表達式的值。 有效的運算符是+, - ,*,/。每個操作數可以是整數或另一個表達式。
在這裏插入圖片描述

思路:
使用棧的方式做
使用op的操作來處理加減乘除

    def evalRPN(self, tokens):
        """
        :type tokens: List[str]
        :rtype: int
        """
        op = {
            '+':lambda x:lambda y: int(float(y)+float(x)),
            '-':lambda x:lambda y: int(float(y)-float(x)),
            '/':lambda x:lambda y: int(float(y)/float(x)),
            '*':lambda x:lambda y: int(float(y)*float(x))
        }
        stack = []
        for i in tokens:
            if i in ['+','-','*','/']:
                stack.append(op[i](stack.pop())(stack.pop()))
            else:
                stack.append(i)
        return stack[0]

151. Reverse Words in a String(Medium)

給定輸入字符串,逐字反轉字符串。

思路:
1、使用python 的split函數

    def reverseWords(self, s):
        """
        :type s: str
        :rtype: str
        """
        l = [i for i in s.split() if i!=''][::-1]
        return ' '.join(l)

152. Maximum Product Subarray(Medium)

給定整數數組nums,找到具有最大乘積的數組(包含至少一個數字)內的連續子數組
在這裏插入圖片描述

思路:
1、兩邊掃各掃一次

    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        
        max1 = -2**31
        #正向
        product = 1
        for i in range(len(nums)):
                product *= nums[i]
                max1 = max(max1,product)
                if product==0:
                    product = 1
                    
        #反向            
        product = 1
        for j in range(len(nums)-1,-1,-1):
            product *= nums[j]
            
            max1 = max(max1,product)
            if product == 0:
                product = 1

        return max1

153. Find Minimum in Rotated Sorted Array(Medium)

假設按升序排序的數組在事先未知的某個樞軸處旋轉。找出最小值

思路:
使用二分法查找

    def findMin(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        start = 0
        end = len(nums)-1
        while end-start>1:
            middle = int((start+end)/2)
            if nums[middle]>nums[end]:
                start = middle
            else:
                end = middle
        return nums[start] if nums[start]<nums[end] else nums[end]

162. Find Peak Element(Medium)

峯值元素是大於其鄰居的元素。在這裏插入圖片描述

思路:
首先要麼單調遞增、要麼單調遞減、要麼上升之後減。
所以當出現開始下降的時候,該index就是了,不需要考慮之前的

    def findPeakElement(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        for i in range(len(nums)-1):
            if nums[i]>nums[i+1]:
                return i
        return len(nums)-1

164. Maximum Gap(Hard)

給定未排序的數組,找到其排序形式中的連續元素之間的最大差異。 如果數組包含少於2個元素,則返回0。(嘗試在線性時間/空間中解決它。)
在這裏插入圖片描述

思路:
解題思路
由於需要線性,並且假定是整數,使用桶排序
1、如果數組中數字小於2或者最大最小值相等,return 0
2、向上取整(math.ceil()),得到桶的大小(最大值-最小值)/(數組長度-1)
(差值不小於(最大值-最小值)/(數組長度-1))
3、得到多少個桶(最大值-最小值)/(桶的大小+1)
4、循環將元素放入桶中(i = bucket[(n-a)//size]),只需記錄最大最小值
5、不同桶之間的最大最小值,就是候選值

    def maximumGap(self, num):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(num) < 2 or min(num) == max(num):
            return 0
        a, b = min(num), max(num)
        size = (b-a)//(len(num)-1) or 1
        bucket = [[None, None] for _ in range((b-a)//size+1)]
        for n in num:
            b = bucket[(n-a)//size]
            b[0] = n if b[0] is None else min(b[0], n)
            b[1] = n if b[1] is None else max(b[1], n)
        bucket = [b for b in bucket if b[0] is not None]
        return max(bucket[i][0]-bucket[i-1][1] for i in range(1, len(bucket)))

165. Compare Version Numbers(Medium)

比較兩個版本號version1和version2。 如果version1> version2返回1;如果version1 <version2返回-1;否則返回0。
在這裏插入圖片描述

思路:
1、使用split將數字分開
2、for循環最大的那個,小的用0補
3、比較兩個數字的大小

    def compareVersion(self, version1, version2):
        """
        :type version1: str
        :type version2: str
        :rtype: int
        """
        version1 = version1.split('.')
        version2 = version2.split('.')
        for i in range(max(len(version1),len(version2))):
            ##加int是因爲可能會出現輸入是01和1的情況
            v1 = int(version1[i]) if i<len(version1) else 0
            v2 = int(version2[i]) if i<len(version2) else 0
            if v1<v2:
                return -1
            if v1>v2:
                return 1
        return 0

166. Fraction to Recurring Decimal(Medium)

給定表示分數的分子和分母的兩個整數,以字符串格式返回分數。 如果小數部分重複,則將重複部分括在括號中。
在這裏插入圖片描述

思路:
1、判斷該數是正數還是負數
2、使用divmod(,)函數,得到整數和餘數
3、使用一個stack數組來存儲餘數,如果已經有該餘數,則跳出循環
4、找到該餘數的index,然後在前面兩個插入‘(’
5、將0的情況去掉

    def fractionToDecimal(self, numerator, denominator):
        """
        :type numerator: int
        :type denominator: int
        :rtype: str
        """
        n, remainder = divmod(abs(numerator), abs(denominator))
        sign = '-' if numerator*denominator < 0 else ''
        result = [sign+str(n), '.']
        stack = []
        while remainder not in stack:
            stack.append(remainder)
            n, remainder = divmod(remainder*10, abs(denominator))
            result.append(str(n))
        ##可能是多位數重複
        idx = stack.index(remainder)
        result.insert(idx+2, '(')
        result.append(')')
        return ''.join(result).replace('(0)', '').rstrip('.')

173. Binary Search Tree Iterator(Medium)

在二叉搜索樹(BST)上實現迭代器。您的迭代器將使用BST的根節點進行初始化。 調用next()將返回BST中的下一個最小數字。
在這裏插入圖片描述

思路:
1、要加一個函數讀取當前最小
2、使用stack進行存儲
3、先把左邊的加入,然後左邊沒有了再加入右邊

class BSTIterator(object):

    def __init__(self, root):
        """
        :type root: TreeNode
        """
        self.stack = []
        self.addmin(root)
        

    def next(self):
        """
        @return the next smallest number
        :rtype: int
        """
        tempNode = self.stack.pop()
        self.addmin(tempNode.right)
        return tempNode.val

    def hasNext(self):
        """
        @return whether we have a next smallest number
        :rtype: bool
        """
        return self.stack
    
    def addmin(self,node):
        while node is not None:
            self.stack.append(node)
            node = node.left

174. Dungeon Game(Hard)

皇后右下角,國王從左上角開始尋找皇后,求國王最少需要多少血?
在這裏插入圖片描述

思路:
1、使用dp操作
2、當走完最後一個房間,至少要剩下1格血,最後狀態也可以當作最初狀態,從最後一個房間往前走,每個房間的血量由下面或者右邊一個較小的一個決定:
dp[i][j] = min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j]
還要考慮每個位置最少最低爲一格血

    def calculateMinimumHP(self, dungeon):
        """
        :type dungeon: List[List[int]]
        :rtype: int
        """
        m = len(dungeon)
        n = len(dungeon[0])
        dp = [[2**31-1 for i in range(n+1)] for j in range(m+1)]
        
        dp[m-1][n] = 1
        
        for i in range(m-1,-1,-1):
            for j in range(n-1,-1,-1):
                dp[i][j] = max(min(dp[i+1][j],dp[i][j+1]) - dungeon[i][j],1)
        
        return dp[0][0]

178. Rank Scores(Medium)

編寫SQL查詢以對分數進行排名。如果兩個分數之間存在平局,則兩者應具有相同的排名。請注意,在平局之後,下一個排名數應該是下一個連續的整數值。

SELECT
  Score,
  (SELECT count(distinct Score) FROM Scores WHERE Score >= s.Score) Rank
FROM Scores s
ORDER BY Score desc

179. Largest Number(Medium)

Given a list of non negative integers, arrange them such that they form the largest number.
在這裏插入圖片描述

思路:
1、自己定義一個比較函數(因爲需要返回倒序,當a大於b,返回負數),然後用sorted()函數
2、把後面的0給去除掉,lstrip(‘0’) 同時要注意數組元素都爲0的情況

    def largestNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: str
        """
        def compare(a,b):
            return int(b+a) - int(a+b)
        
        nums = sorted([str(i) for i in nums],cmp = compare)
        
        return ''.join(nums).lstrip('0') or '0'

180. Consecutive Numbers(Medium)

編寫SQL查詢以查找連續出現至少三次的所有數字。

思路:
將表使用3次,然後用ID匹配是不是附近的,最後選取DISTINCT

SELECT DISTINCT l1.Num as ConsecutiveNums from Logs as l1,Logs as l2,Logs as l3
where l1.Id = l2.Id-1 and l2.Id = l3.Id -1 and l1.Num = l2.Num and l2.Num = l3.Num

184. Department Highest Salary(Medium)

Employee表包含所有員工。每個員工都有一個Id,一個薪水,還有一個部門ID列。
Department表包含公司的所有部門。
找出每個部門工資最高的員工(一樣高需要一起輸出)

# Write your MySQL query statement below
Select Department.Name as Department, Employee.Name as Employee, Employee.Salary
From Employee,Department
where
Employee.DepartmentId = Department.Id and
Employee.Salary = (Select max(Salary) from Employee where Department.Id = Employee.DepartmentId)

185. Department Top Three Salaries(Hard)

編寫SQL查詢以查找在每個部門中獲得前三名薪水的員工。
在這裏插入圖片描述

思路:
1、使用count
2、使用distinct

Select dep.Name as Department, emp.Name as Employee, emp.Salary from Department dep, 
Employee emp where emp.DepartmentId=dep.Id and 
(Select count(distinct Salary) From Employee where DepartmentId=dep.Id and Salary>emp.Salary)<3

187. Repeated DNA Sequences(Medium)

所有DNA由一系列縮寫爲A,C,G和T的核苷酸組成,例如:“ACGAATTCCG”。在研究DNA時,有時識別DNA中的重複序列是有用的。
編寫一個函數來查找DNA分子中不止一次出現的所有10個字母長的序列(子串)。

思路:
1、這裏應該使用KMP算法
2、本題未使用

    def findRepeatedDnaSequences(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        keys = {}
        for i in range(len(s)-9):
            if s[i:i+10] not in keys:
                keys[s[i:i+10]] =1
            else:
                keys[s[i:i+10]] +=1
        return [key for key,value in keys.items() if value>1]

188. Best Time to Buy and Sell Stock IV(Hard)

假設您有一個數組,其中第i個元素是第i天給定股票的價格。
設計算法以找到最大利潤。您最多可以完成k筆交易。
您不得同時進行多筆交易(即,您必須在再次購買之前賣出股票)。
在這裏插入圖片描述

思路:
DP解決
使用兩個list,一個global,一個local
1、一個是當前到達第i天可以最多進行j次交易,最好的利潤是多少(global[i][j])
2、另一個是當前到達第i天,最多可進行j次交易,並且最後一次交易在當天賣出的最好的利潤是多少(local[j])(看代碼中的英文解釋會更好一點)

    def maxProfit(self, k, prices):
        """
        :type k: int
        :type prices: List[int]
        :rtype: int
        """
        ##判斷是否在邊界
        n = len(prices)
        if k<=0 or n ==0:
            return 0
        ##如果k足夠大,那麼這個問題就會變成問題Ⅱ了
        if k>=n/2:
            result = 0
            for i in range(1,n):
                if prices[i]-prices[i-1]>0:
                    result +=prices[i] - prices[i-1]
            return result
        
        global_profit = [[0]*n for _ in range(k+1)]
        
        for i in range(1,k+1):
            local_profit = [0]*n
            for j in range(1,n):
                profit = prices[j] - prices[j-1]
                #We have made max profit with (i - 1) transations in (j - 1) days. 
                #For the last transation, we buy stock on day (j - 1) and sell it on day j.
                
                # We have made profit in (j - 1) days.
                # We want to cancel the day (j - 1) sale and sell it on day j.
                local_profit[j] = max(global_profit[i-1][j-1]+max(profit,0),local_profit[j-1]+profit)
                global_profit[i][j] = max(local_profit[j],global_profit[i][j-1])
        return global_profit[k][n-1]

199. Binary Tree Right Side View(Medium)

給定一個二叉樹,想象自己站在它的右側,返回從上到下排序的節點的值。
在這裏插入圖片描述

思路:
使用循環操作,選取最後一個

    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        res = [root]
        ans = []
        while(res):
            ans.append(res[-1].val)
            res = [k for node in res for k in (node.left,node.right) if k ]
        return ans

200. Number of Islands(Medium)

給定1d(陸地)和’0’(水)的2d網格圖,計算島嶼數量。島被水包圍,通過水平或垂直連接相鄰的土地而形成。
您可以假設網格的所有四個邊都被水包圍。
在這裏插入圖片描述

思路:
1、使用dfs
2、如果此處是1的話,就把周邊所有1 換成X,防止再次訪問(多個相鄰的1只能當作一個島嶼)

    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        def sink(i, j):
            if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1':
                grid[i][j] = 'X'
                map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1))
                # print(grid)
                return 1
            return 0
        
        return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i])))

201. Bitwise AND of Numbers Range(Medium)

計算區間[m,n]內所有數字的與。
Input: [5,7]
5 101 6 110 7 111
Output: 4

思路:
1、最後的結果一定是m、n最左邊共有的兩部分
2、首先將m、n右移,知道m和n相等爲止,用一個i記錄右移了幾位
3、再用i進行左移

    def rangeBitwiseAnd(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        i = 0
        while(m != n):
            m>>=1
            n>>=1
            i+=1
        return m<<i

207. Course Schedule(Medium)

您必須參加總共n門課程,標記爲0到n-1。 有些課程可能有先決條件,例如,要修課程0,你必須先修課程1,表示爲一對:[0,1]
鑑於課程總數和先決條件對列表,您是否可以完成所有課程?
在這裏插入圖片描述

思路:
此題考驗的是無環有向圖,還有拓撲排序
1、首先根據所有課程的先決條件構建無環有向圖
2、存儲所有節點的入度
3、當入度爲0時,加入pre中,然後使用循環把所有和pre中有關的節點入度都減一

    def canFinish(self, numCourses, prerequisites):
        """
        :type numCourses: int
        :type prerequisites: List[List[int]]
        :rtype: bool
        """
        graph = [[] for _ in range(numCourses)]
        degree = [0 for i in range(numCourses)]
        for i in prerequisites:
            graph[i[0]].append(i[1])
            degree[i[1]] +=1
        
        pre = []
        for i in range(len(degree)):
            if degree[i] ==0:
                pre.append(i)
        
        while(pre):
            node = pre.pop()
            for i in graph[node]:
                degree[i] -=1
                if degree[i] == 0:
                    pre.append(i)
        return max(degree)==0

208. Implement Trie (Prefix Tree)(Medium)

使用insert,search和startsWith方法實現trie。
在這裏插入圖片描述

思路:
定義一個TrieNode,包含word(判斷這個word是不是在trie中)、children存儲這個字的每個字符

class TrieNode:
    def __init__(self):
        self.word = False
        self.children = {}

class Trie(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.root = TrieNode()

        

    def insert(self, word):
        """
        Inserts a word into the trie.
        :type word: str
        :rtype: None
        """
        node = self.root
        for i in word:
            if i not in node.children:
                node.children[i] = TrieNode()
            node = node.children[i]
        node.word = True
        

    def search(self, word):
        """
        Returns if the word is in the trie.
        :type word: str
        :rtype: bool
        """
        node = self.root
        for i in word:
            if i not in node.children:
                return False
            node = node.children[i]
        return node.word

    def startsWith(self, prefix):
        """
        Returns if there is any word in the trie that starts with the given prefix.
        :type prefix: str
        :rtype: bool
        """
        node = self.root
        for i in prefix:
            if i not in node.children:
                return False
            node = node.children[i]
        return True

209. Minimum Size Subarray Sum(Medium)

給定n個正整數和正整數s的數組,找到連續子陣列的最小長度,其總和≥s。如果沒有,則返回0。
在這裏插入圖片描述

思路:
1、使用左右指針
2、如果sum>=s的時候,使用while循環,左邊不斷的加,直到不滿足條件爲止
3、最後如果找不到返回0

    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        left = right = 0
        min_length = len(nums)+1
        sum1 = 0
        for right in range(len(nums)):
            sum1 +=nums[right]
            #當加上一個數字後,尋找最小的長度,左邊不斷加,直到sum<s爲止
            while(sum1>=s):
                min_length = min(min_length,right+1-left)
                sum1 -=nums[left]
                left +=1
        return min_length if min_length!=len(nums)+1 else 0

210. Course Schedule II(Medium)

您必須參加總共n門課程,標記爲0到n-1。 有些課程可能有先決條件,例如,要修課程0,你必須先修課程1,表示爲一對:[0,1]
鑑於課程總數和先決條件對列表,列出按順序上的課程
在這裏插入圖片描述

思路:(和207類似)
此題考驗的是無環有向圖,還有拓撲排序
1、首先根據所有課程的先決條件構建無環有向圖
2、存儲所有節點的入度
3、當入度爲0時,加入pre中,然後使用循環把所有和pre中有關的節點入度都減一,使用一個a節點記錄所有節點爲0的節點

    def findOrder(self, numCourses, prerequisites):
        """
        :type numCourses: int
        :type prerequisites: List[List[int]]
        :rtype: List[int]
        """
        graph = [[] for _ in range(numCourses)]
        degree = [0 for i in range(numCourses)]
        for i in prerequisites:
            graph[i[1]].append(i[0])
            degree[i[0]] +=1
        
        pre = []
        a = []
        for i in range(len(degree)):
            if degree[i] ==0:
                pre.append(i)
                a.append(i)
        
        while(pre):
            node = pre.pop()
            for i in graph[node]:
                degree[i] -=1
                if degree[i] == 0:
                    pre.append(i)
                    a.append(i)
        return a if len(a)==numCourses else []

211. Add and Search Word - Data structure design(Medium)

在這裏插入圖片描述

思路:
1、初始化使用list dict
2、通過字的長度進行存儲 word
3、使用雙循環判斷word在哪個裏面

class WordDictionary(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.word_dict = collections.defaultdict(list)
        

    def addWord(self, word):
        """
        Adds a word into the data structure.
        :type word: str
        :rtype: None
        """
        if word:
            self.word_dict[len(word)].append(word)

    def search(self, word):
        """
        Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
        :type word: str
        :rtype: bool
        """
        if not word:
            return False
        if '.' not in word:
            return word in self.word_dict[len(word)]
        for v in self.word_dict[len(word)]:
            success = True
            for i,char in enumerate(word):
                if char!=v[i] and char!='.':
                    success = False
                    break
        return success


# Your WordDictionary object will be instantiated and called as such:
# obj = WordDictionary()
# obj.addWord(word)
# param_2 = obj.search(word)

212. Word Search II(Hard)

給定2D板和字典中的單詞列表,找到板中的所有單詞。
每個字必須由順序相鄰的單元的字母構成,其中“相鄰”單元是水平或垂直相鄰的單元。一個單詞中不能多次使用相同的字母單元格。
在這裏插入圖片描述

思路:
1、使用字典樹Trie,把所有要找的單詞放在字典樹裏,然後每個元素上下左右搜索,找到了就結束當前分支的搜索

class TrieNode():
    def __init__(self):
        self.children = collections.defaultdict(TrieNode)
        self.isWord = False

class Trie():
    def __init__(self):
        self.root = TrieNode()
    def insert(self,word):
        node = self.root
        for w in word:
            if w not in node.children:
                node.children[w] = TrieNode()
            node = node.children[w]
        node.isWord = True
    def search(self,word):
        node = self.root
        for w in word:
            node = node.children.get(w)
            if not node:
                return False
        return node.isWord

class Solution(object):
    def findWords(self, board, words):
        """
        :type board: List[List[str]]
        :type words: List[str]
        :rtype: List[str]
        """
        res = []
        trie = Trie()
        node = trie.root
        for w in words:
            trie.insert(w)
        for i in range(len(board)):
            for j in range(len(board[0])):
                self.dfs(board,node,i,j,'',res)
        return res
    
    def dfs(self,board,node,i,j,path,res):
        if node.isWord:
            res.append(path)
            node.isWord = False
        if i<0 or i>=len(board) or j<0 or j>=len(board[0]):
            return
        
        temp = board[i][j]
        node = node.children.get(temp)
        if not node:
            return
        board[i][j] = '#'
        self.dfs(board,node,i+1,j,path+temp,res)
        self.dfs(board,node,i,j+1,path+temp,res)
        self.dfs(board,node,i-1,j,path+temp,res)
        self.dfs(board,node,i,j-1,path+temp,res)
        board[i][j] = temp

213. House Robber II(Medium)

你是一個專業的強盜,計劃在街上搶劫房屋。每個房子都藏着一定數量的錢。這個地方的所有房屋都排成一個圓圈。這意味着第一棟房屋是最後一棟房屋的鄰居。與此同時,相鄰的房屋連接了安全系統,如果兩個相鄰的房屋在同一個晚上被闖入,它將自動聯繫警方。

思路:
1、使用DP
2、因爲首尾是鄰居,所以使用去首,去尾。當作兩個數組,然後找出兩個數組的最大值
3、比較res[i-1] 和res[i-2]+nums[i]的最大值
4、因爲動態數組是k循環的,所以採用k大小的數組,使得空間使用率降爲O(1)

def rob(self, nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    if len(nums) ==0:
        return 0
    if len(nums)<=3:
        return max(nums)
    return max(self.rob_row(nums[1:]),self.rob_row(nums[:-1]))
    
def rob_row(self,nums):
    res = [0]*2
    res[0] = nums[0]
    res[1] = max(nums[0],nums[1])
    for i in range(2,len(nums)):
        res[i%2] = max(res[(i-1)%2],res[(i-2)%2]+nums[i])
    return max(res)

214. Shortest Palindrome(Hard)

給定一個字符串s,您可以通過在其前面添加字符將其轉換爲迴文結構。通過執行此轉換,找到並返回您可以找到的最短迴文。
在這裏插入圖片描述

思路:
先搞清楚KMP算法

1、藉助KMP的算法,查看最長的公共長度(第一個值仍然爲0,並且我們只需要最後一個值nex[-1],因爲它表明了rev_s與s相互匹配的最大前綴長度。)
2、首先判斷本身是不是迴文
3、然後將s和r連接生成新的字符串l
4、循環判斷l中最大前綴和後綴
5、最後只需要將rev_s的前k個字符與原始串s拼接即可,其中k是s的長度len(s)與p[-1]之差。
http://bookshadow.com/weblog/2015/05/22/leetcode-shortest-palindrome/

    def shortestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        r = s[::-1]
        if r == s:
            return s
        l = s+'#'+r
        j = 0
        nex = [0]*len(l)
        for i in range(1,len(l)):
            j = nex[i-1]
            while j>0 and l[i]!=l[j]:
                j = nex[j-1]
            nex[i] = j + (l[i]==l[j])
        return r[:len(r)-nex[-1]]+s
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章