leetcode-刷题记录

leetcode-刷题记录

  • 初级算法
    • 数组
      • 从排序数组中删除重复项
      • 买卖股票的最佳时机 II
      • 旋转数组
      • 存在重复
      • 只出现一次的数字
      • 两个数组的交集 II
      • 加一
      • 移动零
      • 两数之和
      • 有效的数独
    • 字符串
      • 反转字符串
      • 整数反转
      • 字符串中的第一个唯一字符
      • 有效的字母异位词
      • 验证回文字符串
      • 字符串转换整数 (atoi)
      • 实现 strStr()
      • 外观数列
      • 最长公共前缀
    • 链表
      • 删除链表中的节点
      • 反转链表
      • 合并两个有序链表
      • 回文链表
      • 环形链表
      • 二叉树的最大深度
      • 验证二叉搜索树
      • 对称二叉树
      • 二叉树的层次遍历
      • 将有序数组转换为二叉搜索树
    • 排序和搜索
      • 合并两个有序数组
      • 第一个错误的版本
    • 动态规划
      • 爬楼梯
      • 买卖股票的最佳时机
      • 最大子序和
      • 打家劫舍
  • 中级算法
    • 数组和字符串
      • 三数之和
      • 矩阵置零
      • 字谜分组
      • 无重复字符的最长子串
      • 最长回文子串
      • 递增的三元子序列
    • 链表
      • 两数相加
      • 奇偶链表
      • 相交链表
    • 树和图
      • 中序遍历二叉树
      • 二叉树的锯齿形层次遍历
      • 从前序与中序遍历序列构造二叉树
      • 填充每个节点的下一个右侧节点指针
      • 二叉搜索树中第K小的元素
      • 岛屿数量
    • 回溯算法
      • 电话号码的字母组合
      • 生成括号
      • 全排列
      • 子集
      • 单词搜索
    • 搜索排序
      • 颜色分类
      • 前 K 个高频元素
      • 数组中的第K个最大元素
      • 寻找峰值
      • 在排序数组中查找元素的第一个和最后一个位置
      • 合并区间
      • 搜索旋转排序数组
      • 搜索二维矩阵 II
    • 动态规划
      • 跳跃游戏
      • 不同路径
      • 不同路径II
      • 零钱兑换
      • Longest Increasing Subsequence
  • 探索-递归专题
    • 反转字符串
    • 两两交换链表中的节点
    • 杨辉三角
    • 杨辉三角II
    • 反转链表
    • 递归的重复计算问题的优化:记忆化
      • 斐波那契数
      • 爬楼梯
    • 递归的复杂度分析
      • 二叉树最大深度
      • Pow(x, n)
    • 总结
      • 合并两个有序链表
      • 第K个语法符号
  • 动态规划练习
    • 最小路径和
    • ==解码方法==
    • 不同的二叉搜索树
    • 不同的二叉搜索树 II
    • 三角形最小路径和
    • 单词拆分
    • ==乘积最大子数组==
    • 打家劫舍 II
    • 最佳买卖股票时机含冷冻期
    • 比特位计数
    • 整数拆分
    • 计算各个位数不同的数字个数
    • 最长回文子序列
    • 回文子串
    • 等差数列划分
    • 简化路径

开始leetcode刷题之旅。此博客仅做个人记录,没有相关讲解。

初级算法

数组

从排序数组中删除重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

	class Solution(object):
	    def removeDuplicates(self, nums):
	        """
	        :type nums: List[int]
	        :rtype: int
	        """
	        if len(nums)<2:
	            return len(nums)
	        else:
	            i = 0
	            j = 1
	            while 1:
	                while j<len(nums) and i<len(nums) and nums[j]<=nums[i]: 
	                    j += 1
	                if j==len(nums) or i == len(nums) :
	                    break
	                else:
	                    i += 1
	                    nums[i],nums[j] = nums[j],nums[i]
	                    j += 1
	                    #print(i,j,nums)
	            return i+1

买卖股票的最佳时机 II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多交易(多次买卖一支股票)。
注意:
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

	class Solution:
	    def maxProfit(self, prices: List[int]) -> int:
	        
	        buy = 0
	        sold = 0
	        res = 0
	        while buy < len(prices):
	            while sold<len(prices)-1 and prices[sold+1] > prices[sold]:
	                sold += 1
	            res += prices[sold] - prices[buy]
	            #print(buy,sold,res)
	            buy = sold + 1
	            sold = buy
	        return res

旋转数组

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

	class Solution(object):
	    def right(self, nums, k, l ):
	        print('right')
	        for i in range(k):
	            nums.extend(nums)
	            del nums[:-(l+1)]
	            del nums[-1]
	            
	    def left(self, nums, k, l):
	        print('left')
	        l = len(nums)
	        for i in range(k):
	            nums.extend(nums)
	            del nums[0]
	            del nums[l:]        
	            
	    def rotate(self, nums, k):
	        """
	        :type nums: List[int]
	        :type k: int
	        :rtype: None Do not return anything, modify nums in-place instead.
	        """
	        l = len(nums)
	        k = k%l
	        if k < 0.5*l:
	            self.right(nums, k, l)
	        else:
	            self.left(nums, l-k, l)

存在重复

给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

	class Solution(object):
	    def containsDuplicate(self, nums):
	        """
	        :type nums: List[int]
	        :rtype: bool
	        """
	        if len(nums) <= 1:
	            return False
	        else:
	            res = []
	            i = 0
	            j = len(nums)-1
	            while i < j:
	                if nums[i] == nums[j]:
	                    return True
	                elif nums[i] in res or nums[j] in res:
	                    return True
	                else:
	                    res.extend([nums[i],nums[j]])
	                    i += 1
	                    j -= 1
	            return False

17/18通过测试用例,不知道如何优化。哭哭

	class Solution:
	    def containsDuplicate(self, nums: List[int]) -> bool:
	        dic = {}
	        for i in range(len(nums)):
	            if nums[i] in dic:
	                return True
	            else:
	                dic[nums[i]]=i
	        return False

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

	class Solution(object):
	    def singleNumber(self, nums):
	        """
	        :type nums: List[int]
	        :rtype: int
	        """        
	        while len(nums) >= 1:
	            tmp = nums[0]
	            if tmp in nums[1:]:
	                nums.remove(tmp)
	                nums.remove(tmp)
	            else:
	                break
	        return nums[0]

两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

	class Solution(object):
	    def intersect(self, nums1, nums2):
	        """
	        :type nums1: List[int]
	        :type nums2: List[int]
	        :rtype: List[int]
	        """
	        n1 = nums1 if len(nums1) < len(nums2) else nums2
	        n2 = nums2 if len(nums1) < len(nums2) else nums1
	        res = []
	        for i in n1:
	            if i in n2:
	                res.append(i)
	                n2.remove(i)
	        return res

加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。

	class Solution(object):
	    def plusOne(self, digits):
	        """
	        :type digits: List[int]
	        :rtype: List[int]
	        """
	        res = []
	        flag = 0
	        for i in range(len(digits),0,-1):
	            if i == len(digits):
	                flag = 1 if digits[i-1] + 1 == 10 else 0
	            else :
	                flag = 1 if digits[i-1] + flag == 10 else 0
	            
	            digits[i-1] = 0 if flag == 1 else digits[i-1] + 1
	            
	            if flag == 0:
	                break
	        if flag == 1:
	            digits = [1]+digits
	        return digits

