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//bc/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
  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值