代码随想录 - Day35 - 回溯:重新安排行程,棋盘问题

news2024/11/23 15:27:36

代码随想录 - Day35 - 回溯:重新安排行程,棋盘问题

332. 重新安排行程

输入:tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
输出:["JFK","ATL","JFK","SFO","ATL","SFO"]
解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ,但是它字典排序更大更靠后。
只能取JFK开头的
取[JFK,SFO]
只能取JFK开头的
取[JFK,ATL]
只能取SFO开头的
取[SFO,ATL]
只能取ATL开头的
取[ATL,JFK]
只能取ATL开头的
取[ATL,SFO]
只能取ATL开头的
取[ATL,JFK]
只能取ATL开头的
取[ATL,SFO]
只能取JFK开头的
取[JFK,SFO]
只能取SFO开头的
取[SFO,ATL]
只能取JFK开头的
取[JFK,ATL]
没有可用的SFO开头的
只能取SFO开头的
取[SFO,ATL]
只能取ATL开头的
取[ATL,JFK]
只能取ATL开头的
取[ATL,SFO]
只能取ATL开头的
取[ATL,SFO]
只能取JFK开头的
取[JFK,SFO]
按字典序排列
[JFK,ATL,JFK,SFO,ATL,SFO] < [JFK,ATL,SFO,ATL,JFK,SFO] < [JFK,SFO,ATL,JFK,ATL,SFO]
取SFO加在后面
[JFK,ATL,JFK,SFO,ATL,SFO]
结束
[JFK,SFO], [JFK,ATL], [SFO,ATL], [ATL,JFK], [ATL,SFO]
[JFK,SFO]
[JFK,ATL]
取ATL加在后面
[JFK,SFO,ATL]
取JFK加在后面
[JFK,ATL,JFK]
取SFO加在后面
[JFK,ATL,SFO]
取JFK加在后面
[JFK,SFO,ATL,JFK]
取SFO加在后面
[JFK,SFO,ATL,SFO]
取SFO加在后面
[JFK,SFO,JFK,SFO]
取ATL加在后面
[JFK,ATL,SFO,ATL]
取ATL加在后面
[JFK,SFO,ATL,JFK,ATL]
取ATL加在后面
[JFK,ATL,JFK,SFO,ATL]
取JFK加在后面
[JFK,ATL,SFO,ATL,JFK]
取SFO加在后面
即[JFK,SFO,ATL,JFK,ATL,SFO]
取SFO加在后面
[JFK,ATL,SFO,ATL,JFK,SFO]
[JFK,ATL,JFK,SFO,ATL,SFO]最小

最终答案:行程有效 + 按字典排序最小
行程有效:

  • 第一个必须从JFK出发
  • 所有机票必须且只能用一次
class Solution:
    def backtracking(self, tickets, used, path, cur, result):
        if len(path) == len(tickets) + 1:   # 有效行程比票数大1,所以判断条件应该写成这样
            result.append(path[:])
            return True

        for i, ticket in enumerate(tickets):
            if ticket[0] == cur and used[i] == False:   # 没用过的机票 + 出发机场和上一次的到达机场必须是同一个
                used[i] = True  # 用过的机票设为True
                path.append(ticket[1])  # 只向path中添加到达机场
                state = self.backtracking(tickets, used, path, ticket[1], result)
                path.pop()  # 回溯,pop
                used[i] = False # 回溯,把机票设回False
                if state:   # 只要找到一个可行路径就返回,不继续搜索
                    return True

    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        result = []
        tickets.sort()  # 提前给tickets排序,这样收集到result时的顺序一定是字典序由小到大的
        path = ["JFK"]  # 第一个从JFK出发
        used = [False] * len(tickets)   # 没用过的tickets设为False
        self.backtracking(tickets, used, path, "JFK", result)
        return result[0]

上述代码也可以写成这样:

class Solution:
    def backtracking(self, tickets, used, path, cur, result):
        if len(path) == len(tickets) + 1:
            result.append(path[:])
            return True

        for i in range(len(tickets)):
            if tickets[i][0] == cur and used[i] == False:
                used[i] = True
                path.append(tickets[i][1])
                state = self.backtracking(tickets, used, path, tickets[i][1], result)
                path.pop()
                used[i] = False
                if state:
                    return True

    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        result = []
        tickets.sort()
        path = ["JFK"]
        used = [False] * len(tickets)
        self.backtracking(tickets, used, path, "JFK", result)
        return result[0]

使用字典:比上面的代码复杂了一点,但是速度更快

