代码随想录算法训练营第三十天| 332.重新安排行程, 51. N皇后, 37. 解数独,总结

news2024/11/20 17:39:53

题目与题解

参考资料:回溯总结

332.重新安排行程

题目链接:332.重新安排行程

代码随想录题解:332.重新安排行程

视频讲解:带你学透回溯算法(理论篇)| 回溯法精讲!_哔哩哔哩_bilibili

解题思路:

        这题有两个难点,一个是要求返回的结果是按升序排列最小的,另一个是行程要保证使用每一张机票,并且假设机票行程存在环路,不能困在环中。

        针对第一个难点,可以提前对tickets进行排序,利用list.sort方法重写其中的comparator,排序的key为tickets里面每一张ticket的目的地,也就是tickets.get(i).get(1),这样保证有结果时,第一个结果一定是升序最小。

        针对第二个难点,这里是树枝的去重问题,所以可以用一个usedTickets数组,记录每一张ticket的使用情况,用过就设置为true,保证不会重复使用。

        然后就可以用回溯三部曲:

        参数有 - 用于存放结果的result,用于记录路线的path,输入tickets,usedTickets数组和每次递归时的起点start(这里也可以不需要这个参数,用path.getLast()代替)

        终止条件 - 题目要求每张机票都使用,那么每有N张机票,途径地点就有N+1个,所以当path的元素到达n+1后,路径就完成了,可以返回结果。

        单层遍历逻辑:循环遍历tickets里面的每一个元素,如果usedTickets[i]为true,或者tickets.get(i).get(1) 不等于start,则跳过该循环;否则将tickets.get(i).get(1)加入path,usedTickets[i]设置为true,调用回溯方法,修改start为tickets.get(i).get(1),出来后修改usedTickets[i]为false并弹出path最后一个元素即可。

class Solution {
	List<String> result = new ArrayList<>();
	LinkedList<String> path = new LinkedList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
		boolean[] usedTickets = new boolean[tickets.size()];
		// tickets.sort((list1, list2) -> list1.get(0).compareTo(list2.get(0)));
		tickets.sort(Comparator.comparing(list -> list.get(1)));
		path.add("JFK");
		findItinerary(tickets, usedTickets, "JFK");
		return result;
    }

	boolean findItinerary(List<List<String>> tickets, boolean[] usedTickets, String start) {
		if (path.size() == tickets.size() + 1) {
			result = new ArrayList<>(path);
			return true;
		}
		for (int i = 0; i < tickets.size(); i++) {
			if (usedTickets[i] || !tickets.get(i).get(0).equals(start)) continue;
			path.add(tickets.get(i).get(1));
			usedTickets[i] = true;
			if (findItinerary(tickets, usedTickets, tickets.get(i).get(1)))
				return true;
			usedTickets[i] = false;
			path.pollLast();
		}
		return false;
	}
}

但是这样写在leetcode上不能ac,会提示超时,因为每次遍历tickets都是从头开始遍历的,搜索效率非常低,需要用map替代list。 

看完代码随想录之后的想法 

        随想录答案改造了一下ticket,用Map<String, Map<String, Integer>> map存储tickets每一个起点对应的多个目的地,以及机票用过与否的情况。目前自己写还比较难,先放着以后看。

class Solution {
    private Deque<String> res;
    private Map<String, Map<String, Integer>> map;

    private boolean backTracking(int ticketNum){
        if(res.size() == ticketNum + 1){
            return true;
        }
        String last = res.getLast();
        if(map.containsKey(last)){//防止出现null
            for(Map.Entry<String, Integer> target : map.get(last).entrySet()){
                int count = target.getValue();
                if(count > 0){
                    res.add(target.getKey());
                    target.setValue(count - 1);
                    if(backTracking(ticketNum)) return true;
                    res.removeLast();
                    target.setValue(count);
                }
            }
        }
        return false;
    }

