【左神算法刷题班】第18节:汉诺塔问题、岛屿问题、最大路径和问题

第18节

题目1:汉诺塔问题(变体)

体系学习班18节有讲暴力递归的汉诺塔原题。

给定一个数组arr,长度为N,arr中的值只有1,2,3三种

arr[i] == 1,代表汉诺塔问题中,从上往下第i个圆盘目前在左

arr[i] == 2,代表汉诺塔问题中,从上往下第i个圆盘目前在中

arr[i] == 3,代表汉诺塔问题中,从上往下第i个圆盘目前在右

那么arr整体就代表汉诺塔游戏过程中的一个状况

如果这个状况不是汉诺塔最优解运动过程中的状况,返回-1

如果这个状况是汉诺塔最优解运动过程中的状况,返回它是第几个状况(而不是还剩几个状况)

思路

对于传统的汉诺塔问题,如果我要将 123456 从最左边的柱子上移动到最右边的柱子上,需要分成三大步:

  1. 【第一大步】将 12345 从左边的柱子移动到中间的位置
  2. 【第二大步】将 6 从左边的柱子移动到右边的位置
  3. 【第三大步】将 12345 从中间的位置移动到右边的位置

上述传统问题的解法是,定义递归函数 f(i, from, to, other),表示将 [0~i] 的圆盘从 from 柱子移动到 to 柱子上,另外那个柱子叫 other。

对于本题,需要明确一下题意,有几个已知条件:

  1. 汉诺塔问题,最优解是唯一的路径。
  2. 题目中给的过程状态,如果不在唯一路径上,就返回-1。
  3. 举个极端的例子,1层汉诺塔问题,把1从最左边的柱子上移动到最右边的柱子上,只要一步就可以了。而”1在中间这个柱子上“这个状态,就是一个不在最优解路径上的例子。

本题的解法是,定义递归函数int step(int[] arr, int i, int from, int to, int other),表示当前来到 arr 状态下,将 [0~i] 的圆盘从 from 柱子移动到 to 柱子上,另外那个柱子叫 other,返回至少需要几步。