移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
1.必须在原数组上操作,不能拷贝额外的数组。
2.尽量减少操作次数。

	class Solution(object):
	    def moveZeroes(self, nums):
	        """
	        :type nums: List[int]
	        :rtype: None Do not return anything, modify nums in-place instead.
	        """
	        
	        x = nums.count(0)
	        for i in range(x):
	            indx = nums.index(0)
	            for j in range(indx,len(nums)-1):
	                nums[j] = nums[j+1]
	            nums[-1] = 0
	        return nums

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

	class Solution:
	    def twoSum(self, nums: List[int], target: int) -> List[int]:
	        # bad
	        for i in range(len(nums)-1):
	            sub = nums[i+1:]
	            res_sub = [j+nums[i] for j in sub]
	            if target in res_sub:
	                return [i,i+res_sub.index(target)+1]
	        # hashmap
	        dic = {}
	        for i,n in enumerate(nums):
	            if target-n in dic:
	                return [dic[target-n],i]
	            else:
	                dic[n]=i
	                

有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

		class Solution:
		    def isValidSudoku(self, board: List[List[str]]) -> bool:
		        dic_row = {}
		        dic_col = {}
		        dic_block = {}
		        for i in range(9):
		            # row
		            for j in range(9):
		                # column
		                if board[i][j] == '.':
		                    continue
		                    
		                if i not in dic_row:
		                    dic_row[i] = [board[i][j]]
		                else:
		                    if board[i][j] in dic_row[i]:
		                        return False
		                    else:
		                        dic_row[i].append(board[i][j])
		                    
		                if j not in dic_col:
		                    dic_col[j] = [board[i][j]]
		                else:
		                    if board[i][j] in dic_col[j]:
		                        return False
		                    else:
		                        dic_col[j].append(board[i][j])
		                        
		                if 10*int(i/3)+int(j/3) not in dic_block:
		                    dic_block[10*int(i/3)+int(j/3)] = [board[i][j]]
		                else:
		                    if board[i][j] in dic_block[10*int(i/3)+int(j/3)]:
		                        return False
		                    else:
		                        dic_block[10*int(i/3)+int(j/3)].append(board[i][j])
		                    
		        return True

字符串

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

	
	class Solution:
	    def reverseString(self, s: List[str]) -> None:
	        """
	        Do not return anything, modify s in-place instead.
	        """
	        start = 0
	        end = len(s)-1
	        while start<end:
	            s[start],s[end] = s[end],s[start]
	            start = start + 1
	            end = end - 1
	        return s

整数反转

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转.。

class Solution:
    def reverse(self, x: int) -> int:
        if -10<x<10:
            return x
        elif x<0:
            flag = 1
            x = -x
        else:
            flag = 0
        #import math
        #n = int(math.log(x)/math.log(10))
        n = len(list(str(x)))-1
        res = 0
        while x > 0:
            res = (x%10)*10**n + res
            x = int(x/10)
            n = n-1
        res = -res if flag==1 else res
        res = 0 if res<-2**31 or res>2**31-1 else res
        return res

字符串中的第一个唯一字符

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

class Solution:
    def firstUniqChar(self, s: str) -> int:
        dic_1 = {}
        dic_2 = {}
        for i in range(len(s)):
            if s[i] in dic_1:
                del dic_1[s[i]]
                dic_2[s[i]] = i
            else:
                if s[i] in dic_2:
                    continue
                else:
                    dic_1[s[i]] = i
        if dic_1 == {}:
            return -1
        else:
            res = len(s)
            for i in dic_1:
                if dic_1[i] < res:
                    res = dic_1[i]
            return res
            # 104ms
            res = min([dic_1[i] for i in dic_1])
            return res
            # 112ms

有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
       
        if len(s) != len(t):
            return False
        
        # solution1
        t = list(t)
        for i in s:
            if i in t:
                t.remove(i)
        return t==[]

有更好的解法

验证回文字符串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。

class Solution:
    def isPalindrome(self, s: str) -> bool:
        # 65,97,48
        
        dic = {}
        for i in range(128):
            dic[chr(i)] = i
        #print(dic)
        i = 0
        j = len(s)-1
        while i<j:
            while not (dic['A']<=dic[s[i]]<=dic['Z'] or dic['a']<=dic[s[i]]<=dic['z'] or dic['0']<=dic[s[i]]<=dic['9']) and i < j:
                i += 1
            while not (dic['A']<=dic[s[j]]<=dic['Z'] or dic['a']<=dic[s[j]]<=dic['z'] or dic['0']<=dic[s[j]]<=dic['9']) and i < j:
                j -= 1
            si = dic[s[i]] if dic[s[i]]<=dic['Z'] else dic[s[i]]-32
            sj = dic[s[j]] if dic[s[j]]<=dic['Z'] else dic[s[j]]-32
            if si == sj:
                i += 1
                j -= 1
            else:
                return False
        return True

字符串转换整数 (atoi)

请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。

class Solution:
    def myAtoi(self, str: str) -> int:
        dic = {}
        for i in range(ord('0'),ord('9')+1):
            dic[chr(i)] = i
            
        if len(str) == 0:
            return 0
        
        elif str[0] in dic or str[0] == ' ' or str[0]=='+' or str[0]=='-':
            i = 0
            while i < len(str) and str[i] == ' ':
                i += 1
            str = str[i:]
            if len(str) == 0:
                return 0
            
            flag = 1
            if str[0] == '+':
                str = str[1:]
            elif str[0] == '-':
                flag = -1
                str = str[1:]
            if len(str) == 0:
                return 0
            
            i = 0
            res = 0
            while i<len(str):
                try:
                    res = flag*int(str[:i+1])
                    i += 1
                except:
                    break
        
            if res>0:
                return min(res,2**31-1)
            else:
                return max(res,-2**31)
           
        else:
            return 0

实现 strStr()

实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        if needle == '':
            return 0
        i = 0
        while i < len(haystack):
            while i < len(haystack) and haystack[i] != needle[0]:
                i += 1
            if i == len(haystack):
                return -1
            res = i
            
            j = 0
            while j < len(needle) and i < len(haystack) and haystack[i]==needle[j]:
                j += 1
                i += 1
            if j == len(needle):
                return res
            if i == len(haystack):
                return -1
            i  = res + 1
        return -1

外观数列

外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:

	1.	1
	2.  11
	3.  21
	4.  1211
	5.  111221
class Solution:
    def countAndSay(self, n: int) -> str:
        dic = {1:"1"}
        if n==1:
            return "1"
        else:
            if n-1 in dic:
                tmp_n_1 = dic[n-1]
            else:
                tmp_n_1 = self.countAndSay(n-1)
                dic[n-1] = tmp_n_1
            res = ['1',tmp_n_1[0]]
            for i in range(1,len(tmp_n_1)):
                if tmp_n_1[i] == res[-1]:
                    res[-2] = str(1+int(res[-2]))
                else:
                    res.extend(['1',tmp_n_1[i]]) 
            return ''.join(res)

最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs) == 0:
            return ""
        elif len(strs) == 1:
            return strs[0]
        elif '' in strs:
            return ''
        p = 0
        while 1:
            if p < len(strs[0]):
                tmp = strs[0][:p+1] 
            else:
                return tmp
            for i in range(1,len(strs)):
                if p < len(strs[i]):
                    tmp1 = strs[i][:p+1]
                    if tmp1 == tmp:
                        continue
                    else:
                        return tmp[:-1]
                else:
                    return strs[i]
            p += 1

有更优的解法。

链表