    public List<String> findItinerary(List<List<String>> tickets) {
        map = new HashMap<String, Map<String, Integer>>();
        res = new LinkedList<>();
        for(List<String> t : tickets){
            Map<String, Integer> temp;
            if(map.containsKey(t.get(0))){
                temp = map.get(t.get(0));
                temp.put(t.get(1), temp.getOrDefault(t.get(1), 0) + 1);
            }else{
                temp = new TreeMap<>();//升序Map
                temp.put(t.get(1), 1);
            }
            map.put(t.get(0), temp);

        }
        res.add("JFK");
        backTracking(tickets.size());
        return new ArrayList<>(res);
    }
}

遇到的困难

        想了一个多小时,超时问题实在不知道怎么解,hard不愧是hard。

51. N皇后

题目链接:51. N皇后

代码随想录题解:51. N皇后

视频讲解:​​​​​​​这就是传说中的N皇后? 回溯算法安排!| LeetCode:51.N皇后_哔哩哔哩_bilibili

解题思路:

       两眼一麻黑,直接抄答案。

看完代码随想录之后的想法 

        重点还是得把图画出来,理清每一层的思路,才能真正写出来。

        首先来看一下皇后们的约束条件:

  1. 不能同行
  2. 不能同列
  3. 不能同斜线

确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,这里可以抽象为一棵树。

用一个 3 * 3 的棋盘,将搜索过程抽象为一棵树,如图:

51.N皇后

从图中,可以看出,二维矩阵中矩阵的高就是这棵树的高度,矩阵的宽就是树形结构中每一个节点的宽度。

那么我们用皇后们的约束条件,来回溯搜索这棵树,只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了

递归函数参数:定义全局变量二维数组result来记录最终结果,参数n是棋盘的大小,然后用row来记录当前遍历到棋盘的第几层了。

终止条件:当递归到棋盘最底层(也就是叶子节点)的时候,就可以收集结果并返回了,此时row=n

单层搜索的逻辑:递归深度就是row控制棋盘的行,每一层里for循环的col控制棋盘的列,一行一列,确定了放置皇后的位置。每次都是要从新的一行的起始位置开始搜,所以都是从0开始。

验证棋盘是否合法:按照如下标准去重:

  1. 不能同行,这里不需要检查,因为每次递归必然是换新的一行
  2. 不能同列
  3. 不能同斜线 (45度和135度角),这里注意超过180度的对角不用考虑,因为按递归的顺序,大于row的行里面不会有棋子。
class Solution {
	List<List<String>> result = new ArrayList<>();
	List<String> path = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
		char[][] chessboard = new char[n][n];
		for (int i = 0; i < n; i++) {
			Arrays.fill(chessboard[i], '.');
		}
		solveNQueens(n, 0, chessboard);
		return result;
    }
	void solveNQueens(int n, int row, char[][] chessboard) {
		if (row == n) {
			List<String> temp= new ArrayList<>();
			for (int i = 0; i < n; i++) {
				temp.add(String.copyValueOf(chessboard[i]));
			}
			result.add(temp);
			return;
		}
		for (int i = 0; i < n; i++) {
			if (!isValid(chessboard, i, row, n)) continue;
			chessboard[row][i] = 'Q';
			solveNQueens(n, row+1, chessboard);
			chessboard[row][i] = '.';
		}
	}

	boolean isValid(char[][] chessboard, int col, int row, int n) {
		for (int i = 0; i < n; i++) {
			if (chessboard[i][col] == 'Q')
				return false;
		}
		for (int i = 1; col - i >= 0 && row - i >= 0 ; i++) {
			if (chessboard[row - i][col - i] == 'Q')
				return false;
		}
		for (int i = 1; col + i < n && row - i >= 0 ; i++) {
			if (chessboard[row - i][col + i] == 'Q')
				return false;
		}
		return true;
	}
}

遇到的困难

        一开始连N皇后问题的定义都不是很清楚,就抓瞎了,这种特型的二维数组题以后就有参考标准了。

37. 解数独

题目链接:37. 解数独

