给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 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
给定一个数组,它的第 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]
给定两个数组,编写一个函数来计算它们的交集。
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 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 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() 函数。
给定一个 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
没有完成
给定一个二叉搜索树,编写一个函数 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 高的元素。
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 个不同的元素。
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
这道题应该是用二分查找做的,这里做的不对。
没有完成
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
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]
一个机器人位于一个 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]
给定一个无序的整数数组,找到其中最长上升子序列的长度。
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
给定一个非负索引 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) ,即计算 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
在第一行我们写上一个 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 为节点组成的二叉搜索树有多少种?
示例:
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
给定一个整数 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
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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]
重点是当前是否持有股票,以及买卖股票操作,以及无操作造成的股票持有情况的变化。
给定一个非负整数 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