删除链表中的节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        
        # solution1
        tmp = head
        length = 1
        while tmp.next != None:
            length+=1
            tmp = tmp.next
            
        tmp = head
        # del_id + n == length+1
        if n==length:
            # first
            return head.next
        elif n==1:
            # last
            for i in range(length-2):
                tmp = tmp.next
            tmp.next = None
            return head
        else:
            del_id = length-n
            for i in range(del_id-1):
                tmp = tmp.next
            tmp.next = tmp.next.next
            return head
        
        # solution2
        tmp1 = head
        while 1:
            tmp2 = tmp1
            for i in range(n+1):
                try:
                    tmp2 = tmp2.next
                except:
                    return tmp1.next
            if tmp2 is None:
                tmp1.next = tmp1.next.next if n>1 else None
                print(head)
                return head
            else:
                tmp1 = tmp1.next

反转链表

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        
        # recursion
        if head is None:
            return head
        res = head
        head = head.next
        res.next = None
        while head is not None:
            tmp1 = head.next
            head.next=res
            res = head
            head = tmp1
        return res
        
        # BP
        if head is None or head.next is None:
            return head
        else:
            tmp = head
            sub = self.reverseList(head.next)
            tmp.next.next = tmp
            tmp.next = None
            return sub

合并两个有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 is None or l2 is None:
            head = l1 if l2 is None else l2
            return head
        
        if l1.val > l2.val:
            head = l2
            l2 = l2.next
        else:
            head = l1
            l1 = l1.next
        res = head
            
        while l1 is not None and l2 is not None:
            if l1.val < l2.val:
                res.next = l1
                res = res.next
                l1 = l1.next
            else:
                res.next = l2
                res = res.next
                l2 = l2.next        
        if l1 is None and l2 is not None:
            res.next = l2
            return head
        elif l2 is None and l1 is not None:
            res.next = l1
            return head

回文链表

请判断一个链表是否为回文链表。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        dic = {}
        tmp = head
        p = 0
        while tmp is not None:
            dic[p] = tmp.val
            p  += 1
            tmp = tmp.next
            
        length = int(p/2)
        
        for i in range(length):
            if dic[p-1-i] == head.val:
                head = head.next
            else:
                return False
        return True

环形链表

给定一个链表,判断链表中是否有环。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if head is None:
            return False
        dic = {}
        while head is not None:
            if head in dic:
                return True
            else:
                dic[head] = head.val
                head = head.next
        return False

通过。选择合适的数据格式很有必要,字典的耗时远小于列表的。

二叉树的最大深度

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if root == None:
            return 0
        else:
            if root.left is None and root.right is None:
                return 1
            elif root.left is not None and root.right is not None:
                return max(self.maxDepth(root.left),self.maxDepth(root.right))+1
            elif root.left is None and root.right is not None:
                return self.maxDepth(root.right)+1
            else:
                return self.maxDepth(root.left)+1

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
1.节点的左子树只包含小于当前节点的数。
2.节点的右子树只包含大于当前节点的数。
3,所有左子树和右子树自身必须也是二叉搜索树。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def tree2list(self, root: TreeNode) -> list:
            """
            if root.left is not None:
                self.isValidBST(root.left)
            print(root.val)
            if root.right is not None:
                self.isValidBST(root.right)
            """
            res_list = [root.val] if root.left is None else self.tree2list(root.left) + [root.val]
            res_list = res_list if root.right is None else res_list + self.tree2list(root.right)
            return res_list
    def isValidBST(self, root: TreeNode) -> bool:
        
        if root is None:
            return True
        else:
            """
            res = self.tree2list(root)
            for i in range(1,len(res)):
                if res[i] <= res[i-1]:
                    return False
            """
            if root.left is not None:
                left = self.tree2list(root.left)
                for i in range(1,len(left)):
                    if left[i] <= left[i-1] :
                        return False
            else:
                left = []
            
            if left != []:
                if root.val <= left[-1]:
                    return False
            
            if root.right is not None:
                right = self.tree2list(root.right)
                if right[0] <= root.val:
                    return False
                for i in range(1,len(right)):
                    if right[i] <= right[i-1] :
                        return False 
            return True

二叉树的中序遍历结果,是一个递增的数组。

对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def tree2list(self, root: TreeNode, mode: bool) -> list:
        # mode: left--->right
        #print(root)
        left = self.tree2list(root.left,mode) if root.left is not None else ['null']
        right = self.tree2list(root.right,mode) if root.right is not None else ['null']
        if mode:
            return  [root.val] + left + right
        else:
            return  [root.val] + right + left
        
    def isSymmetric(self, root: TreeNode) -> bool:
        if root is None:
            return True
        elif root.left is None and root.right is None:
            return True
        elif root.left is None or root.right is None:
            return False
        l2r = self.tree2list(root,True)
        r2l = self.tree2list(root,False)
        print(l2r,r2l)
        return l2r==r2l

所谓对称就是先做后右,还是先右后左的遍历结果是一致的,目前是用到的BP的方法。

二叉树的层次遍历

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if root is None:
            return []
        if root.left is None and root.right is None:
            return [[root.val]]
        
        l = self.levelOrder(root.left) if root.left is not None else []
        r = self.levelOrder(root.right) if root.right is not None else []
        
        res = [[root.val]]
        while l != [] and r !=[]:
            tmp = l[0] + r[0]
            res.append(tmp)
            l = l[1:]
            r = r[1:]
            
        if l != [] and r == []:
            res.extend(l)
        elif l == [] and r != []:
            res.extend(r)
            
        return res

将有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        
        if len(nums)==0:
            return None
        elif len(nums) == 1:
            res = TreeNode(nums[0])
            return res
        elif len(nums) == 2:
            res = TreeNode(nums[-1])
            res.left = TreeNode(nums[0])
            return res
        elif len(nums) == 3:
            res = TreeNode(nums[1])
            res.left = TreeNode(nums[0])
            res.right = TreeNode(nums[2])
            return res
        
        root_id = int(len(nums)/2)
        res = TreeNode(nums[root_id])
        res.left = self.sortedArrayToBST(nums[:root_id])
        res.right = self.sortedArrayToBST(nums[root_id+1:])
        return res

排序和搜索

合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 num1 成为一个有序数组。
说明:
1.初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        if m == 0:
            nums1[:n+1] = nums2
        elif n == 0:
            pass
        else:
            i = m-1
            # nums1
            j = n-1
            # nums2
            for p in range(m+n-1,-1,-1):
 
                if nums1[i] > nums2[j]:
                    nums1[p] = nums1[i]
                    i = i-1
                else:
                    nums1[p] = nums2[j]
                    j = j-1
                if j == -1:
                    break
                if i == -1:
                    nums1[:p] = nums2[:j+1]
                    break

第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):
 
class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        t1 = 1
        t2 = n
        while 1:
            test_id = int((t1+t2)/2)
            tests = [isBadVersion(test_id-1),isBadVersion(test_id)]
            if tests == [False,True]:
                return test_id
            elif tests == [False,False]:
                t1 = test_id+1
            elif tests == [True,True]:
                t2 = test_id-1

动态规划

爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            # solution1
            res = [1,2]
            for i in range(2,n):
                res.append(res[i-1]+res[i-2])
            return res[-1]
            # solution2
            res_dic = {1:1,2:2}
            for i in range(3,n+1):
                res_dic[i] = res_dic[i-1]+res_dic[i-2]
            return res_dic[n]
            # solution3
            tmp1 = 1
            tmp2 = 2
            for i in range(3,n+1):
                res = tmp1 + tmp2
                tmp1 = tmp2
                tmp2 = res
            return res

经典中的经典,也是最基础,最简单的。