defaultdict()中只能存在不同的 key。

  • 添加元素时([key1, value2]),如果defaultdict()里面已经有一个 key1 了({key1: value1}) ,就不会新建一个 key1,而是把 value2 添加在 key1 原本的 value1 后面({key1: [value1, value2]}
from collections import defaultdict

class Solution:
    def backtracking(self, targets, path, ticketNum):
        if len(path) == ticketNum + 1:
            return True  # 找到有效行程

        airport = path[-1]  # 当前机场(path中最后一个元素)
        destinations = targets[airport]  # 取机场字典中的当前机场对应的 value 值,即为当前机场可以到达的机场列表
        for i, dest in enumerate(destinations):
            targets[airport].pop(i)  # 标记已使用的机票(把第 i 张机票删掉)
            # pop掉的i对应的到达机场 == path.append()的dest表示的到达机场
            path.append(dest)  # 添加目的地到路径
            if self.backtracking(targets, path, ticketNum):
                return True  # 找到有效行程
            targets[airport].insert(i, dest)  # 回溯,恢复机票(把第 i 张机票插入回 i 的位置
            path.pop()  # 移除目的地
        return False  # 没有找到有效行程

    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        targets = defaultdict(list)  # 构建机场字典
        # 把出发机场作为 key,到达机场作为 value
        # 如 JFK : SFO, ATL
        for ticket in tickets:
            targets[ticket[0]].append(ticket[1])
        # 对到达机场列表进行排序
        # 如 JFK : SFO, ATL 排序为 JFK : ATL, SFO
        for airport in targets:
            targets[airport].sort()  

        path = ["JFK"]  # 起始机场为"JFK"
        self.backtracking(targets, path, len(tickets))
        return path   

这道题是困难题,但是,把图画出来之后觉得不是很难,思路也比较好想,就是代码不好写。
敲代码能力有很大的进步空间。
可能是因为敲的太少手生吧。

51. N皇后

n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击,即这 n 个皇后不能处于同一行 / 同一列 / 同一斜线。

给一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表皇后和空位。

不会,直接看题解。
画了个图辅助理解。
在这里插入图片描述

假设Q占据的格子为 [x, y] ,那么 [x1~xn, y][x, y1~yn][x+i, y+i][x-i, y-i],都不能再放其它Q了。要注意边界范围,所有的坐标都小于n

class Solution:
    def isValid(self, row, col, chessBoard):
        # 检查列
        for i in range(row):
            if chessBoard[i][col] == "Q":
                return False
        # 检查 45 度角是否有皇后
        i, j = row - 1, col - 1
        while i >= 0 and j >= 0:
            if chessBoard[i][j] == "Q":
                return False    # 左上方向已经存在皇后,不合法
            i -= 1
            j -= 1
        # 检查 135 度角是否有皇后
        i, j = row - 1, col + 1
        while i >= 0 and j < len(chessBoard):
            if chessBoard[i][j] == "Q":
                return False    # 右上方向已经存在皇后,不合法
            i -= 1
            j += 1

        return True

    def backtracking(self, n, row, chessBoard, result):
        if row == n:
            result.append(chessBoard[:])    # 棋盘填满,将当前解加入结果集
            return
        for col in range(n):
            if self.isValid(row, col, chessBoard):
                chessBoard[row] = chessBoard[row][:col] + 'Q' + chessBoard[row][col+1:]  # 放置皇后
                self.backtracking(n, row + 1, chessBoard, result)   # 递归到下一行
                chessBoard[row] = chessBoard[row][:col] + '.' + chessBoard[row][col+1:]  # 回溯,撤销当前位置的皇后


    def solveNQueens(self, n: int) -> List[List[str]]:
        result = []
        chessBoard = ['.' * n for _ in range(n)]  # 初始化棋盘
        self.backtracking(n, 0, chessBoard, result)
        return [[''.join(row) for row in solution] for solution in result]  # 变成字符串放进 list 返回

我想不通,明明我的思路没错,为什么代码总是报错!
找到问题了,因为字符串不能直接修改,所以只好用切片的方式修改,这样才能正常运行,并得到正确结果。

37. 解数独

这道题不让return,只能在原有board里修改
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
数独部分空格内已填入了数字,空白格用 '.' 表示。
数独只有一个解
借用代码随想录里面的图:
在这里插入图片描述

本题中棋盘的每一个位置都要放一个数字(而N皇后是一行只放一个皇后),并检查数字是否合法,解数独的树形结构要比N皇后更宽更深。
本题递归不用终止条件,解数独是要遍历整个树形结构寻找可能的叶子节点就立刻返回。
不用终止条件不会死循环
递归的下一层的棋盘一定比上一层的棋盘多一个数,等数填满了棋盘自然就终止(填满当然好了,说明找到结果了),所以不需要终止条件!
递归逻辑:
一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!

class Solution:
    def isValid(self, row, col, val, board):
        for i in range(9):
            if board[row][i] == str(val):
                return False
        for j in range(9):
            if board[j][col] == str(val):
                return False
        startRow = (row // 3) * 3
        startCol = (col // 3) * 3
        for i in range(startRow, startRow + 3):
            for j in range(startCol, startCol + 3):
                if board[i][j] == str(val):
                    return False
        return True

    def backtracking(self, board):
        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] != ".":
                    continue
                for k in range(1, 10):
                    k = str(k)
                    if self.isValid(i, j, k, board):
                        board[i][j] = k
                        if self.backtracking(board):
                            return True
                        board[i][j] = '.'
                return False
        return True

    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        self.backtracking(board)

今天这三道题让我感到恶心🤢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/989741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么客户跟踪对客户成功很重要?如何正确做到这一点?

如果您想以客户为中心&#xff0c;了解您的客户就非常重要。您可以利用客户沟通管理平台&#xff0c;例如SaleSmartly&#xff08;SS客服&#xff09;查看各种指标来了解客户对您的实际体验以及他们对您的期望。您需要长时间跟踪它们&#xff0c;注意它们的变化并找出原因&…

JavaEE初阶(1)(冯诺依曼体系、CPU、CPU基本原理、如何衡量CPU的好坏?指令、操作系统、操作系统“内核”)

目录 冯诺依曼体系&#xff08;Von Neumann Architecture&#xff09; CPU CPU基本原理&#xff1a; 如何衡量CPU的好坏&#xff1f; 1、主频&#xff08;时钟速度&#xff09;&#xff1a; 2、核心数&#xff1a; 指令 操作系统 操作系统“内核” 冯诺依曼体系&#x…

微信小程序 房贷计算器 js代码终极版

这里写目录标题 展示图1.在utils 中创建文件calculateMortgage.ts2. 在需要使用的地方引入并传参 展示图 1.在utils 中创建文件calculateMortgage.ts /** 假设房贷本金是60万&#xff0c;贷款年利率为4.8%即月利率为0.4%&#xff0c;分20年即240期偿还&#xff0c;等额本金还款…

OpenCV(三十二):轮廓检测

1.轮廓概念介绍 在计算机视觉和图像处理领域中&#xff0c;轮廓是指在图像中表示对象边界的连续曲线。它是由一系列相邻的点构成的&#xff0c;这些点在边界上连接起来形成一个封闭的路径。 轮廓层级&#xff1a; 轮廓层级&#xff08;Contour Hierarchy&#xff09;是指在包含…

哭了,python自动化办公,终于支持 Mac下载了

想了解更多精彩内容&#xff0c;快来关注程序员晚枫 大家好&#xff0c;这里是程序员晚枫&#xff0c;小红薯/小破站也叫这个名。 在我的主页发布的免费课程&#xff1a;给小白的《50讲Python自动化办公》&#xff0c;一直在更新中&#xff0c;昨晚12点多&#xff0c;有朋友在…

1987-2021年全国31省专利申请数和授权数

1987-2021年全国31省国内三种专利申请数和授权数 1、时间&#xff1a;1987-2021年 2、来源&#xff1a;整理自国家统计局、科技统计年鉴、各省年鉴 3、范围&#xff1a;31省市 4、指标&#xff1a;国内专利申请受理量、国内发明专利申请受理量、国内实用新型专利申请受理量…

PCIe 5.0验证实战,经常遇到的那些问题?

PCIe 5.0是当前最新的PCI Express规范&#xff0c;提供了更高的数据传输速率和更大的带宽。 PCIe是连接两个芯片的接口&#xff0c;负责两个芯片通信, 连接芯片的通路为高速SerDes, 称之为链路。PCIe确保通路正常-链路训练状态机。PCIe在芯片内部是非常重要的一个大的模块&…

php常用算法

许多人都说 算法是程序的核心&#xff0c;一个程序的好于差,关键是这个程序算法的优劣。作为一个初级phper&#xff0c;虽然很少接触到算法方面的东西 。但是对于冒泡排序&#xff0c;插入排序&#xff0c;选择排序&#xff0c;快速排序四种基本算法&#xff0c;我想还是要掌握…

论机器生产内容 MGC 与新数字时代的两个世界

摘要&#xff1a;本文从新数字时代人类社会的两种存在形态&#xff1a;数字世界&#xff08;元宇宙&#xff09;与物理世界&#xff08;时空宇宙&#xff09;&#xff0c;以及新兴数字产业&#xff1a;机器生产内容MGC的发展、现状与未来出发&#xff0c;通过对新数字时代及两个…

Mysql 入门篇之二进制安装

文章目录 Mysql 5.7 入门安装卸载自带组件下载二进制包安装配置 Mysql 8.0 入门安装卸载自带组件下载二进制包安装配置 Mysql 5.7 入门安装 环境说明&#xff1a;CentOS Linux release 7.6.1810 (Core) 4核4G 卸载自带组件 卸载自带的mysql相关组件 rpm -qa | grep mysql rpm…

jemalloc 5.3.0源码总结

注意&#xff1a;jemalloc 的最新版本里没有所谓的 huge class&#xff0c;bin 中slab外面也不再套一个run的概念了&#xff0c;看其它人分享的文章时需要注意。 简述 用户侧通过 tcache 来访问&#xff0c;tcache 是一个线程的申请又释放的对象的缓存&#xff0c;它绑定了一…

紫光电子档案管理系统存在SQL注入漏洞(漏洞复现)

文章目录 紫光电子档案管理系统存在SQL注入漏洞&#xff08;漏洞复现&#xff09;0x01 前言0x02 漏洞描述0x03 影响范围0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 紫光电子档案管理系统存在SQL注入漏洞&#xff08;漏洞复现&#xff09; 0x01 前言 本次测试仅…

数据结构与算法-----指针与结构体

目录 前言 指针 定义 示例1&#xff08;访问修改数据&#xff09;&#xff1a; 示例2&#xff08;野指针&#xff09;&#xff1a; 示例3&#xff08;动态空间分配问题&#xff09;&#xff1a; 示例4&#xff08;字符串赋值错误问题&#xff09;&#xff1a; 示例5&am…

2023年限售股解禁研究报告

第一章 概述 解禁是指限售流通股过了限售承诺期&#xff0c;可以在二级市场自由买卖的过程。根据流通性质&#xff0c;可将上市公司股份分为有限售条件的流通股&#xff08;“限售流通股”&#xff09;及无限售条件的流通股&#xff08;“流通股”&#xff09;。 限售流通股指…

案例实战-Spring boot Web

准备工作 需求&环境搭建 需求&#xff1a; 部门管理&#xff1a; 查询部门列表 删除部门 新增部门 修改部门 员工管理 查询员工列表&#xff08;分页、条件&#xff09; 删除员工 新增员工 修改员工 环境搭建 准备数据库表&#xff08;dept、emp&#xff09; -- 部门管理…

NLP(3)--GAN

目录 一、概述 二、算法过程 三、WGAN 1、GAN的不足 2、JS散度、KL散度、Wasserstein距离 3、WGAN设计 四、Mode Collapse and Mode Dropping 1、Mode Collapse 2、Mode Dropping 3、FID 四、Conditional GAN 一、概述 GAN&#xff08;Generative Adversial Networ…

【云原生进阶之PaaS中间件】第一章Redis-1.7发布订阅模式

1 Redis 发布订阅 1.1 概述 发布订阅模式&#xff08;Publish-Subscribe Pattern&#xff09;是一种消息传递模式&#xff0c;其基本原理是消息的发送者&#xff08;发布者&#xff09;不会直接发送消息给特定的接收者&#xff08;订阅者&#xff09;&#xff0c;而是将消息分…

基于SpringBoot的无忌在线考试系统(源码+讲解+调试运行)做毕设课设均可

技术栈 前后端分离 前端使用: Vue Element Plus 后端使用: SpringBoot Mysql8.0 Mybatis-Plus 功能 分为 管理员端 和 老师端 和 学生端 管理员端 登陆页 ​科目管理 查看所有科目 ,增加 ,修改 ,删除科目 , 模糊搜索课程 ​考试管理 查看所有考试 ,增加 ,修改 ,删除考试 题库…

Linux之Shell变量和引用

目录 深入认识变量 什么是变量 变量的名称 组成 规则 变量的类型 原则 shell的变量数据类型 变量定义 原则 格式 案例 自定义变量 定义 引用变量的值 查看变量 环境变量 定义 定义环境变量 案例 --- 三种方法定义 对比 shell环境变量存储的文件 位置变量…

Python - PyQt6、QDesigner、pyuic5-tool 安装使用

Python 开发可视化界面可以使用原生的 tkinter&#xff0c;但是原生框架使用起来颇为不方便&#xff0c;所以最流行的还是QT UI框架&#xff0c;QT是使用C语言开发&#xff0c;Python 想使用需要对其进行封装&#xff0c;所以就出现了PyQt框架&#xff0c;这个框架使用极其方便…