力扣题型练习

前言

构建图
在这里插入图片描述

graph={
    "A": ["B","C"],
    "B": ["A","C","D"],
    "C": ["A","B","D","E"],
    "D": ["B","C","E","F"],
    "E": ["C","D"],
    "F": ["D"]
}

注意:

  • pop(0)弹出第一个数
  • pop()弹出最后一个数

DFS 与 BFS 在寻找路径最不同的一点:

  • DFS 是一条路走到黑,它适合用于 「是否存在一条路径」
  • 而 BFS 是影分身,每次影分身都会在原基础上走一步,适合用于 「是否存在一条最短路径」

bfs(队列,先进先出)

在这里插入图片描述

def BFS(graph,s):
    queue=[]#队列
    queue.append(s)
    seen=set()#已访问过的集合
    seen.add(s)
    while(len(queue)>0):
        vertex=queue.pop(0)#弹出第一个元素
        nodes=graph[vertex]
        for w in nodes:
            if w not in seen:
                queue.append(w)
                seen.add(w)
        print(vertex)
BFS(graph,"A")#A B C D E F

dfs(栈,先进后出)

在这里插入图片描述

def DFS(graph,s):
    stack=[]#栈
    stack.append(s)
    seen=set()#已访问过的集合
    seen.add(s)
    while(len(stack)>0):
        vertex=stack.pop()#弹出最后一个元素
        nodes=graph[vertex]
        for w in nodes:
            if w not in seen:
                stack.append(w)
                seen.add(w)
        print(vertex)
DFS(graph,"A")#A C E D F B

bfs&dfs题目

783.二叉搜索树节点最小距离(中序遍历)

在这里插入图片描述
在这里插入图片描述

  • 先中序遍历,把结果防在数组中;
  • 然后对数组中的相邻元素求差,得到所有差值的最小值