买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices) <= 1:
            return 0
        buy = prices[0]
        sell = 0
        for i in range(1,len(prices)):
            buy = min(buy,prices[i])
            sell = max(sell,prices[i]-buy)
        return sell

一开始理解,还是比较困难。buy是逐步找到整个序列中的最小值,sold则是buy之后的最大值。
动态规划最重要的是:状态转移方程

最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        tmp = nums[0]
        res = tmp
        nums = nums[1:]
        for i in nums:
            if tmp<0:
                tmp = i
            else:
                tmp = tmp+i
            res = max(res,tmp)
        return res

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

class Solution:
    def rob(self, nums: List[int]) -> int:
        if nums == []:
            return 0
        if len(nums) <= 2:
            return max(nums)
        res = [nums[0],max(nums[:2])]
        nums = nums[2:]
        for i in nums: 
            tmp = max(res[-1],res[-2]+i)
            res[0] = res[1]
            res[1] = tmp
        return res[-1]

中级算法

数组和字符串

三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = {}
        r = 0
        for a in range(len(nums)-2):
            b = a+1
            c = len(nums)-1
            if a>0 and nums[a] == nums[a-1]:
                continue
            if nums[a]>0:
                break
            while b<c:
                if nums[a] + nums[b] + nums[c] == 0:
                    res[r] = [nums[a],nums[b],nums[c]]
                    r += 1
                    b += 1
                    while a<b<c and nums[b] == nums[b-1]:
                        b += 1
                    c -= 1
                    while a<b<c and nums[c] == nums[c+1]:
                        c -= 1
                elif nums[a] + nums[b] + nums[c] > 0:
                    c -= 1
                    while a<b<c and nums[c] == nums[c+1]:
                        c -= 1
                else:
                    b += 1
                    while a<b<c and nums[b] == nums[b-1]:
                        b += 1
                if nums[c] < 0:
                    break
        x = [res[i] for i in res]
        return x

指针的正确使用

矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        # mn额外空间的,应该是类似于flag_matrix的感觉
        # n+m的,应该是行列分开记录。
        
        row = []
        col = []
        r_m = len(matrix)
        c_m = len(matrix[0])
        for r in range(r_m):
            for c in range(c_m):
                if matrix[r][c] == 0:
                    row.append(r)
                    col.append(c)      
        for r in range(r_m):
            for c in range(c_m):
                if r in row or c in col:
                    matrix[r][c] = 0

字谜分组

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串.

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        dic = {}
        for i in strs:
            tmp = [ord(ii) for ii in i]
            tmp.sort()
            #tmp = sum(tmp)
            tmp = ''.join([chr(i) for i in tmp])
            if tmp in dic:
                dic[tmp].append(i)
            else:
                dic[tmp] = [i]
        res = []
        for i in dic:
            res.append(dic[i])
        return res            

做了转换。用ascii码排序。

无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        res = 0
        tmp = ''
        for i in s:
            if i not in tmp:
                tmp += i  
            else:
                res = max(res,len(tmp))
                tmp = tmp.rsplit(i)[-1] + i
        res = max(res,len(tmp))    
        return res

最长回文子串

定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s) <= 1:
            return s
        elif len(s) == 2:
            if s[0] == s[-1]:
                return s
            else:
                return s[0]
            
        res = s[0]
        for i in range(1,len(s)):
            tmp1 = s[:i]
            tmp2 = s[i:]
            
            if tmp1[-1] == tmp2[0]:
                tmp = ''
                for j in range(min(len(tmp1),len(tmp2))):
                    if tmp1[-(j+1)] == tmp2[j]:
                        tmp = tmp1[-(j+1)] + tmp + tmp2[j]
                    else:
                        break
                res = res if len(res) > len(tmp) else tmp
                
            tmp1 = s[:i]
            tmp2 = s[i:]
            
            if len(tmp2)>1 and tmp1[-1] == tmp2[1]:
                tmp = tmp2[0]
                tmp2 = tmp2[1:]
                for j in range(min(len(tmp1),len(tmp2))):
                    if tmp1[-(j+1)] == tmp2[j]:
                        tmp = tmp1[-(j+1)] + tmp + tmp2[j]
                    else:
                        break
                res = res if len(res) > len(tmp) else tmp
        
        return res

还有一种动态规划的解法,不会。。。。

递增的三元子序列

给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。
数学表达式如下:
如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1,使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false。

class Solution:
    def increasingTriplet(self, nums: List[int]) -> bool:
        # 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。
        minx = float('inf')
        maxx = float('inf')
        for i in nums:
            if i<minx:
                minx = i
            elif minx<i<maxx:
                maxx = i
            elif i>maxx:
                return True
        return False

遍历数组,找到当前的最小值和最大值。

链表

两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        tmp = l1.val + l2.val
        res = ListNode(tmp%10)
        res_f = res
        flag = int(tmp/10)
        l1 = l1.next
        l2 = l2.next
        while l1 is not None or l2 is not None:
            if l1 is not None and l2 is not None:
                tmp = l1.val + l2.val + flag
                l1 = l1.next
                l2 = l2.next
            elif l1 is None and l2 is not None:
                tmp = l2.val + flag
                l2 = l2.next
            elif l1 is not None and l2 is None:
                tmp = l1.val + flag
                l1 = l1.next
            tmp_node = ListNode(tmp%10)
            flag = int(tmp/10)
            res.next = tmp_node
            res = res.next
        if flag == 1:
            res.next = ListNode(1)
            return res_f
        else:
            return res_f

奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head or head.next is None:
            return head
       
        tmp1 = head
        tmp2 = head.next
        even = tmp2
        
        while 1:
            if tmp2.next is not None:
                tmp1.next = tmp2.next
                tmp1 = tmp1.next
            else:
                tmp1.next = even
                break
            
            if tmp1.next is not None:
                tmp2.next = tmp1.next
                tmp2 = tmp2.next
            else:
                tmp2.next = None
                tmp1.next = even
                break
        return head

不是最优方法,还有改进空间。

相交链表

编写一个程序,找到两个单链表相交的起始节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        
        # hash
        dic_A = {}
        while headA is not None:
            dic_A[headA] = headA.val
            headA = headA.next
        
        while headB is not None:
            if headB in dic_A:
                return headB
            else:
                headB = headB.next
        return None
        # 
        A = headA
        B = headB
        while A is not None and B is not None:
            if A == B:
                return A
            A = A.next
            B = B.next
            
            A = headB if A is None and B is not None else A
            B = headA if A is not None and B is None else B
            
        return None

第一种是用hash的方法,对其中一个链表建立hash表,然后遍历另外一个。第二种方法是先找到两个链表,从后往前数,长度相同的部分。之后再一下一下往后移动指针,寻找相同的部分。

树和图

中序遍历二叉树

给定一个二叉树,返回它的中序遍历。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        res = []
        if root.left is not None:
            res.extend(self.inorderTraversal(root.left))
        res.append(root.val)
        if root.right is not None:
            res.extend(self.inorderTraversal(root.right))
        return res

二叉树的锯齿形层次遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    
    def ori_zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
        if root.left is None and root.right is None:
            return [[root.val]]
        
        left = self.ori_zigzagLevelOrder(root.left) if root.left is not None else []
        right = self.ori_zigzagLevelOrder(root.right) if root.right is not None else []
        res = [[root.val]]
        if left == []:
            res.extend(right)
            return res
        if right == []:
            res.extend(left)
            return res
        while 1:
            res.append(left[0]+right[0])
            left = left[1:]
            right = right[1:]
            if left == [] or right ==[]:
                break
        res.extend(left)
        res.extend(right)
        return res
    
    def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
        
        if not root:
            return []
        res = self.ori_zigzagLevelOrder(root)
        for i in range(1,len(res),2):
            res[i] = res[i][::-1]
        print(res)
        return res