public static int kth(int[] arr) {int N = arr.length;return step(arr, N - 1, 1, 3, 2);
}// 我的疑问:arr为什么全程不更新?
// 自问自答:因为返回它当前走到了第几个状况,而不是还剩几个状况。
public static int step(int[] arr, int index, int from, int to, int other) {if (index == -1) {return 0;}if (arr[index] == other) { // 最大的数字只可能在from或者to的底部,不可能在other上return -1;}// arr[index]的值,剩下两种情况:// 情况1:arr[index] == from// 情况2:arr[index] == toif (arr[index] == from) { // 情况1:如果index号圆盘还在from上,说明上述连【第一大步】都没走完// 因为我只想知道当前已经走过多少步了,所以只要统计在【第一大步】中走了多少步就可以了,后面的【第二大步】【第三大步】肯定根本没走// 怎么统计呢?我们知道【第一大步】的目标是将[0~i-1]从from挪到other上,而且当前已经走到arr状态了,所以就这样继续递归return step(arr, index - 1, from, other, to);} else { // 情况2:如果index号圆盘已经在to上了,说明已经完成[0~index-1]的汉诺塔问题了// 【第一大步】已经完成的从[0~index-1]范围上的index层汉诺塔问题需要的步骤数(n层汉诺塔,最优解2^n-1步)int p1 = (1 << index) - 1; // 【第二大步】已经将index号圆盘从from挪到to了,因为我们从arr中看到index号圆盘已经在to上了int p2 = 1; // 【第三大步】当前正在经历的,将[0~i-1]号圆盘从other挪到to上,在arr状态下,统计已经走过多少步了?int p3 = step(arr, index - 1, other, to, from); // 如果发现它的子问题根本就不是最优解的某一步,直接返回-1if (p3 == -1) { return -1;}return p1 + p2 + p3;}
}
image-20230814002726237

题目2:两个岛屿的距离,“感染”问题

Leetcode 原题:

https://leetcode.com/problems/shortest-bridge/

我在力扣上的自己写的答案:

class Solution {int m, n;public static final int offset = 100;public int shortestBridge(int[][] grid) {m = grid.length;n = grid[0].length;// 将其中一个岛A加offset,用来区分两个岛label:for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == 1) {incr(grid, i, j);break label; // 中断所有循环,回到label处,但并不重新进入循环}}}// 左上角主动感染,右下角原地不动int term = offset;while (true) {boolean[][] seen = new boolean[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == term && !seen[i][j]) {int result = process(grid, i, j, term, seen);if (result != Integer.MAX_VALUE) return result - offset;}}}term++;}}// 当前岛屿向外感染public int process(int[][] grid, int i, int j, int term, boolean[][] seen) {int result = Integer.MAX_VALUE;if (i < 0 || i == m || j < 0 || j == n || seen[i][j]) return result; // 越界,或重复路线seen[i][j] = true;if (grid[i][j] == 0) { // 当前位置未感染,则感染grid[i][j] = term + 1;} else if (grid[i][j] == term) { // 当前位置是感染源,则去感染周围result = Math.min(result, process(grid, i + 1, j, term, seen));result = Math.min(result, process(grid, i - 1, j, term, seen));result = Math.min(result, process(grid, i, j + 1, term, seen));result = Math.min(result, process(grid, i, j - 1, term, seen));} else if (grid[i][j] == 1) { // 两岛接壤,则快速返回return term;}return result;}// 给其中一个岛加offsetpublic void incr(int[][] grid, int i, int j) {if (i < 0 || i == m || j < 0 || j == n) return;if (grid[i][j] == 1) {grid[i][j] = offset;incr(grid, i + 1, j);incr(grid, i - 1, j);incr(grid, i, j + 1);incr(grid, i, j - 1);}}
}

题目3:最大路径和

牛客网原题:

https://www.nowcoder.com/questionTerminal/8ecfe02124674e908b2aae65aad4efdf

给定一个矩阵matrix,先从左上角开始,每一步只能往右或者往下走,走到右下角。然后从右下角出发,每一步只能往上或者往左走,再回到左上角。任何一个位置的数字,只能获得一遍。返回最大路径和。

输入描述
第一行输入两个整数M和N,M,N<=200
接下来M行,每行N个整数,表示矩阵中元素5 10
1 1 1 1 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 1
1 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 1 1 1 1
输出描述
输出一个整数,表示最大路径和16
思路

第一次见到这题,是在体系学习班第14节。当时只讲了不能贪心,应该用dp,但没有细说。

黄色部分表示我想要拿到的位置:

在这里插入图片描述

错误的贪心路径

少拿一个灰色的格子。
在这里插入图片描述

正确的路径

最好情况下,能够拿到所有的格子。

在这里插入图片描述

虽然题目要求是一来一回,但我们可以想象成有两个人 a、b,都从左上角走到右下角,求整个过程中,最多能拿到多少值。

内存超限版本如下。其实可以省掉一个维度就不会超了,因为(i1, j1), (i2, j2) 两个坐标中,存在关系:i1+j1=i2+j2。可变参数数量能省则省!

import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {static int[][] arr;public static void main(String[] args) {Scanner in = new Scanner(System.in);int m = in.nextInt();int n = in.nextInt();arr = new int[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {arr[i][j] = in.nextInt();}}int[][][][] dp = new int[m][n][m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {for (int k = 0; k < m; k++) {for (int l = 0; l < n; l++) {dp[i][j][k][l] = -1;}}}}int res = process(0, 0, 0, 0, dp);System.out.println(res);}// 当前a在i1,j1位置,b在i2,j2位置// 两个人都只能向右走或者向下走,求能拿到的最多点数public static int process(int i1, int j1, int i2, int j2, int[][][][] dp) {if (i1 == arr.length || j1 == arr[0].length) return 0;if (i2 == arr.length || j2 == arr[0].length) return 0;if (dp[i1][j1][i2][j2] >= 0) return dp[i1][j1][i2][j2];// a,b如果走到了同一个位置,点数只能累加一次int res = arr[i1][j1];if (i1 != i2 && j1 != j2) res += arr[i2][j2];// a向右,b向右int p1 = process(i1 + 1, j1, i2 + 1, j2, dp);// a向下,b向下int p2 = process(i1, j1 + 1, i2, j2 + 1, dp);// a向右,b向下int p3 = process(i1, j1 + 1, i2 + 1, j2, dp);// a向下,b向右int p4 = process(i1 + 1, j1, i2, j2 + 1, dp);res += Math.max(Math.max(p1, p2), Math.max(p3, p4));dp[i1][j1][i2][j2] = res;return res;}
}
/*5 10
1 1 1 1 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 1
1 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 1 1 1 12 2
1 1
1 1*/

题目4

牛客网原题:

https://www.nowcoder.com/practice/7201cacf73e7495aa5f88b223bbbf6d1

给定两个有序数组arr1和arr2,再给定一个整数k,你可以从来自arr1和arr2的两个数各选一个数,返回相加和最大的前k个。

思路

不能用双指针从最右边开始往左滑动,因为这样会丢失本来可以重复使用的数字。

正确的方法是用大根堆。

当从大根堆拿走一个元素之后,将表格中在它左边和上边的元素,加入大根堆。

在这里插入图片描述

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

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

相关文章

主从同步介绍、主从同步原理、主从同步结构、构建思路、配置一主一从、配置一主多从、读写分离介绍、工作原理、配置mycat服务、添加数据源、创建集群、指定主机角

Top NSD DBA DAY07 案例1&#xff1a;MySQL一主一从案例2&#xff1a;配置一主多从结构案例3&#xff1a;数据读写分离 1 案例1&#xff1a;MySQL一主一从 1.1 问题 数据库服务器192.168.88.53配置为主数据库服务器数据库服务器192.168.88.54配置为从数据库服务器客户端192…

网络编程(8.14)TCP并发服务器模型

作业&#xff1a; 1. 多线程中的newfd&#xff0c;能否修改成全局&#xff0c;不行&#xff0c;为什么&#xff1f; 2. 多线程中分支线程的newfd能否不另存&#xff0c;直接用指针间接访问主线程中的newfd,不行&#xff0c;为什么&#xff1f; 多线程并发服务器模型原代码&…

排查docker无法启动问题

查看Linux系统操作日志(最后200行就可以排查)&#xff1a; tail -200f /var/log/messages

数据分析--帆软报表--大数据大屏

进入国企公司学习有一段时间了&#xff0c;岗位是数据分析方向------ 母前使用的是帆软工具进行的开发。 可以进行大数据大屏 也可使嵌入到手机端。 下面是例子

Python-OpenCV中的图像处理-GrabCut算法交互式前景提取

Python-OpenCV中的图像处理-GrabCut算法交互式前景提取 Python-OpenCV中的图像处理-GrabCut算法交互式前景提取 Python-OpenCV中的图像处理-GrabCut算法交互式前景提取 cv2.grabCut(img: Mat, mask: typing.Optional[Mat], rect, bgdModel, fgdModel, iterCount, mode…) img…

【Apple】Logic Pro导入7.1.4.wav并自动分析多声道

Step1: 创建空项目 Step2: 选中下图“使用麦克风或...”这一项&#xff0c;底下要创建的轨道数填1就行。 点击创建之后&#xff1a; Step3: 拖动文件、拖动文件、拖动文件到项目中&#xff0c;并选中复选框“所有所选文件都源自一个项目&#xff08;将创建一个智能速度多轨道集…

[NLP]LLM 训练时GPU显存耗用量估计

以LLM中最常见的Adam fp16混合精度训练为例&#xff0c;分析其显存占用有以下四个部分&#xff1a; GPT-2含有1.5B个参数&#xff0c;如果用fp16格式&#xff0c;只需要1.5G*2Byte3GB显存, 但是模型状态实际上需要耗费1.5B*1624GB. 比如说有一个模型参数量是1M&#xff0c;在…

什么是前端框架?怎么学习? - 易智编译EaseEditing

前端框架是一种用于开发Web应用程序界面的工具集合&#xff0c;它提供了一系列预定义的代码和结构&#xff0c;以简化开发过程并提高效率。 前端框架通常包括HTML、CSS和JavaScript的库和工具&#xff0c;用于构建交互式、动态和响应式的用户界面。 学习前端框架可以让您更高效…

nginx的负载均衡

nginx的负载均衡 文章目录 nginx的负载均衡1.以多台虚拟机作服务器1.1 在不同的虚拟机上安装httpd服务1.2 在不同虚拟机所构建的服务端的默认路径下创建不同标识的文件1.3 使用windows本机的浏览器分别访问3台服务器的地址 2.在新的一台虚拟机上配置nginx实现反向代理以及负载均…

使用element UI 的el-upload上传图片并携带参数的用法

直接看代码&#xff1a;前端实现 <div class"upload"><el-uploadclass"upload-demo"name"upload_name":data"{user_name:user_name}"action"http://localhost:8000/api/deal_pest_Image":show-file-list"fal…

01|Java中常见错误或不清楚

补充&#xff1a;length vs length() vs size() 1 java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性. 2 java中的length()方法是针对字符串String说的,如果想看这个字符串的长度则用到length()这个方法. 3.java中的siz…

【Vue-Router】命名视图

命名视图 同时 (同级) 展示多个视图&#xff0c;而不是嵌套展示&#xff0c;例如创建一个布局&#xff0c;有 sidebar (侧导航) 和 main (主内容) 两个视图&#xff0c;这个时候命名视图就派上用场了。 可以在界面中拥有多个单独命名的视图&#xff0c;而不是只有一个单独的出…

Python获取、修改主机名称和IP地址实践

Python获取、修改主机名称和IP地址的方法有多种&#xff0c;内置socket模块、执行系统命令、第三方模块等等&#xff0c;本文只是完成功能的一次成功的实践。 1. 获取、修改主机名称 本案例使用python的socket模块获取、修改主机名称&#xff0c;socket模块是一个用于实现网络…

UML-A 卷-知识考卷

UML-A 卷-知识考卷 UML有多少种图&#xff0c;请列出每种图的名字&#xff1a; 常用的几种UML图&#xff1a; 类图&#xff08;Class Diagram&#xff09;&#xff1a;类图是描述类、接口、关联关系和继承关系的图形化表示。它展示了系统中各个类之间的静态结构和关系。时序…

TFRecords详解

内容目录 TFRecords 是什么序列化(Serialization)tf.data 图像序列化&#xff08;Serializing Images)tf.Example函数封装 小结 TFRecords 是什么 TPU拥有八个核心&#xff0c;充当八个独立的工作单元。我们可以通过将数据集分成多个文件或分片&#xff08;shards&#xff09;…

2023年7月京东洗衣机行业品牌销售排行榜(京东数据分析软件)

2023年上半年&#xff0c;洗衣机市场表现平淡&#xff0c;同环比来看出货量都有一定程度的下滑。7月份&#xff0c;洗衣机市场仍未改变这一下滑态势。 根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;7月份&#xff0c;京东平台洗衣机的销量为109万&#xff0c;环比下降…

web图书管理系统Servlet+JSP+javabean+MySQL图书商城图书馆 源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 web图书管理系统ServletJSPjavabeanMySQL 系统有1权限…

ChatGPT能代替搜索引擎吗?ChatGPT和搜索引擎有什么区别?

ChatGPT和搜索引擎是两种在信息获取和交流中常用的工具&#xff0c;ChatGPT是一种基于人工智能技术的聊天机器人&#xff0c;而搜索引擎是一种在互联网上搜索信息的工具。尽管它们都是依托互联网与信息获取和交流有关&#xff0c;部分功能重合&#xff0c;但在很多方面存在着明…

2023年7月京东美妆护肤品小样行业数据分析(京东数据挖掘)

如今&#xff0c;消费者更加谨慎&#xff0c;消费决策也更加理性。在这一消费环境下&#xff0c;美妆护肤市场中&#xff0c;面对动辄几百上千的化妆品&#xff0c;小样或体验装无疑能够降低消费者的试错成本。由此&#xff0c;这门生意也一直备受关注。 并且&#xff0c;小样…

交融动画学习

学习抖音&#xff1a; 渡一前端教科频道 利用 filter 的属性实现交融效果 变成 让后利用这个效果实现一个功能 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><style>* {margin: 0;…