贪心算法
采用贪心的策略保证每次操作都是局部最优,使其尽可能的多(但不一定是最多的)
分配问题
455.Assign Cookies分发饼干(easy)
"""
思路:用最小且能饱腹的饼干分给饥饿度最小的孩子,达到资源最大化
"""
class Solution(object):
def findcontentchildren(self,g,s):
g = sorted(g) #饥饿度
s = sorted(s) #饼干
childcount = cookies = 0
#还有孩子或饼干没有分配完则继续
while (childcount < len(g)) and (cookies < len(s)):
#每次给饥饿度最小的孩子分配最小且能饱腹的饼干
if g[childcount] <= s[cookies]:
childcount += 1 #能饱腹,则喂饱孩子数+1
cookies += 1 #若不能饱腹,则该饼干对之后其他孩子都无效,消耗饼干数+1
return childcount #返回喂饱孩子个数
135.Candy分发糖果(hard)
"""
思路:两次遍历,所有孩子初始化糖果数为1
先从左往右遍历,右边的孩子比左边的评分高,则右边的糖果数为左边糖果数+1
再从右往左遍历,左边的孩子比右边的评分高且左边当前糖果数不大于右边,则左边糖果数为右边糖果数+1
"""
class Solution:
def candy(self, ratings: List[int]) -> int:
n = len(ratings) #人数
candy_nums = [1] * n #糖果数全部初始化为1
#从左开始遍历
for i in range(1,n):
if ratings[i] > ratings[i-1]: #右大于左
candy_nums[i] = candy_nums[i-1]+1
else:
candy_nums[i] = 1
#从右开始遍历
for i in range(n-1,0,-1): #1到n的倒序
if ratings[i-1] > ratings[i]:
candy_nums[i-1] = max(candy_nums[i-1],candy_nums[i]+1)
return sum(candy_nums)
605.CanPlaceFlowers种花问题(easy)
"""
思路:花坛列表首尾加0(不影响种花),找出0位置,其左右两端都为0,则种花数+1,当前位置更新为1,进行循环
"""
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
count = 0
flowerbed = [0]+flowerbed+[0]
for i in range(1,len(flowerbed)-1):
if flowerbed[i] == 0 and flowerbed[i+1] == 0 and flowerbed[i-1] == 0:
count+=1
flowerbed[i] = 1
if count >= n:
return True
return False
860.柠檬水找零(easy)(增)
"""
思路:if条件语句进行判断
"""
class Solution:
def lemonadeChange(self, bills: List[int]) -> bool:
five,ten,twenty = 0,0,0
for i in bills:
if i == 5:
five += 1
elif i == 10 and five >= 1:
if five < 1: return False
five -= 1
ten += 1
else:
if ten >= 1 and five >= 1:
five -= 1
ten -= 1
twenty += 1
elif five >= 3:
five -= 3
twenty += 1
else:
return False
return True
区间问题
452.最少箭射气球(medium)
class Solution:
def findMinArrowShots(self, points: List[List[int]]) -> int:
if not points:
return 0
points.sort(key = lambda x:x[1]) #以右坐标排序
count = 1 #先射一箭
biu = points[0][1] #射箭位置为第一个球的右坐标
for ball in points:
if ball[0] <= biu: #如果球的位置在射箭位置的左侧则同时射落两个
continue
else:
count += 1 #否则需要再次射箭
biu = ball[1] #射箭位置为这个球的右坐标
return count
435.无重叠区间(medium)
"""
思路:对区间以右坐标为准进行排序,首个区间就是右坐标最小的区间,找出与首个区间不重叠且右坐标最小的区间(其左坐标大于首区间右坐标即不重叠),进行遍历找出所有不重叠区间
"""
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort(key = lambda x: x[1]) #以右坐标排序
cur,ok = 0,1
n = len(intervals)
for i in range(1,n):
if intervals[i][0] >= intervals[cur][1]: #左坐标大于最小右坐标即不重叠
ok += 1
cur = i
return n-ok
链表
206.反转链表(easy)
class Solution:
def reverseList(self,head):
if head == None or head.next == None:
return head
pre = None
cur = head
while cur:
x = cur.next
cur.next = pre
pre = cur
cur = x
return pre
21.合并两个有序链表(easy)
"""
思路:先设置一个哨兵节点pre,若l1 当前节点的值小于等于 l2 ,就把 l1 当前的节点接在 pre 节点的后面同时将 l1 指针往后移一位。否则,对 l2 做同样的操作。不管将哪一个元素接在了后面,都需要把 pre 向后移一位。直到l1,l2指向null
"""
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
prehead = ListNode(-1)
pre = prehead
while l1 and l2:
if l1.val <= l2.val: #l1节点的值小于l2
pre.next = l1 #pre指针下一节点指向l1
l1 = l1.next #l1指针后移一位
else: #l2节点的值小于l1
pre.next = l2 #pre指针下一节点指向l2
l2 = l2.next #l2指针后移一位
pre = pre.next #pre指针后移
# 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
if l1 is not None:
pre.next = l1
else:
pre.next = l2
return prehead.next
234.回文链表(easy)
"""
思路:遍历链表将值复制到数组列表中。我们用 current_node 指向当前节点。每次迭代向数组添加 current_node.val,并更新 current_node = current_node.next,当 current_node = null 时停止循环。比较列表中的节点地值是否回文
"""
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
val = []
current_node = head
while current_node:
val.append(current_node.val)
current_node = current_node.next
return val == val[::-1]
83.删除排序链表重复值(easy)
"""
下一节点的值不等于该节点的值则指针下移,若相等,则该点指针指向下下个节点
"""
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
cur = head
if not head:
return head
while cur.next:
if cur.next.val == cur.val:
cur.next = cur.next.next
else:
cur = cur.next
return head
"""
Method 1
思路:使用快慢指针的方法,先定义一个虚拟节点dummyhead,让快指针先走n步,然后快慢指针再一起走,当快指针走到链表最后指向空的时候,慢指针的下一个节点即为要删除节点,此时让慢指针指向下下个节点即可。
"""
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dummyhead = ListNode(0,head) #定义一个虚拟节点0,快慢指针都从虚拟节点开始
fast = dummyhead
slow = dummyhead
#进行循环,让快指针先走n步
i = 0
while i < n:
fast = fast.next
i += 1
#快慢指针一起走直到快指针为空
while fast.next is not None:
fast = fast.next
slow = slow.next
#删除节点
slow.next = slow.next.next
return dummyhead.next
"""
Method 2
思路:首先从头节点开始对链表进行一次遍历,得到链表的长度 L。随后我们再从头节点开始对链表进行一次遍历,当遍历到第 L-n+1个节点时,它就是我们需要删除的节点。
"""
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
def getLength(head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
dummy = ListNode(0, head)
length = getLength(head)
cur = dummy
for i in range(1, length - n + 1):
cur = cur.next
cur.next = cur.next.next
return dummy.next
328.奇偶链表(medium)
"""
思路:分离奇偶链表,最后将两个链表进行合并。
第一个节点为head奇数链表的头结点,它的下一节点为偶数,是偶数链表的头结点
"""
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head:
return head
evenhead = head.next
odd, even = head, evenhead
while even and even.next:
odd.next = even.next
odd = odd.next
even.next = odd.next
even = even.next
odd.next = evenhead
return head
KMP算法
28.实现strStr() (easy)
def strStr(haystack, needle):
if len(needle) == 0:
return 0
m,n = len(haystack), len(needle)
#1.求next数组
nxt = [0] * n
j = 0
for i in range(1,n):
while j > 0 and needle[i] != needle[j]:
j = nxt[j-1]
if needle[i] == needle[j]:
j += 1
nxt[i] = j
#return nxt
#2.匹配字符串
j = 0
for i in range(0, m):
while j>0 and haystack[i] != needle[j]:
j = nxt[j - 1]
if haystack[i] == needle[j]:
j += 1
if j == n:
return i - n + 1
return -1
strStr('abxabcabcaby','abcaby')
二分查找
704.二分查找(easy)
"""
思想:把nums分为大致相等的两部分,取nums[mid]与target作比较:
若nums[mid]=t,则找到t,返回mid值即为下标
若nums[mid]<t,则在mid右半边继续寻找t
若nums[mid]>t,则在mid左半边继续寻找t
high<low时跳出循环
"""
class Solution(object):
def search(self, nums, target):
left,right = 0,len(nums)-1
while left <= right:
mid = (left+highright)//2
if nums[mid] < target: #若中间值小于目标值,则low移到mid右边,再次循环更新mid
left = mid + 1
elif nums[mid] > target: #若中间值大于目标值,则high移到mid左边,再次循环更新mid
right = mid - 1
else:
return mid
return -1
69.sqrt()
class Solution(object):
def mySqrt(self, x):
left,right = 0, x
while left <= right:
mid = (left+right)//2
if mid**2 < x:
left = mid+1
elif mid**2 > x:
right = mid-1
else:
return mid
return right #right>left时跳出循环,mid值不是int向下取整,此时right=mid-1,故返回right
栈
20.有效的括号(easy)
"""
思路:使用栈的方法,依次遍历s,若为左括号,则入栈,若为右括号且栈不为空,则看右括号是否与栈顶的左括号匹配,匹配则返回True
"""
class Solution:
def isValid(self, s: str) -> bool:
matchingBrackets = {")":"(", "]":"[", "}":"{"}
stack = []
for i in s:
if i in '([{':
stack.append(i) #左括号则入栈
elif i in ')]}':
if stack == []:
return False
else:
if matchingBrackets[i] == stack[-1]: #若右括号与栈顶左括号匹配
stack.pop() #栈顶左括号出栈
else:
return False
if stack == []: #遍历完后,栈为空则全部匹配成功
return True
else:
return False
225. 用队列实现栈(easy)
class MyStack:
def __init__(self):
self.queue1 = collections.deque()
self.queue2 = collections.deque()
def push(self, x: int) -> None:
self.queue2.append(x)
while self.queue1:
self.queue2.append(self.queue1.popleft())
self.queue1, self.queue2 = self.queue2, self.queue1
def pop(self) -> int:
return self.queue1.popleft()
def top(self) -> int:
return self.queue1[0]
def empty(self) -> bool:
return not self.queue1
739.每日温度(medium)
"""
单调栈思路:我们实际上就是要找到每个数右边第一个比它大的数
从左到右依次遍历温度,让数组的下标入栈(注意是下标不是温度!)
比较栈顶元素所在位置的温度与当前的温度,若当前温度更低,则温度对应的下标入栈;若当前温度更高,则栈顶元素出栈,数组中填入当前温度与栈顶温度的间隔天数
"""
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
stack = [0]
answer = [0]*len(temperatures)
for i in range(1,len(temperatures)):
if temperatures[i] <= temperatures[stack[-1]]: #当前温度小于栈顶温度
stack.append(i) #入栈
else:
while len(stack) != 0 and temperatures[i] > temperatures[stack[-1]]: #栈不为空且当前温度大于栈顶温度
answer[stack[-1]] = i - stack[-1]
stack.pop() #出栈
stack.append(i) #当前温度下标入栈
return answer
二叉树
104.二叉树的最大深度(easy)
# 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 maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
else:
left_height = self.maxDepth(root.left)
right_height = self.maxDepth(root.right)
return max(left_height,right_height) + 1
226.翻转二叉树(easy)
# 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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left,root.right = right,left
return root
617.合并二叉树(easy)
# 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 mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
if not t1:
return t2
if not t2:
return t1
merged = TreeNode(t1.val+t2.val)
merged.left = self.mergeTrees(t1.left,t2.left)
merged.right = self.mergeTrees(t1.right,t2.right)
return merged
101.对称二叉树(easy)
# 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
"""
t1,t2只要有一个为空,则返回False
t1,t2都为空,则返回True
采用递归的思想,判断左右子树是否镜像对称,直到有true或false
"""
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def tree(t1,t2):
if not t1 and not t2:
return True
elif not t1 or not t2:
return False
elif t1.val != t2.val:
return False
else:
#判断t1左子树与t2右子树是否是镜像对称的,t1右子树与t2左子树是否是镜像对称的
return tree(t1.left,t2.right) and tree(t1.right,t2.left)
#判断根的左右子树是否是镜像对称的
return tree(root.left,root.right)
110.平衡二叉树(easy)
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
"""
思路:递归地去遍历每个节点,计算每个节点地左右子树的深度,判断左右子树的深度是否会超过1,若不超过1则返回True,否则返回False
"""
#求树的深度
def depth(root):
if not root:
return 0
left = depth(root.left)
right = depth(root.right)
return max(left,right) + 1
#求每个节点左右子树的深度差
def compare_depth(root):
if not root: #若为空树则左右子树均为空
return True
#左右子树的深度,调用求深度的递归函数
leftdepth = depth(root.left)
rightdepth = depth(root.right)
if abs(leftdepth - rightdepth) > 1:
return False
#否则,深度差小于1,再递归地找左右子树的子树看其是否平衡
return compare_depth(root.left) and compare_depth(root.right)
return compare_depth(root)
数学问题
326. 3的幂(easy)
- 2的幂
- 4的幂同理
"""
思路:n一直除以3,直到n=1则该数是3的幂
"""
class Solution:
def isPowerOfThree(self, n: int) -> bool:
#试除法
while n and n % 3 == 0:
n = n / 3
if n==1:
return True
return False
#递归法
class Solution:
def isPowerOfThree(self, n: int) -> bool:
if n <= 0:
return False
if n == 1:
return True
if n % 3 != 0:
return False
return self.isPowerOfThree(n/3)
202.快乐数(easy)
#本题还可使用快慢指针以及哈希表方法求解
class Solution:
def isHappy(self, n: int) -> bool:
def calculate_happy(num):
sum_ = 0
while num:
sum_ += (num % 10) ** 2 #从个位开始依次取,平方求和
num = num // 10
return sum_
record = [] #记录中间结果
while True:
n = calculate_happy(n) #将n赋值为位置平方和
if n == 1:
return True
elif n in record: #若中间结果重复出现说明陷入死循环,不是快乐数
return False
else:
record.append(n)