有优化空间。

从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。
注意:你可以假设树中没有重复的元素。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if len(inorder) == 3 and preorder[1:] == [inorder[0],inorder[-1]]:
            root = TreeNode(preorder[0])
            root.left = TreeNode(preorder[1])
            root.right = TreeNode(preorder[-1])
            return root
        if len(inorder) == 2:
            if preorder == inorder:
                root = TreeNode(preorder[0])
                root.right = TreeNode(preorder[-1])
                return root
            else:
                root = TreeNode(preorder[0])
                root.left = TreeNode(preorder[-1])
                return root
        if len(inorder) == 1:
            return TreeNode(preorder[0])
        if len(inorder) == 0:
            return None
        
        root = TreeNode(preorder[0])
        root_ind = inorder.index(preorder[0])
        if root_ind == len(inorder)-1:
            # only left
            left_in = inorder[:-1]
            left_pre = preorder[1:]
            root.left = self.buildTree(left_pre,left_in) 
            return root
        if  root_ind == 0:
            # only right
            right_in = inorder[1:]
            right_pre = preorder[1:]
            root.right = self.buildTree(right_pre,right_in)
            return root
        else:
            left_in = inorder[:root_ind]
            left_pre = preorder[1:1+len(left_in)]
            right_in = inorder[root_ind+1:]
            right_pre = preorder[-len(right_in):]
            root.left = self.buildTree(left_pre,left_in) 
            root.right = self.buildTree(right_pre,right_in)
            return root

填充每个节点的下一个右侧节点指针

没有完成

二叉搜索树中第K小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def inorderTraversal(self,root):
        if not root:
            return []
        if root.left is None and root.right is None:
            return [root.val]
        res = []
        res.extend(self.inorderTraversal(root.left))
        res.append(root.val)
        res.extend(self.inorderTraversal(root.right))
        return res
    
    def kthSmallest(self, root: TreeNode, k: int) -> int:
        
        if root.left is None and root.right is None:
            return root.val
        
        left = self.inorderTraversal(root.left) if root.left is not None else []
        if k <= len(left):
            return left[k-1]
        elif k == len(left)+1:
            return root.val
        else:
            k = k-len(left)-2
        right = self.inorderTraversal(root.right)
        return right[k]

岛屿数量

没有完成

回溯算法

电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        dic = {'2':['a','b','c'],
               '3':['d','e','f'],
               '4':['g','h','i'],
               '5':['j','k','l'],
               '6':['m','n','o'],
               '7':['p','q','r','s'],
               '8':['t','u','v'],
               '9':['w','x','y','z']
              }
        if len(digits) == 0:
            return []
        elif len(digits) == 1:
            return dic[digits[0]]
        else:
            res = []
            tmp = self.letterCombinations(digits[1:]) 
            for ch in dic[digits[0]]:
                for strs in tmp:
                    res.append(ch+strs)
            return res

生成括号

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        if n == 0:
            return [""]
        elif n == 1:
            return ["()"]
        elif n == 2:
            return ["(())","()()"]
        else:
            res = []
            for i in range(n):
                j = n - i - 1
                left = self.generateParenthesis(i)
                right = self.generateParenthesis(j)
                #print(['({}){}'.format(l,r) for l in left for r in right])
                res.extend(['({}){}'.format(l,r) for l in left for r in right])
                print(i,j,res)
            return res

这个题比较难理解

全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        if len(nums) == 0:
            return []
        elif len(nums) == 1:
            return [nums]
        elif len(nums) == 2:
            return [nums,nums[::-1]]
        else:
            res = []
            tmp = self.permute(nums[:-1])
            for i in tmp:
                for j in range(len(nums)):
                    res.append(i[:j]+[nums[-1]]+i[j:])
            return res

子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        if len(nums) == 0:
            return [[]]
        elif len(nums) == 1:
            return [[],nums]
        else:
            tmp = self.subsets(nums[:-1])
            res = []
            for i in tmp:
                res.append(i.copy())
                i.append(nums[-1])
                res.append(i)          
            return res

单词搜索

没有完成

搜索排序

颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        
        n_0 = 1 if nums[0] == 0 else 0
        for i in range(1,len(nums)):
            print(i,nums[i],nums)
            if nums[i]==2:
                continue
            if nums[i]==1:
                nums[n_0+1:i+1] = nums[n_0:i]
                nums[n_0] = 1
            if nums[i]==0:
                nums[1:i+1] = nums[0:i]
                nums[0] = 0
                n_0 += 1

前 K 个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        if len(nums) == k:
            return nums
        dic = {}
        for i in nums:
            if i in dic:
                dic[i]+=1
            else:
                dic[i]=1
        fre = []
        res = []
        for i in dic:
            if len(res)<k:
                fre.append(dic[i])
                res.append(i)
            elif dic[i] > min(fre):
                ind = fre.index(min(fre))
                res[ind] = i
                fre[ind] = dic[i]
        return res

数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        if k < int(len(nums)*0.5):
            # k largest
            for i in range(k):
                for j in range(1,len(nums)):
                    if nums[j] < nums[j-1]:
                        nums[j],nums[j-1] = nums[j-1],nums[j]
                res = nums[-1]
                nums = nums[:-1]
            return res
        else:
            k = len(nums) - k + 1
            for i in range(k):
                for j in range(1,len(nums)):
                    if nums[j] > nums[j-1]:
                        nums[j],nums[j-1] = nums[j-1],nums[j]
                res = nums[-1]
                nums = nums[:-1]
            return res

寻找峰值

峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞。

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        
        nums.append(float(-inf))
        nums = [float(-inf)] + nums
        for i in range(1,len(nums)-1):
            tmp = nums[i-1:i+2] 
            if tmp[1] > tmp[0] and tmp[1]>tmp[2]:
                return i-1

在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        # 二分查找
        if len(nums) == 0:
            return [-1,-1]
        if target < nums[0] or target > nums[-1]:
            return [-1,-1]
        elif target == nums[0]:
            i = 0
            while i<len(nums)-1 and nums[i+1] == target:
                i = i+1
            return [0,i]
        elif target == nums[-1]:
            i = len(nums)-1
            while i>1 and nums[i-1] == target:
                i = i-1
            return [i,len(nums)-1]
        else:
            s = 0
            e = len(nums)-1
            while s<=e:
                mid = int(0.5*(s+e))
                if nums[mid] == target:
                    i = mid
                    j = mid
                    while i>=1 and nums[i-1] == target:
                        i = i-1
                    while j<=len(nums)-1 and nums[j+1] == target:
                        j = j+1
                    return [i,j]
                elif nums[mid] > target:
                    e = mid-1
                    while s<e and nums[e-1] == nums[e]:
                        e = e-1
                else:
                    s = mid+1
                    while s<e and nums[s+1] == nums[s]:
                        s = s+1
            return [-1,-1]

合并区间

没有完成

搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        dic = dict(zip(nums,range(len(nums))))
        try:
            return dic[target]
        except:
            return -1

这道题应该是用二分查找做的,这里做的不对。

搜索二维矩阵 II

没有完成

动态规划

跳跃游戏