代码随想录题解:​​​​​​​​​​​​​​37. 解数独

视频讲解:回溯算法二维递归?解数独不过如此!| LeetCode:37. 解数独_哔哩哔哩_bilibili

解题思路:

       见答案,二刷再看

看完代码随想录之后的想法 

        

遇到的困难

        

今日收获

        今天全是hard题,确实很难,二刷再好好看。

回溯总结:

回溯算法能解决如下问题:

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 棋盘问题:N皇后,解数独等等

在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果。

对于组合问题,for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够题目要求的k个元素了,就没有必要搜索了

排列问题与组合的不同:

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了

去重:使用set去重的版本相对于used数组的版本效率都要低很多

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

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

相关文章

c语言--动态内存管理(malloc、realloc、free、calloc)

目录 一、为什么要有动态内存分配二、 malloc和free2.1 malloc 三、 calloc和realloc3.1calloc3.2 realloc 四、常见的动态内存的错误4.1 对NULL指针的解引用操作4.2 对动态开辟空间的越界访问4.3 对非动态开辟内存使用free释放4.4 使用free释放⼀块动态开辟内存的一部分4.5对同…

Midjourney艺术家分享|By Moebius

Moebius&#xff0c;本名让吉拉德&#xff08;Jean Giraud&#xff09;&#xff0c;是一位极具影响力的法国漫画家和插画师&#xff0c;以其独特的科幻和幻想风格而闻名于世。他的艺术作品不仅在漫画领域内受到高度评价&#xff0c;也为电影、时尚和广告等多个领域提供了灵感。…

逆向案例十三(1)——贝壳网登录密码逆向

链接地址&#xff1a;合肥房产网_合肥二手房|租房|新房|房地产信息网【合肥贝壳找房】 点击登录&#xff0c;打开开发者工具&#xff0c;点击账号密码登录&#xff0c;输入错误密码和账号 。找到登录的数据包。打开发现有许多参数加密。数据包是authenticate 再登陆一次看哪些…

分类预测 | Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预测

分类预测 | Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预测 目录 分类预测 | Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现CPO-LSSVM冠豪猪算法优化最小支持向量机数据分类预…

机器学习模型:决策树笔记

第一章&#xff1a;决策树原理 1-决策树算法概述_哔哩哔哩_bilibili 根节点的选择应该用哪个特征&#xff1f;接下来选什么&#xff1f;如何切分&#xff1f; 决策树判断顺序比较重要。可以使用信息增益、信息增益率、 在划分数据集前后信息发生的变化称为信息增益&#xff0c…

MySQL故障排查与优化

一、MySQL故障排查 1.1 故障现象与解决方法 1.1.1 故障1 1.1.2 故障2 1.1.3 故障3 1.1.4 故障4 1.1.5 故障5 1.1.6 故障6 1.1.7 故障7​ 1.1.8 故障8 1.1.9 MySQL 主从故障排查 二、MySQL优化 2.1 硬件方面 2.2 查询优化 一、MySQL故障排查 1.1 故障现象与解决方…

Windows Docker 部署 Firefly III 开源记账软件

一、简介 Firefly III是一款开源的记账软件&#xff0c;支持全球多种语言。它可以帮助用户追踪和管理个人账目、预算和账单&#xff0c;减少支出&#xff0c;节省更多。该软件支持多种货币、银行账户和投资账户&#xff0c;并提供了丰富的报表功能&#xff0c;帮助用户更好地了…

Netty客户端发送数据给服务器的两个通道(1)

EventLoopGroup group new NioEventLoopGroup();// 设置的连接group。 Bootstrap bootstrap new Bootstrap().group(group).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) // 超时时间。 .channel(NioSocketChannel.class).handler(new ChannelInitializer() { Ov…

JVM专题——类文件加载

本文部分内容节选自Java Guide和《深入理解Java虚拟机》, Java Guide地址: https://javaguide.cn/java/jvm/class-loading-process.html &#x1f680; 基础&#xff08;上&#xff09; → &#x1f680; 基础&#xff08;中&#xff09; → &#x1f680;基础&#xff08;下&a…