xrange() 函数用法与 range 完全相同,所不同的是生成的不是一个数组,而是一个生成器。
xrange(3, 5)#xrange(3, 5)
list(xrange(3,5))#[3, 4]
range(3,5)# 使用 range[3, 4]

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def minDiffInBST(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        self.vals=[]
        self.dfs(root)
        return min([self.vals[i+1]-self.vals[i] for i in xrange(len(self.vals)-1)])
    


    def dfs(self,root):
        if not root:
            return
        self.dfs(root.left)
        self.vals.append(root.val)
        self.dfs(root.right)

2059.转换数字的最小运算数(BFS)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
算法思路:
在广度优先搜索的过程中,step为当前值对应的转化次数。
(从题干得出!!!)
注意到如果 x不在可以操作的范围(本题为 [0, 1000]闭区间内的整数)内,除非x=goal 恰好成立,否则由于我们无法进行任何操作,该数一定无法转化为目标值。
故我们无需将可操作范围以外的数值加入队列。且由于初始值一定在可操作范围内,因此我们可以保证队列中的值一定在可操作范围内。
除此以外,为了避免重复遍历,我们需要用数组vis 来维护可操作范围内整数是否已被加入过队列。
当我们遍历到 x 时,我们枚举数组中的元素和加、减与按位异或三种操作,计算生成的值y,此时有以下几种情况:

  • y恰好等于目标值goal,此时我们应当返回step+1,即初始值转化为目标值的最小次数作为答案;
  • y不在可操作范围,此时无需任何操作;
  • y在可操作范围内,且y已被加入过队列,此时无需任何操作;
  • y在可操作范围,且y未被加入过队列,此时我们需要更新y的访问情况,并将y加入队列,更新step+1;
  • 最终,不存在答案返回-1;
    参考BFS模板,加上步数统计
class Solution(object):
    def minimumOperations(self, nums, start, goal):
        """
        :type nums: List[int]
        :type start: int
        :type goal: int
        :rtype: int
        """
        queue=[]
        queue.append(start)
        seen=set()
        seen.add(start)
        step=0#记录步数
        while(len(queue)>0):
            step+=1#step是在这加1的!
            for _ in range(len(queue)):#用来累积步数的
                x=queue.pop(0)#弹出第一个元素
                for num in nums:
                    for y in (x+num,x-num,x^num):
                        if y==goal:                           
                            return step
                        if 0<=y<=1000 and y not in seen:
                            queue.append(y)
                            seen.add(y)
        return -1
                        

1219.黄金矿工

在这里插入图片描述
在这里插入图片描述
算法思路:回溯算法
首先在mXn个网格内枚举起点。只要格子内的数大于0,它就可以作为起点进行开采。记枚举的起点为(i,j),我们就可以从(i,j)开始进行递归+回溯,枚举所有可行的开采路径。我们用递归函数dfs(x,y,gold)进行枚举,其中(x,y)表示所在的位置,gold表示开采位置(x,y)之前,已拥有的黄金数量。根据题目的要求,我们需要进行如下步骤:

  • 我们需要将gold更新为gold+grid[x][y],表示对位置(x,y)进行开采。由于我们的目标是最大化收益,因此我们还要维护一个最大的收益值ans,并在这一步使用gold更新ans;
  • 我们需要枚举矿工下一步的方向。由于矿工每次可以从当前位置向上下左右四个方向走,因此我们需要依次枚举每一个方向。如果往某一方向不会走出网格,并且走到的位置的值不为0,我们就可以进行递归搜索;
  • 在搜索完所有方向后,我们进行回溯。

需要注意的是,题目规定了“每个单元格只能被开采一次”,因此当前我们到达位置(x,y)时,我们可以将grid[x][y]暂时置为0;在进行回溯之前,再将grid[x][y]的值恢复。

class Solution(object):
    def getMaximumGold(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        m=len(grid)
        n=len(grid[0])
        global ans
        ans=0
        
        def dfs(x,y,gold):
            gold=gold+grid[x][y]
            global ans
            ans=max(ans,gold)
            res=grid[x][y]
            grid[x][y]=0#遍历过,标记
            for nx,ny in ((x-1,y),(x+1,y),(x,y-1),(x,y+1)):
                if 0<=nx<m and 0<=ny<n and grid[nx][ny]>0:#符合条件遍历
                    dfs(nx,ny,gold)

            grid[x][y]=res#遍历完恢复原来值


        for i in range(m):
            for j in range(n):
                if grid[i][j]!=0:#依次遍历
                    dfs(i,j,0)
        
        return ans

LCP 07.传递信息(dfs)

在这里插入图片描述
在这里插入图片描述
算法思路:暴力的深度搜索

class Solution(object):
    def numWays(self, n, relation, k):
        """
        :type n: int
        :type relation: List[List[int]]
        :type k: int
        :rtype: int
        """
        adjvex=collections.defaultdict(set)#python里也可用
        for x,y in relation:
            adjvex[x].add(y)#x位置,y为能传到的地方,可能不止一个
        def dfs(x,step):
            if step==k:#到达规定的轮数
                if x==n-1:#并且到最后一个点
                    self.res+=1#结果加1
                return
            for y in adjvex[x]:
                dfs(y,step+1)
        self.res=0
        dfs(0,0)#初始值:位置0,步数0
        return self.res

模拟、字符串

6.Z字形变换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution(object):
    def convert(self, s, numRows):
        """
        :type s: str
        :type numRows: int
        :rtype: str
        """
        if numRows < 2: return s
        res = ["" for _ in range(numRows)]
        i, flag = 0, -1
        for c in s:
            res[i] += c
            if i == 0 or i == numRows - 1: flag = -flag#flag用得妙
            i += flag
        return "".join(res)

往届真题

蛇形填数

在这里插入图片描述
解题思路:找规律,模拟

找到一个很关键的规律
ij坐标相加是奇数,←↓走势
ij坐标相加是偶数,→↑走势
在这里插入图片描述

i,j,num=0,0,0#初始化坐标和计数器
while True:#无限循环开始
    num+=1#元素递增
    if i==19 and j==19:#从0遍历到19, 相当于20行20列
        break
    if (i+j)&1:#奇数↙
        i+=1
        if j>0:
            j-=1
    else:#偶数↗
        j+=1
        if i>0:
            i-=1
print(num)#761

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值