给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        if len(nums) == 1:
            return True
        p = 0
        while p<len(nums):
            print(p)
            jump = nums[p]
            if jump == 0:
                return False
            if jump + p >= len(nums)-1:
                return True
            pos_i = nums[p+1:p+jump+1]
            while len(pos_i)>0 and pos_i[-1] == 0:
                pos_i = pos_i[:-1]
            if len(pos_i) == 0:
                return False
            while len(pos_i)>1 and pos_i[-2]>pos_i[-1]:
                pos_i = pos_i[:-1]
            p = p+len(pos_i)
            
        return False

不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        
        res = [[0]*m]*n
        res[0] = [1]*m
        for i in range(1,n):
            for j in range(0,m):
                if j == 0:
                    res[i][j] = 1
                else:
                    res[i][j] = res[i-1][j] + res[i][j-1]
        return res[n-1][m-1]

不同路径II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        last = obstacleGrid[-1][-1]
        fisrt = obstacleGrid[0][0]
        if last == 1:
            return 0
        if fisrt == 1:
            return 0
        col = len(obstacleGrid[0])
        row = len(obstacleGrid)
        res = [[0]*col]*row
        
        for r in range(row):
            for c in range(col):
                if obstacleGrid[r][c] == 1:
                    res[r][c] = 0
                else:
                    if r==0 and c==0:
                        res[r][c] = 1-obstacleGrid[0][0]
                    elif r == 0 and c>0:
                        res[r][c] = res[r-1][c-1]
                    elif c == 0 and r>0:
                        res[r][c] = res[r-1][c]
                    else:
                        res[r][c] = res[r-1][c] + res[r][c-1]
        return res[-1][-1]

类似的思路,加了些条件判定。

零钱兑换

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        """
        # up to bottom
        if amount == 0:
            return 0
        elif amount < 0:
            return -1
        res = float('inf')
        tmp_dic = {0: 0, -1: -1}
        for i in coins:
            if amount-i in tmp_dic:
                tmp = tmp_dic[amount-i]
            else:
                tmp = self.coinChange(coins,amount-i)
                #print(coins,amount-i,tmp)
                tmp_dic[amount-i] = tmp
            if tmp != -1:
                res = min(res,tmp+1)
        res = res if res != float('inf') else -1
        return res
        """
        # bottom to up
        dic = {0:0}
        for a in range(1,amount+1):
            tmp = [dic[a-i]+1 for i in coins if a-i in dic.keys() and dic[a-i] !=-1]
            dic[a] = min(tmp) if tmp != [] else -1
        return dic[amount]

Longest Increasing Subsequence

给定一个无序的整数数组,找到其中最长上升子序列的长度。

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if len(nums)<2:
            return len(nums)
        tmp = [nums[0]]
        res = 1
        for i in nums:
            if i > tmp[-1]:
                tmp.append(i)
                res = max(res,len(tmp))
            else:
                n = sum([1 for j in tmp if j>i])
                if n == 1:
                    tmp = [j for j in tmp if j<i]
                    tmp.append(i)
        return res

探索-递归专题

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

class Solution(object):
    def reverseString(self, s):
        """
        :type s: List[str]
        :rtype: None Do not return anything, modify s in-place instead.
        """
        if len(s)==0:
            return s
        else:
            s[0],s[-1] = s[-1],s[0]
            if len(s) <= 3:
                return s
            else:
                s[1:-1]=self.reverseString(s[1:-1])
                return s

提交代码后显示:477/478个通过测试用例,总是说超出内存限制,不知道该怎么改进了。。。

两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head is None or head.next is None:
            return head
        else:
            tmp = head.next.next
            h = head.next
            h.next = head
            if tmp is None:
                h.next.next = None
                return h
            else:
                h.next.next = self.swapPairs(tmp)
                return h

杨辉三角

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

class Solution(object):
    def generate(self, numRows):
        """
        :type numRows: int
        :rtype: List[List[int]]
        """
        if  numRows == 0:
            return []
        elif numRows == 1:
            return [[1]]
        elif numRows == 2:
            return [[1],[1,1]]
        else:
            res_1 = self.generate(numRows-1)
            last_e = res_1[-1]
            new = [1]
            for i in range(len(last_e)-1):
                new.append(last_e[i]+last_e[i+1])
            new.append(1)
            res_1.append(new)
            return res_1

杨辉三角II

给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

class Solution(object):
    def getRow(self, rowIndex):
        """
        :type rowIndex: int
        :rtype: List[int]
        """
        if rowIndex == 0:
            return [1]
        elif rowIndex == 1:
            return [1,1]
        else:
            last_e = self.getRow(rowIndex-1)
            last_e_1 = last_e[1:]
            new = [1] + [sum(x) for x in zip(last_e,last_e_1)] + [1]
            return new

反转链表

反转一个单链表。可以迭代或递归地反转链表

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        #print('head',head)
        if head is None or head.next is None:
            return head
        else:
            # recursion
            last = self.reverseList(head.next)
            head.next.next = head
            head.next = None
            return last
            # iteration
            p = head
            q = head.next
            p.next = None
            while q is not None:
                r = q.next
                q.next = p
                p = q
                q = r
            return p

这是很经典,也花了很长时间理解的一个题目,对于理解递归帮助很大。递归的精髓在于:理解递归函数的输出,或是定义。例如反转链表时,首先确认好,函数返回的会是一个反转好的链表的head,那么,调用self.reverseList(head.next)获得的就是一个已经反转好的链表,最后一个element是head.next!!!

递归的重复计算问题的优化:记忆化

斐波那契数

斐波那契数,给定 N,计算 F(N)

class Solution(object):
    def fib(self, N):
        """
        :type N: int
        :rtype: int
        """
        # original
        if N == 0:
            return 0
        elif N == 1:
            return 1
        else:
            return self.fib(N-1)+self.fib(N-2)
        
        # memorization
        dic_fib = {0:0,1:1}
        def save_fib(N):
            print(dic_fib)
            if N in dic_fib:
                return dic_fib[N]
            else:
                s = save_fib(N-1)+save_fib(N-2)
                dic_fib[N] = s
                return s
        return save_fib(N)

爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==1:
            return 1
        elif n==2:
            return 2
        else:
            return self.climbStairs(n-1)+self.climbStairs(n-2)
        # 以上是没有采用记忆化技术的实现,在n=18时,就已经超过代码运行时间限制。
        
        save_dic = {1:1,2:2}
        def save_sta(n):
            if n in save_dic:
                return save_dic[n]
            else:
                s = save_sta(n-1)+save_sta(n-2)
                save_dic[n]=s
                return s
        return save_sta(n)
        # 采用记忆化技术后,可以通过全部测试样例。
        
        def pos_des(i,n):
            if i>n:
                return 0
            elif i==n:
                return 1
            else:
                return pos_des(i+1,n) + pos_des(i+2,n)
        return pos_des(0,n)
        # 最后这种是暴力法,没有通过全部测试用例。
        # pos_des中,i代表了当前位置,n代表了目标位置。
        # 当前位置可以走一个台阶或者两个台阶 是一开始都会想到,但是无法很好实现。

递归的复杂度分析

二叉树最大深度

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        
        # recursion
        if not root:
            return 0
        else:
            if root.left is not None and root.right is not None:
                depth = max(self.maxDepth(root.right),self.maxDepth(root.left)) + 1
            elif root.left is None and root.right is not None:
                depth = self.maxDepth(root.right) + 1
            elif root.left is not None and root.right is None:
                depth = self.maxDepth(root.left) + 1
            #elif root.left is None and root.right is None:
            else:
                depth = 1
        return depth
        
        #  iteration
        depth_root = []
        if root is not None:
            depth_root.append((1,root))
        depth = 0
        while depth_root != []:
            current_depth,root = depth_root.pop()
            if root is not None:
                depth = max(depth,current_depth)
                depth_root.append((current_depth+1,root.left))
                depth_root.append((current_depth+1,root.right))
        return depth           