Makefile:make install的实现(十一)

1、make install的概念 在Linux环境下有些时候软件或者服务会通过源码安装&#xff0c;执行一些make、make install、make clean的指令。例如&#xff1a;redis make&#xff1a;编译所有的文件、生成一些动态库、静态库、可执行程序等等make install&#xff1a;通常会创建一个…

Qt | Qt 框架结构概述

一、Qt 基本框架概述 1、Qt 5 引入了模块化的概念,Qt 5 将实现众多功能的 Qt 库细分为各个模块,也就是说一个模块中包含了实现某种功能的众多 C++类库,比如 Qt GUI 模块用于图形用户界面绘制,该模块中包含了实现 GUI 组件的类库,比如 QFont、QImage、QOpenGL、QWindow 等…

11.python的字典dict(下) 遍历字典,结构优化

11.python的字典dict(下) 遍历所有的键值对 items()方法是字典的一个内置方法&#xff0c;用于返回字典中所有键值对的视图&#xff08;view&#xff09;。它返回一个可迭代的对象&#xff0c;每个元素都是一个包含键和对应值的元组。 下面用一个例子来说明items()方法的用法…

闻风丧胆的算法(二)

&#x1f308;个人主页&#xff1a;Rookie Maker &#x1f525; 系列专栏&#xff1a;算法 &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于IT的优质内容&#xff01;&#x1f3c6;&#x1f3c6; &#x1f600;欢迎来到小田代码世界~ &#x1f601; 喜欢的小…

第十二届通信和宽带网络国际会议(ICCBN 2024)即将召开!

2024年第十二届通信和宽带网络国际会议将于2024年7月25日至27日在西藏林芝举行会议涵盖的议题广泛多样&#xff0c;包括但不限于&#xff1a;5G、6G技术与应用&#xff0c;宽带网络架构和优化&#xff0c;物联网与智能连接&#xff0c;人工智能在通信领域的应用&#xff0c;数据…

C++ 标准库类型stackqueue

C/C总述&#xff1a;Study C/C-CSDN博客 栈与队列详解&#xff08;数据结构&#xff09;&#xff1a;栈与队列_禊月初三-CSDN博客 stack&#xff08;栈&#xff09; stack的常用函数 函数说明功能说明stack()构造空栈push(T& val)将元素val压入栈中size()返回栈中元素个…

蓝桥杯算法题:区间移位

题目描述 数轴上有n个闭区间&#xff1a;D1,...,Dn。 其中区间Di用一对整数[ai, bi]来描述&#xff0c;满足ai < bi。 已知这些区间的长度之和至少有10000。 所以&#xff0c;通过适当的移动这些区间&#xff0c;你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 100…

【数据结构(一)】初识数据结构

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你学更多数据结构知识 目录 1.前言2.集合架构3.时间和空间复杂度3.1算法效率3.2时间复杂度3.2.1大O的渐进…

Unity类银河恶魔城学习记录12-4 p126 Item Tooltip源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI.cs using System.Collections; using System.Collections.Generic; usi…

AD20全流程的使用笔记

目录 首先一个完整的AD工程文件需要我们自己建立的文件有这些&#xff1a; 新建工程&#xff1a; 从现有的工程文件中将元件添加到原理图库&#xff1a; 元件的摆放&#xff1a; 器件的复制及对齐&#xff1a; 导线、Netlabe、端口的添加&#xff1a; Value值的校对&…

每日一练 寻找两个正序数组的中间数

题目参上&#xff0c;以下是解题思路&#xff1a; 首先&#xff0c;我们应该想到的一种方法是把两数组合并为一个整体的数组&#xff0c;然后返回其中位数即可。那么我们如何合并两数组呢&#xff1f;我们可以用归并排序&#xff0c;设置上下两指针&#xff0c;不断遍历返回较…