1. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 暴力法查找(6080s)时间复杂度在 O(n2)
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i]+ nums[j] == target:
return [i, j]
# 做差,利用list.index方法
if len(nums) == 2:
return [0, 1]
else:
for i in range(len(nums)):
tmp = target - nums[i]
if tmp in nums[i+1:]:
return [i, nums.index(tmp, i+1)]
# 用字典模拟哈希求解,利用内置函数(36s)
# 标签:哈希映射
# 由于哈希查找的时间复杂度为 O(1),所以可以利用哈希容器 map 降低时间复杂度
# 遍历数组 nums,i 为当前下标,每个值都判断map中是否存在 target-nums[i] 的 key 值
# 如果存在则找到了两个值,如果不存在则将当前的 (nums[i],i) 存入 map 中,继续遍历直到找到为止
# 如果最终都没有结果则抛出异常
# 时间复杂度:O(n)
# enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据下标和数据
hashmap = {}
for i, num in enumerate(nums):
if target - num in hashmap:
return [hashmap[target - num], i]
hashmap[num] = i
67. 二进制求和
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1
和 0
。
class Solution:
def addBinary(self, a: str, b: str) -> str:
# # 方法一:转为整数计算再转为2进制
num_int = int(a,2)+int(b,2)
return bin(num_int)[2:]
# 方法二:二进制计算
# 定义两个指针,分别指向两个字符串的末尾
i, j = len(a)-1, len(b)-1
# 定义一个进位和储存结果变量
carry, res = 0, ""
while i>=0 or j >=0:
if i>=0:
carry += int(a[i])
i -= 1
if j>=0:
carry += int(b[j])
j -= 1
res = str(carry%2) + res
carry //= 2
# 如果最后carry为1循环终止,则在结果前面补加一个“1”
if carry == 1:return "1"+res
return res
2. 两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 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:
# 自己写的
i, j = l1, l2
num_1, num_2 = str(l1.val), str(l2.val)
while l1.next:
num_1 = str(l1.next.val)+num_1
l1 = l1.next
while l2.next:
num_2 = str(l2.next.val)+num_2
l2 = l2.next
num = str(int(num_1) + int(num_2)) # num=807
# 转字符串结果为链表
prenode = ListNode(int(num[-1]))
if len(num) == 1: return prenode
lastnode = prenode
for i in num[len(num)-2::-1]:
lastnode.next = ListNode(int(i))
lastnode = lastnode.next
return prenode
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if len(num1) < len(num2):
num1, num2 = num2, num1 #使num1的长度大于num2,减少遍历次数
s, j = 0, len(num2)-1
carry, res = 0, 0
while j >= 0:
for i in range(len(num1)):
carry += int(num1[::-1][i]+"0"*i) * int(num2[j])
j -= 1
carry = int(str(carry) + "0"*s)
res, carry = res + carry, 0
s += 1
return str(res)
7. 整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
class Solution:
def reverse(self, x: int) -> int:
# [::-1]反转字符串
if x < 0:
x = -x
x = "-" + str(x)[::-1]
else:
x = str(x)[::-1]
x = int(x)
if x <= -2**31 or x >= 2**31-1:
return 0
else:
return x
9. 回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
class Solution:
def isPalindrome(self, x: int) -> bool:
# # 利用[::-1]
if x < 0:
return False
else:
return x == int(str(x)[::-1])
# 利用reverse()方法
# y = list(str(x))
# y.reverse()
# return list(str(x)) == y
11. 盛最多水的容器(Top100)
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
class Solution:
def maxArea(self, height: List[int]) -> int:
# 暴力法:
area = 0
for i in range(len(height)-1):
for j in range(len(height)):
area = max((j-i)*min(height[i], height[j]), area)
return area
# 双指针
i, j = 0, len(height)-1
area = 0
while i < j:
area = max((j-i)*min(height[i], height[j]), area)
if height[i]>height[j]:
j -= 1
else:
i += 1
return area
15. 三数之和(Top100)
给你一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
if len(nums) == 0:return []
if nums[-1] < 0:return []
if nums[0] > 0:return []
# 将target遍历一遍,看后面是否存在i和j相加为0,k为abc中最小值
k, tmp = 0, []
for k in range(len(nums)-2):
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:
tmp.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
elif 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
return tmp
20. 有效的括号
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串,判断字符串是否有效。
有效字符串需满足:
注意空字符串可被认为是有效字符串。
class Solution:
def isValid(self, s: str) -> bool:
# 方法一:栈
stack = [0]
dic={')':'(', '}':'{', ']':'['}
for i in s:
if i in ['(', '{', '[']:
stack.append(i)
elif i in [')', '}', ']']:
if dic[i] == stack.pop():
continue
else:
return False
if len(stack) != 1: return False
return True
# 方法二:消除
li = ["()", "{}", "[]"]
while li[0] in s or li[1] in s or li[2] in s:
import re
s_li = re.split("\(\)|\{\}|\[\]",s)
s = "".join(s_li)
if len(s) == 0:return True
return False
21. 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
# 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:
# 方法一:迭代遍历
i, j = l1, l2
prenode = ListNode(0)
lastnode = prenode
while i and j:
if i.val < j.val:
lastnode.next = ListNode(i.val)
lastnode, i = lastnode.next, i.next
else :
lastnode.next = ListNode(j.val)
lastnode, j = lastnode.next, j.next
if i != None:
lastnode.next = i
else:
lastnode.next = j
return prenode.next
# 方法二:递归
if l1 is None:return l2
if l2 is None:return l1
if l1.val <= l2.val:
l1.next=self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next=self.mergeTwoLists(l1, l2.next)
return l2
34. 在排序数组中查找元素的第一个和最后一个位置(重要)
给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]
。
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
# 暴力法:
# if target not in nums:return [-1, -1]
# tmp = []
# for i in range(len(nums)):
# if nums[i] == target:
# tmp.append(i)
# return [tmp[0], tmp[len(tmp)-1]]
# 二分法1
# left, right = 0, len(nums)-1
# while (left <= right):
# mid = (left + right)//2
# if nums[mid] < target:
# left = mid + 1
# elif nums[mid] > target:
# right = mid - 1
# elif nums[mid] == target:
# l=r=mid
# while l >= 0 and nums[l] == target: l -= 1
# while r <= len(nums)-1 and nums[r] == target: r += 1
# return [l+1, r-1]
# return [-1, -1]
53. 最大子序和
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
# 1、贪心算法(每一步都选择最佳方案,到最后就是全局最优的方案。)
# 当前sum和最大sum默认取第1个元素
# 当前sum用来判断当前连续子数组和是否继续增加元素还是新起一个连续子数组
# 最大sum用来记录所有连续子数组和,并保持更新取最大的值
curr_sum = max_sum = nums[0]
for i in range(1, len(nums)):
# 当前curr_sum为负数时,导致当前元素nums[i] > 当前curr_sum + nums[i]
# 此时摈弃前面的负数curr_sum,将nums[i]值重新赋值给curr_sum。
# 如果curr_sum值比之前的最大和max_sum更大,则赋值给max_sum保持最大。
curr_sum = max(nums[i], curr_sum + nums[i])
max_sum = max(max_sum, curr_sum)
return max_sum
# 2、动态规划(DP)
# 常数空间,沿数组移动并在原数组修改。
# 如果当前元素的前一项元素>0,说明对和有益,则当前元素更新为这两项的元素之和,
# 否则对和无益,摈弃前面的元素。
max_sum = nums[0]
for i in range(1, len(nums)):
if nums[i - 1] > 0:
nums[i] += nums[i - 1]
max_sum = max(nums[i], max_sum)
return max_sum
# 3、暴力法
# 类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
# 第1个循环,选取数组中的每一个元素作为初始位置进行遍历;
# 初始位置后加上后面的每一个元素,得到和sum,并不断的跟最大值max进行比较赋值
max_num = nums[0]
for i in range(len(nums)):
sum = 0
for j in range(i, len(nums)):
sum += nums[j]
max_num=max(max_num, sum)
return max_num
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
class Solution:
def climbStairs(self, n: int) -> int:
# 1、动态
if n <= 3:
return n
else:
f1, f2= 1, 2
for i in range(3, n+1):
f3 = f2 + f1
f1, f2 = f2, f3
return f3
# # 2、递归
if n <=3:
return n
else:
return self.climbStairs(n-1) + self.climbStairs(n-2)
# 3、记忆递归
li = [0,1,2]
if n <= 3:
return n
else:
for i in range(3, n+1):
li.append(li[i-1]+li[i-2])
return li[-1]
101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,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 isSymmetric(self, root: TreeNode) -> bool:
#递归:
if root == None:return True
def match(l,r):
if l == None and r==None:return True
elif l == None or r ==None:return False
elif l.val != r.val:return False
return match(l.left, r.right) and match(l.right, r.left)
return match(root.left, root.right)
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
# 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
# return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
# 迭代
stack = []
if root is not None:stack.append((1, root))
depth = 0
while stack != []:
current_depth, root = stack.pop()
if root is not None:
depth = max(depth, current_depth)
stack.append((current_depth+1,root.left))
stack.append((current_depth+1,root.right))
return depth