Pow(x, n)

实现 pow(x, n) ,即计算 x 的 n 次幂函数。

class Solution(object):
    def myPow(self, x, n):
        """
        :type x: float
        :type n: int
        :rtype: float
        """
        # violence
        if x==1 or n==0:
            return 1
        if n<0:
            x = 1/x
            n = abs(n)
        return x*self.myPow(x, n-1)
        
        # square
        if x == 1 or n == 0:
            return 1.0
        
        if n<0:
            x = 1/x
            n = abs(n)
        
        if n % 2 == 1:
            return x*float(self.myPow(x, n/2)**2)
        else:
            return float(self.myPow(x, n/2)**2)

无脑递归的实现无法通过所以测试用例,会出现runtime error的。需要利用x^n = (x(n/2))2减少递归次数。

总结

合并两个有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        
        # recursion
        if l1 is None:
            return l2
        elif l2 is None:
            return l1
        
        if l1.val < l2.val:
            sub_list = self.mergeTwoLists(l1.next, l2)
            l1.next = sub_list
            return l1
        else:
            sub_list = self.mergeTwoLists(l1, l2.next)
            l2.next = sub_list
            return l2
        
        # iteration
        if l1 is None:
            return l2
        elif l2 is None:
            return l1
        
        if l1.val<l2.val:
            p = l1
            l1 = l1.next
        else:
            p = l2
            l2 = l2.next
        res = p
        while l1 is not None and l2 is not None:
            if l1.val<l2.val:
                p.next = l1
                l1 = l1.next
            else:
                p.next = l2
                l2 = l2.next
            p = p.next
        if l1 is None and l2 is not None:
            p.next = l2
        elif l1 is not None and l2 is None:
            p.next = l1
        return res

第K个语法符号

在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为01,1替换为10。
给定行数 N 和序数 K,返回第 N 行中第 K个字符。(K从1开始)

class Solution(object):
    def kthGrammar(self, N, K):
        """
        :type N: int
        :type K: int
        :rtype: int
        """
        # recursion
        if N==1:
            return 0
        elif N==2 and K==1:
            return 0
        elif N==2 and K==2:
            return 1
        sub_res = self.kthGrammar(N-1, K/2) if K % 2 == 0 else self.kthGrammar(N-1, (K+1)/2)
        # 0-->01 1-->10
        res = 1 if (sub_res==0 and K%2==0) or (sub_res==1 and K%2==1) else 0
        return res
        
        # memorize
        dic_n_k = {11:0,12:0,21:0,22:1}
        def sub_kthGrammar(n,k):
            if 10*n+k in dic_n_k:
                return dic_n_k[10*n+k]
            else:
                sub_res = sub_kthGrammar(n-1, k/2) if k % 2 == 0 else sub_kthGrammar(n-1, (k+1)/2)
                if k % 2 == 0:
                    dic_n_k [10*(n-1)+(k/2)] = sub_res
                else:
                     dic_n_k [10*(n-1)+((k+1)/2)] = sub_res
            res = 1 if (sub_res==0 and k%2==0) or (sub_res==1 and k%2==1) else 0
            return res
        return sub_kthGrammar(N,K)

原始递归方法耗时24ms完成全部测试用例,记忆化技术方法耗时16ms.

动态规划练习

最小路径和

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        row = len(grid)
        col = len(grid[0])  
        res = [[0]*col]*row
        for r in range(row):
            for c in range(col):
                if r==0 and c==0:
                    res[r][c] = grid[r][c]
                elif r==0 and c>0:
                    res[r][c] = res[r][c-1] + grid[r][c]
                elif r>0 and c==0:
                    res[r][c] = res[r-1][c] + grid[r][c]
                else:
                    res[r][c] = min(res[r-1][c],res[r][c-1]) + grid[r][c]
        return res[-1][-1]

和之前的不同路径题目思路类似

解码方法

一条包含字母 A-Z 的消息通过以下方式进行了编码:

‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26

给定一个只包含数字的非空字符串,请计算解码方法的总数。

class Solution:
    def numDecodings(self, s: str) -> int:
        dic = {'1': 'A', '2': 'B', '3': 'C', '4': 'D', '5': 'E', '6': 'F', '7': 'G', '8': 'H', '9': 'I', \
        '10': 'J','11': 'K', '12': 'L', '13': 'M', '14': 'N', '15': 'O', '16': 'P', '17': 'Q', '18': 'R', \
        '19': 'S', '20': 'T', '21': 'U', '22': 'V', '23': 'W', '24': 'X', '25': 'Y', '26': 'Z'}
        if len(s)==0 or s[0] == '0':
            return 0
        elif len(s) == 1:
            return 1
        elif len(s) == 2:
            if s in dic:
                if '0' in s:
                    return 1
                else:
                    return 2
            else:
                if '0' in s:
                    return 0
                else:
                    return 1
        else:
            tmp = [1,1]
            # -1 0
            for i in range(1,len(s)):
                if s[i] == '0':
                    if s[i-1] in ['1','2']:
                        tmp.append(tmp[-2])
                    else:
                        return 0
                elif s[i-1] == '1':
                    tmp.append(tmp[-2] + tmp[-1])
                elif s[i-1] == '2' and s[i] in ['1','2','3','4','5','6']:
                    tmp.append(tmp[-2] + tmp[-1])
                else:
                    tmp.append(tmp[-1])
            return tmp[-1]

花费很长时间的一道题目,对于状态转移方程建立有误

不同的二叉搜索树

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
leetcode-刷题记录_第1张图片

class Solution:
    def numTrees(self, n: int) -> int:
        if n == 0:
            return 0
        elif n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            dic = {
                0:1,
                1:1,
                2:2
                }
            res = 0
            for i in range(n):
                if i in dic:
                    left = dic[i]
                else:
                    left = self.numTrees(i)
                    dic[i] = left
                if n-1-i in dic:
                    right = dic[n-1-i]
                else:
                    right = self.numTrees(n-1-i)
                    dic[n-1-i] = right
                res += left*right
            dic[n] = res
            return res

不同的二叉搜索树 II

给定一个整数 n,生成所有由 1 … n 为节点所组成的二叉搜索树。
示例:

输入: 3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None


class Solution:
    def generatelist(self,list_n:List[int]) -> List[TreeNode]:
        if  len(list_n) == 1:
            return [TreeNode(list_n[0])]
        else:
            res = []
            for r in self.generatelist(list_n[1:]):
                tmp_tree = TreeNode(list_n[0])
                tmp_tree.right = r
                res.append(tmp_tree)
            
            for i in range(1,len(list_n)-1):
                left = self.generatelist(list_n[:i])
                right = self.generatelist(list_n[i+1:])
                for l in left:
                    for r in right:
                        tmp_tree = TreeNode(list_n[i])
                        tmp_tree.left = l
                        tmp_tree.right = r
                        res.append(tmp_tree)
            
            for l in self.generatelist(list_n[:-1]):
                tmp_tree = TreeNode(list_n[-1])
                tmp_tree.left = l
                res.append(tmp_tree)    
            
            print(list_n,res)
            return res

    def generateTrees(self, n: int) -> List[TreeNode]:
        if n==0:
            return []
        if n==1:
            return [TreeNode(1)]
        else:
            x = list(range(1,1+n))
            return self.generatelist(x)

通过,但是效率不高,分析是因为top-to-bottom计算的,最好的方法是使用bottm-to-up。

