1.两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
试例
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
res = []
for i in range(len(nums)):
another_num = target - nums[i]
if another_num in nums[i+1:]:
res.append(i)
res.append(nums[i+1:].index(another_num)+i)
break
return res
def twoSum(nums, target):
lens = len(nums)
j=-1
for i in range(1,lens):
temp = nums[:i]
if (target - nums[i]) in temp:
j = temp.index(target - nums[i])
break
if j>=0:
return [j,i]
2.两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
两个列表同时遍历,逐位相加,保留进位 。carry保存的是进位。
# 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:
re = ListNode(0)
r = re
carry = 0
while l1 or l2:
x = l1.val if l1 else 0
y = l2.val if l2 else 0
sum = x + y + carry
carry = sum // 10
r.next = ListNode(sum % 10)
r = r.next
if l1 != None: l1 = l1.next
if l2 != None: l2 = l2.next
#当l1和l2都走到了最后,假如是5+5,那么还得需要一个ListNode(1)
if carry > 0:
r.next = ListNode(1)
return re.next
# 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:
prenode = ListNode(0)
lastnode = prenode
val = 0
while val or l1 or l2:
val, cur = divmod(val + (l1.val if l1 else 0) + (l2.val if l2 else 0), 10)
lastnode.next = ListNode(cur)
lastnode = lastnode.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
return prenode.next
def generateList(l: list) -> ListNode:
prenode = ListNode(0)
lastnode = prenode
for val in l:
lastnode.next = ListNode(val)
lastnode = lastnode.next
return prenode.next
def printList(l: ListNode):
while l:
print("%d, " %(l.val), end = '')
l = l.next
print('')
if __name__ == "__main__":
l1 = generateList([1, 5, 8])
l2 = generateList([9, 1, 2, 9])
printList(l1)
printList(l2)
s = Solution()
sum = s.addTwoNumbers(l1, l2)
printList(sum)
prenode是记录链表最初的节点,记录了最初的节点就相当于记录这个链表。
3.无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
遍历字符串,当前字符与前面的字符串相比较,看有没有重复的,如果没有重复的话就最大字符串+1。
index_dict记录了str[i]之前所有字符的位置
i-start+1表示子字符串的距离
start表示与上一个子字符串最后一个位置(例如:pwwkew,当i=2时候,因为两个ww,所以此时start的位置变成2,这样子算距离i-start+1才对)。start也可以解释为上一个重复字符的位置(后面那一个)
class Solution:
def lengthOfLongestSubstring(self, str):
"""
:type s: str
:rtype: int
"""
start = 0
index_dict = {}
max = 0
for i in range(len(str)):
if str[i] in index_dict and index_dict[str[i]] >= start:
start = index_dict[str[i]] + 1
index_dict[str[i]] = i
else:
index_dict[str[i]] = i
if i-start + 1 > max:
max = i-start + 1
print(index_dict)
return max
index_dict[str[i]] >= start 解决的是当例子为"tmmzuxt"时,遍历到最后一个t时,才是最长子串。
4.寻找两个正序数组的中位数
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的中位数。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
m = len(nums1)
n = len(nums2)
i, j = 0, 0
while j < n:
if i == m+j:
nums1[i+1:] = nums2[j:]
break
if nums1[i] > nums2[j]:
nums1.insert(i, nums2[j])
i += 1
j += 1
elif nums1[i] <= nums2[j]:
i += 1
if (m+n) % 2 == 0:
return float(nums1[int((m+n)/2)-1] + nums1[int((m+n)/2)])/2
else:
return nums1[int((m+n)/2)]
思路是对两个有序数组进行排序,保存在nums1里面,然后求中位数
5.最长回文子串
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
示例 3:
输入:s = "a"
输出:"a"
示例 4:
输入:s = "ac"
输出:"a"
注意:单个字符也是回文子串
令dp[j][i]从字符串j到i是否为回文串
动态回归方程 dp[j][i]是看j+1和i-1是否为回文串.
class Solution(object):
def longestPalindrome(self, s):
n = len(s)
dp = [[0] * n for _ in range(n)]
max_len = 0
res = ""
for i in range(n):
# dp[i][i] = 1
for j in range(i, -1, -1):
if s[i] == s[j] and (i - j < 2 or dp[i - 1][j + 1]):
dp[i][j] = 1
if dp[i][j] and i - j + 1 > max_len:
max_len = i - j + 1
res = s[j:i + 1]
# print(dp)
return res
7.整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321示例 2:
输入: -123
输出: -321示例 3:
输入: 120
输出: 21
class Solution:
def reverse(self, x: int) -> int:
flag = 1 if x >= 0 else -1
str_x = str(x)
if flag == -1:
str_x = str_x[1:][::-1]
res = int(str_x) * flag
else:
str_x = str_x[::-1]
res = int(str_x)
return res if -2**31 < res < 2**31-1 else 0
8.字符串转换为整数
#-*-coding:utf-8-*-
class Solution(object):
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
#去掉左边字符
str=str.lstrip()
#如果字符串空,返回
if len(str)==0:
return 0
#设置默认输出为0
last=0
#如果有符号设置起始位置2,其余的为1
i=2 if str[0]=='-'or str[0]=='+' else 1
#循环,直到无法强转成int,跳出循环
while i <= len(str):
try:
last=int(str[:i])
i+=1
except:
break
#如果数字超出范围,返回范围最大值
if last<-2147483648 :
return -2147483648
if last>2147483647:
return 2147483647
return last
10.正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
- '.' 匹配任意单个字符
- '*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1:
输入:s = "aa" p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa" p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
11.盛最多水的容器
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
class Solution:
def maxArea(self, height: List[int]) -> int:
i, j = 0, len(height)-1
res = 0
while i < j:
if height[i] < height[j]:
area = height[i] * (j -i)
if res < area:
res = area
i += 1
else:
area = height[j] * (j -i)
if res < area:
res = area
j -= 1
return res
解析:使用的是双指针发。https://www.bilibili.com/video/BV1S54y1v7Zr?from=search&seid=14140394072019839006
14.最长公共前缀
输入: ["flower","flow","flight"] 输出: "fl"
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if strs == []: # 字符串为空返回''
return ''
elif len(strs) == 1: # 若列表仅有一个单词,返回该单词
return strs[0]
else:
minlen = len(min(strs, key=len)) # 找到最短的单词长度
s = ''
for i in range(1, minlen + 1): # 最多遍历 minlen 次
# 每次遍历同时从每个单词取相同长度的前缀加入集合,集合中不会有重复单词
# 列表中每个单词的相同长度前缀相同,因此集合长度为1
if len({s[:i] for s in strs}) == 1:
# 将s值更新为当前s长度与任意一个单词[:i]的部分中较大的那个值
# 为了避免不存在strs[1],此处默认为第一个
s = max(s, strs[0][:i])
return s
15.三数之和
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(n):
for j in range(i+1, n):
left = 0 - nums[i] - nums[j]
r = []
if left in nums[j+1:]:
r.extend([nums[i], nums[j], left])
if r not in res:
res.append(r)
return res
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
'''
算法思路:最外层控制一个元素的循环,
内层用双指针,一个从头到尾扫描,另一个从尾到头扫描,判断三个元素的值之和是否为零
注意:相同的元素需要跳过
'''
# 对列表进行排序
nums.sort()
res, k = [], 0
for k in range(len(nums) - 2):
# 如果出现最小元素为正数,则不存在和为0的情况,直接返回
if nums[k] > 0:
break
# 如果出现第一个元素重复的情况,为避免重复结果,跳过后续执行
if k > 0 and nums[k] == nums[k - 1]:
continue
# 定义接下来的两个元素的双指针
i, j = k + 1, len(nums) - 1
while i < j:
s = nums[k] + nums[i] + nums[j]
if s < 0:
i += 1
# 跳过重复元素
while i < j and nums[i] == nums[i - 1]:
i += 1
elif s > 0:
j -= 1
# 跳过重复元素
while i < j and nums[j] == nums[j + 1]:
j -= 1
else:
# 当出现元素满足条件是,将结果加入到列表
res.append([nums[k], nums[i], nums[j]])
# 接着更新索引(注意跳过相同元素)
i += 1
j -= 1
while i < j and nums[i] == nums[i - 1]:
i += 1
while i < j and nums[j] == nums[j + 1]:
j -= 1
return res
解析:利用排序避免重复答案
19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
res = ListNode(0, head) #避免head链表只有一个的时候,temp.next.next不存在
len = self.lenthListNode(head)
temp = res
for i in range(len - n):
temp = temp.next
temp.next = temp.next.next
return res.next
def lenthListNode(self, head):
len = 0
while head:
len += 1
head = head.next
return len
if __name__ == "__main__":
nums = [1,2,3,4,5]
head = ListNode(nums[0])
p = head
for i in range(1, len(nums)):
p.next = ListNode(nums[i])
p = p.next
# while head:
# print("listnode.val", head.val)
# head = head.next
res = Solution().removeNthFromEnd(head, 2)
while res:
print("res.val:\t", res.val)
res = res.next
进阶:你能尝试使用一趟扫描实现吗?
#-*-coding:utf-8-*-
def FindKthToTail(self, head, k):
if not head:
return None
pFast = head
pSlow = head
for i in range(k - 1):
if pFast.next:
pFast = pFast.next
else:
return None
while pFast.next:
pFast = pFast.next
pSlow = pSlow.next
return pSlow
21.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
# res = ListNode(0)
res = ListNode(0)
p = res
while l1 and l2:
if l1.val < l2.val:
p.next = ListNode(l1.val)
l1 = l1.next
p = p.next
else:
p.next = ListNode(l2.val)
l2 = l2.next
p = p.next
while l1:
p.next = ListNode(l1.val)
l1 = l1.next
p = p.next
while l2:
p.next = ListNode(l2.val)
l2 = l2.next
p = p.next
return res.next
if __name__ == "__main__":
nums1 = [1,2,4]
head1 = ListNode(nums1[0])
p1 = head1
for i in range(1, len(nums1)):
p1.next = ListNode(nums1[i])
p1 = p1.next
nums2 = [1,3,4]
head2 = ListNode(nums2[0])
p2 = head2
for i in range(1, len(nums2)):
p2.next = ListNode(nums2[i])
p2 = p2.next
res = Solution().mergeTwoLists(head1, head2)
while res:
print("res.val\t", res.val)
res = res.next
27. 移除元素
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
i = 0
for j in range(len(nums)):
if nums[j] != val:
nums[i] = nums[j]
i += 1
return i
28、实现 strStr()
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
输入: haystack = "hello", needle = "ll" 输出: 2
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
n = len(haystack)
m = len(needle)
res = -1
for i in range(n-m+1):
if haystack[i:i+m] == needle:
res =i
break
return res
31. 下一个排列
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
提示:数组的全排列中已知全排列中的一个排列,实现这个排列的下一个排列的函数。
class Solution:
def nextPermutation(self, nums):
"""
Do not return anything, modify nums in-place instead.
"""
length = len(nums)
i = length - 1
while i > 0:
if nums[i-1] < nums[i]:
start = i
while start < length and nums[i] > nums[start]:
i += 1
i -= 1
nums[i], nums[start] = nums[start], nums[i]
nums[start:] = nums[:start-1:-1]
return nums
i -= 1
return nums[::-1]
if __name__ == "__main__":
# nums = [1, 2, 4, 7, 6, 5, 1]
# nums = [7, 6, 4, 5, 3, 2, 1]
# nums = [1,2,3]
# nums = [3,2,1]
nums = [1, 3, 4, 2]
res = Solution().nextPermutation(nums)
print(res)
这个代码一直不能ac不知道为什么
33、搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的索引,否则返回 -1 。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
34.在排序数组中查找元素的第一个和最后一个位置
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
class Solution:
def searchRange(self, nums, target: int):
res = [-1, -1]
i = 0
len_nums = len(nums) - 1
while i <= len_nums:
if nums[i] == target:
start = stop = i
res[0], res[1] = start, stop
while stop+1 <= len_nums and nums[stop+1] == target:
stop += 1
res[1] = stop
break
i += 1
return res
if __name__ == "__main__":
# nums = [5,7,7,8,8]
nums = [1]
target = 1
res = Solution().searchRange(nums, target)
print(res)
38. 报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被读作 "one 1" ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
class Solution:
def combinationSum(self, candidates, target):
def backtrack(candidates, target, path, sum, startIndex):
if sum == target:
res.append(path)
return
elif sum > target:
return
for i in range(startIndex, len(candidates)):
sum += candidates[i]
backtrack(candidates, target, path+[candidates[i]], sum, i)
sum -= candidates[i]
res = []
backtrack(candidates, target, [], 0, 0)
return res
class Solution:
def combinationSum(self, candidates, target):
def backtrack(candidates, target, path, sum, startIndex):
if sum == target:
res.append(path)
return
elif sum > target:
return
else:
for i in range(startIndex, len(candidates)):
backtrack(candidates, target, path+[candidates[i]],sum+candidates[i], i)
res = []
backtrack(candidates, target, [], 0, 0)
return res
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
#-*-coding:utf-8-*-
#暴力解法
def tracp(array):
res = 0
for i in range(len(array)):
l_max = max(array[0:i+1])
r_max = max(array[i:])
res += min(l_max, r_max) - array[i]
return res
#双指针解法
def tracp1(array):
res = 0
left = 0;right = len(array)-1
l_max = array[0];r_max = array[-1]
while left <= right:
l_max = max(l_max, array[left])
r_max = max(r_max, array[right])
if l_max <= r_max:
res += l_max - array[left]
left += 1
else:
res += r_max - array[right]
right -= 1
return res
array = [0,1,0,2,1,0,1,3,2,1,2,1]
res = tracp1(array)
print(res)
46.全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def backtrack(nums, tmp):
if not nums:
res.append(tmp)
return
for i in range(len(nums)):
backtrack(nums[:i] + nums[i+1:], tmp + [nums[i]])
backtrack(nums, [])
return res
48. 旋转图像
给定一个 n × n 的二维矩阵表示一个图像。
将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
# -*-coding:utf-8-*-
class Solution:
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: void Do not return anything, modify matrix in-place instead.
"""
n = len(matrix[0])
# transpose matrix
for i in range(n):
for j in range(i, n):
matrix[j][i], matrix[i][j] = matrix[i][j], matrix[j][i]
# reverse each row
for i in range(n):
matrix[i].reverse()
return matrix
53.最大子序列
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [0]
输出:0
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
dp = nums[:]
for i in range(1, n):
dp[i] = max(dp[i-1] + nums[i], nums[i])
return max(dp)
dp[i]表示以nums[i]结尾的最大子序和,最大子序和有两种可能,1)自己本身nums[i],2)dp[i]+nums[i]
class Solution:
def canJump(self, nums):
n = len(nums)
if n <= 1:
return True
cur = 0
for i in range(n):
if cur < i:
return False
cur = max(i+ nums[i], cur)
if cur >= n-1:
break
return True
if __name__ == "__main__":
nums = [2,3,1,1,4]
res = Solution().canJump(nums)
print(res)
62.不同路径
个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
输入:m = 3, n = 7
输出:28
class Solution:
def uniquePaths(self, m, n):
dp = [[ 0 for _ in range(n)] for _ in range(m)]
for i in range(m):
for j in range(n):
if i == 0 or j == 0:
dp[i][j] = 1
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
if __name__ == "__main__":
m = 3
n = 7
res = Solution().uniquePaths(m,n)
print(res)
64. 最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
class Solution:
def minPathSum(self, grid):
if not grid:
return
m = len(grid)
n = len(grid[0])
for i in range(m):
for j in range(n):
if i == 0 and j == 0:
continue
elif i == 0: grid[i][j] = grid[i][j-1] + grid[i][j]
elif j == 0: grid[i][j] = grid[i-1][j] + grid[i][j]
else:
grid[i][j] = min(grid[i-1][j], grid[i][j-1]) + grid[i][j]
return grid[-1][-1]
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
if not grid:
return
m = len(grid)
n = len(grid[0])
dp = [[0]*n for i in range(m)]
for i in range(m):
for j in range(n):
if i == 0 and j == 0:
dp[0][0] = grid[0][0]
elif i == 0:
dp[i][j] = dp[i][j-1] + grid[i][j]
elif j == 0:
dp[i][j] = dp[i-1][j] + grid[i][j]
else:
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
return dp[m-1][n-1]
55.跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
输入: [2,3,1,1,4] 输出: true 解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
class Solution:
def canJump(self, nums):
n = len(nums)
if n <= 1:
return True
cur = 0
for i in range(n):
if cur < i:
return False
cur = max(i+ nums[i], cur)
if cur >= n-1:
break
return True
if __name__ == "__main__":
nums = [2,3,1,1,4]
res = Solution().canJump(nums)
print(res)
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
class Solution:
def climbStairs(self, n: int) -> int:
res = [1,2]
for i in range(2, n):
res.append(res[i-2] + res[i-1])
return res[n-1]
class Solution:
def climbStairs(self, n):
dp = [0 for i in range(n)]
dp[0] = 1
dp[1] = 2
for i in range(2,n):
dp [i] = dp[i-1] + dp[i-2]
return dp[-1]
if __name__ == "__main__":
n = 3
res = Solution().climbStairs(n)
print(res)
75.颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
class Solution:
def sortColors(self, nums):
"""
Do not return anything, modify nums in-place instead.
"""
left = 0
right = len(nums) - 1
i = 0
while i <= right:
if nums[i] == 0:
nums[i], nums[left] = nums[left], nums[i]
i += 1
left += 1
elif nums[i] == 2:
nums[i], nums[right] = nums[right], nums[i]
right -= 1
else:
i += 1
return nums
if __name__ == "__main__":
nums = [2,0,2,1,1,0]
res = Solution().sortColors(nums)
print(res)
78.子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
class Solution:
def subsets(self, nums):
def backtrack(nums, path, startIndex):
if startIndex == len(nums):
return
for i in range(startIndex, len(nums)):
res.append(path+[nums[i]])
backtrack(nums, path+[nums[i]], i+1)
res = [[]]
backtrack(nums, [], 0)
return res
解决方法:回溯法
79.单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
94.二叉树的中序遍历
1.中序遍历
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def inorderTraversal(self, root):
res = []
def travel(root):
if root == None:
return
travel(root.left)
res.append(root.val)
travel(root.right)
travel(root)
return res
if __name__ == "__main__":
nodeA = TreeNode('A')
nodeB = TreeNode('B')
nodeC = TreeNode('C')
nodeD = TreeNode('D')
nodeE = TreeNode('E')
nodeF = TreeNode('F')
nodeG = TreeNode('G')
nodeA.left = nodeB
nodeA.right = nodeC
nodeB.left = nodeD
nodeB.right = nodeE
nodeC.left = nodeF
nodeC.right = nodeG
res = Solution().inorderTraversal(nodeA)
print(res)
前序遍历
class Solution:
def inorderTraversal(self, root):
res = []
def travel(root):
if root == None:
return
res.append(root.val)
travel(root.left)
travel(root.right)
travel(root)
return res
后序遍历
class Solution:
def inorderTraversal(self, root):
res = []
def travel(root):
if root == None:
return
travel(root.left)
travel(root.right)
res.append(root.val)
travel(root)
return res
96.不同的二插搜索树
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
class Solution:
def numTrees(self, n):
res = [0]*(n+1)
res[0] = 1
res[1] = 1
for i in range(2, n+1):
for j in range(1, i+1):
res[i] += res[j-1]*res[i-j]
return res[-1]
# https://www.bilibili.com/video/BV1Fk4y1m7KJ?from=search&seid=18214715255875086207
if __name__ == "__main__":
n = 3
res = Solution().numTrees(n)
print(res)
102.二叉树的层序遍历示例:
二叉树:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def levelOrder(self, root):
# 先处理特殊情况
if not root:
return []
# 返回结果
res = []
from collections import deque #双端队列
# 定义队列
queue = deque()
# 将根节点入队
queue.append(root)
# 队列不为空,表达式二叉树还有节点,循环遍历
while queue:
# 先标记每层的节点数
size = len(queue)
# 定义变量,记录每层节点值
level = []
# 这里开始遍历当前层的节点
for _ in range(size):
# 出队
node = queue.popleft()
# 先将当前节点的值存储
level.append(node.val)
# 节点的左右节点非空时,入队
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
# 添加每层的节点值列表
res.append(level)
return res
if __name__ == "__main__":
nodeA = TreeNode('A')
nodeB = TreeNode('B')
nodeC = TreeNode('C')
nodeD = TreeNode('D')
nodeE = TreeNode('E')
nodeF = TreeNode('F')
nodeG = TreeNode('G')
nodeA.left = nodeB
nodeA.right = nodeC
nodeB.left = nodeD
nodeB.right = nodeE
nodeC.left = nodeF
nodeC.right = nodeG
res = Solution().levelOrder(nodeA)
print(res)
103.二叉树的最大深度
141.环形链表
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出: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 not head or not head.next:
return False
slow = head
fast = head.next
while slow != fast:
if not fast or not fast.next:
return False
slow = slow.next
fast = fast.next.next
return True
class Solution:
def hasCycle(self, head) -> bool:
save = set()
while head:
if head in save:
return True
save.add(head)
head = head.next
return False
用集合不用列表是因为 判断元素在不在里面集合的效率比列表快得多
142.环形链表2
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
save = []
while head:
if head in save:
return head
save.append(head)
head = head.next
return None
148 排序链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def sortList(self, head: ListNode) -> ListNode:
save = []
while head is not None:
save.append(head.val)
head = head.next
save.sort()
phead = ListNode(-1)
cur = phead
for i in save:
cur.next = ListNode(i)
cur = cur.next
return phead.next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if head == None or head.next == None:
return head
slow, fast = head, head #快慢指针技巧的运用,用来截断链表。
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
left = head
right = slow.next
slow.next = None
return self.merge(self.sortList(left), self.sortList(right))
def merge(self, head1, head2):
if head1 == None: return head2
if head2 == None: return head1
prehead = ListNode(0)
temp = prehead
while head1 and head2:
if head1.val <= head2.val:
temp.next = head1
head1 = head1.next
temp = temp.next
else:
temp.next = head2
head2 = head2.next
temp = temp.next
if head1 == None:
temp.next = head2
if head2 == None:
temp.next = head1
return prehead.next
注释:归并排序的思想
198.打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4
示例 2 nums = [2,1,1,2]
class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)
if n <= 2:
return max(nums)
dp = [0 for i in range(n)]
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, n):
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
return max(dp)
class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)
if n <= 2:
return max(nums)
dp = [0 for i in range(n)]
dp[0] = nums[0]
for i in range(1, n): #可以从1开始,是因为此时dp[-1]=0
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
return max(dp)
200.岛屿数量
给你一个由 '1'
(陆地)和 '0'
(水)组成的的二维网格,请你计算网格中岛屿的数量。
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
n = len(grid)
m = len(grid[0])
res = 0
for i in range(n):
for j in range(m):
if grid[i][j] == "1":
res += 1
self.dfs(grid, i, j, n, m)
return res
def dfs(self, grid, i, j, n, m):
if i >= n or j >= m or i < 0 or j < 0 or grid[i][j] != "1":
return
grid[i][j] = "-1"
self.dfs(grid, i+1, j, n, m)
self.dfs(grid, i-1, j, n, m)
self.dfs(grid, i, j+1, n, m)
self.dfs(grid, i, j-1, n, m)
206.反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
221.最大方形
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
m = len(matrix)
n = len(matrix[0])
res = 0
dp = [[0 for _ in range(n)] for _ in range(m)]
for i in range(m):
for j in range(n):
if matrix[i][j] == "1":
if i == 0 or j == 0:
dp[i][j] = int(matrix[i][j])
else:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
res = max(dp[i][j], res)
return res**2
234.回文链表
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
val = []
while head:
val.append(head.val)
head = head.next
#return val == val[::-1]
left = 0
right = len(val)-1
while left < right:
if val[left] == val[right]:
left += 1
right -= 1
else:
return False
return True
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
slow = head
fast = head
pre = head
prepre = None
while fast and fast.next:
#pre记录反转的前半个列表,slow一直是原表一步步走
pre = slow
slow = slow.next
fast = fast.next.next
pre.next = prepre
prepre = pre
if fast:#长度是奇数还是偶数对应不同情况
slow = slow.next
while slow and pre:
if slow.val != pre.val:
return False
slow = slow.next
pre = pre.next
return True