三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        if len(triangle) == 0:
            return 0
        elif len(triangle) == 1:
            return triangle[0][0]
        else:
            tmp = [triangle[0][0]+triangle[1][0],triangle[0][0]+triangle[1][1]]
            for i in triangle[2:]:
                tmp1=[i[0]+tmp[0]]
                for j in range(1,len(i)-1):
                    tmp1.append(i[j]+min(tmp[j-1:j+1]))
                tmp1.append(i[-1]+tmp[-1])
                tmp = tmp1
            return min(tmp)

单词拆分

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        if wordDict == []:
            return False
        if s in wordDict or s == '':
            return True
        else:
            for word in wordDict:
                if word in s:
                    tmp = s.split(word)
                    flag = 0
                    for ii in tmp:
                        if not self.wordBreak(ii,wordDict):
                            flag = 1
                            break 
                    if not flag:
                        return True
            return False

乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字)。

示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        res = -float('inf')
        i_max = 1
        i_min = 1
        for i in nums:
            if i >= 0:
                i_max = max(i_max*i,i)
                i_min = min(i_min*i,i)
            else:
                i_max,i_min = i_min, i_max
                i_max = max(i_max*i,i)
                i_min = min(i_min*i,i)
            res = max(i_max,res)
        return res

打家劫舍 II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

class Solution:
    def be_the_richest(self, nums: List[int]):
        if nums == []:
            return 0
        elif len(nums)<=2:
            return max(nums)
        else:
            res = [0]*(len(nums)-2)
            res.append(max(nums[-2:]))
            res.append(nums[-1])
            #print(res)
            #print(nums)
            for i in range(len(nums)-3,-1,-1):
                res[i] = max(nums[i]+res[i+2],res[i+1])
            return res[0]

    def rob(self, nums: List[int]) -> int:
        if len(nums)==0:
            return 0
        elif 0 < len(nums) <= 3:
            return max(nums)
        else:
            return max(self.be_the_richest(nums[2:-1])+nums[0],self.be_the_richest(nums[1:]))

最佳买卖股票时机含冷冻期

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if prices == []:
            return 0
        income = []
        # 0 there is no stack kept
        # 1 there is stack kept
        income.append([0,-prices[0]])
        for i in range(1,len(prices)):
            tmp = prices[i]
            tmp0 = max(income[-1][0],income[-1][1]+tmp)
            # there is no stack kept after i-th day
            tmp1 = max(income[-2][0]-tmp,income[-1][1]) if i > 1 else max(0-tmp,income[-1][1])
            # there is stack kept after i-th day
            income.append([tmp0,tmp1])
        return income[-1][0]

重点是当前是否持有股票,以及买卖股票操作,以及无操作造成的股票持有情况的变化。
leetcode-刷题记录_第2张图片

比特位计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]

class Solution:
    def countBits(self, num: int) -> List[int]:
        # f(2x) = f(x)
        # f(2x+1) = f(x) + 1
        res = [0]
        for i in range(1,num+1):
            if i%2 == 0:
                res.append(res[int(i/2)])
            else:
                res.append(res[int(i/2)]+1)
        return res

整数拆分

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例 1:=
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

class Solution:
    def integerBreak(self, n: int) -> int:
        res=[0]*(n+1)
        res[1] = 1
        for i in range(1,n+1):
            for j in range(i+1,n+1):
                res[j] = max(res[j],(j-i)*i,(j-i)*res[i])
        return res[-1]

计算各个位数不同的数字个数

给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10n 。

示例:
输入: 2
输出: 91
解释: 答案应为除去 11,22,33,44,55,66,77,88,99 外,在 [0,100) 区间内的所有数字。

class Solution:
    def c_m_n(self, m: int, n: int) -> int:
        # Cmn m!/n!
        res = 1
        for i in range(m,m-n,-1):
            res = res*i
        return res

    def countNumbersWithUniqueDigits(self, n: int) -> int:
        if n == 0:
            return 1
        else:
            tmp = 1
            for i in range(1,n+1):
                tmp = self.c_m_n(9,i) + (i-1)*self.c_m_n(9,i-1) + tmp
            return tmp

最长回文子序列

给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。

示例 1:
输入:
“bbbab”
输出:
4
一个可能的最长回文子序列为 “bbbb”。
示例 2:
输入:
“cbbd”
输出:
2
一个可能的最长回文子序列为 “bb”。

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        res_dic = {}
        # key:str(start+end) 
        for st in range(len(s)-1,-1,-1):
            res_dic[str(st)+str(st)] = 1
            for e in range(st+1,len(s)):
                if s[st] == s[e]:
                    try:
                        res_dic[str(st)+str(e)] = res_dic[str(st+1)+str(e-1)] + 2
                    except:
                        res_dic[str(st)+str(e)] = 2
                else:
                    res_dic[str(st)+str(e)] = max(res_dic[str(st+1)+str(e)] , res_dic[str(st)+str(e-1)])
            #print(res_dic)
        return res_dic[str(0)+str(len(s)-1)]

回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

示例 1:
输入: “abc”
输出: 3
解释: 三个回文子串: “a”, “b”, “c”.
示例 2:
输入: “aaa”
输出: 6
解释: 6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”

class Solution:
    def countSubstrings(self, s: str) -> int:
        if len(s) <= 1:
            return 1
        else:
            res = 0
            for i in range(len(s)):
                tmp1 = s[i:]
                tmp2 = tmp1[::-1]
                res += (tmp1 == tmp2)
            # 添加一个字符后,新产生的回文串,只能是以添加字符为结尾的回文串
            return res+self.countSubstrings(s[:-1])

等差数列划分

如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。

例如,以下数列为等差数列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下数列不是等差数列。
1, 1, 2, 5, 7

数组 A 包含 N 个数,且索引从0开始。数组 A 的一个子数组划分为数组 (P, Q),P 与 Q 是整数且满足 0<=P 如果满足以下条件,则称子数组(P, Q)为等差数组:
元素 A[P], A[p + 1], …, A[Q - 1], A[Q] 是等差的。并且 P + 1 < Q 。
函数要返回数组 A 中所有为等差数组的子数组个数。

示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三个子等差数组: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。

class Solution:
    def numberOfArithmeticSlices(self, A: List[int]) -> int:
        #增加一位数后,增加的只有以增加数为结尾的等差数列个数
        if len(A)<3:
            return 0
        elif len(A)==3:
            if A[0]-A[1]==A[1]-A[2]:
                return 1
            else:
                return 0
        if self.numberOfArithmeticSlices(A[-3:])==1:
            res = 1
            end_id = -1
            start_id = -4
            while start_id>=-len(A) and self.numberOfArithmeticSlices(A[start_id:end_id]):
                res+=1
                start_id -= 1
                end_id -= 1
            return res+self.numberOfArithmeticSlices(A[:-1])
        else:
            return self.numberOfArithmeticSlices(A[:-1])

简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

示例 1:
输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例 2:
输入:"/…/"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
示例 3:
输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:
输入:"/a/./b/…/…/c/"
输出:"/c"
示例 5:
输入:"/a/…/…/b/…/c//.//"
输出:"/c"
示例 6:
输入:"/a//b////c/d//././/…"
输出:"/a/b/c"

class Solution:
    def simplifyPath(self, path: str) -> str:
        ps = path.split('/')[1:]
        res = []
        for i in ps:
            if i=='..':
                res = res[:-1]
            elif i=='' or i=='.':
                continue
            else:
                res.append(i)
        res = '/'+'/'.join(res)
        return res

你可能感兴趣的:(算法基础)