【华为OD机考B卷 | 100分】五子棋迷(JAVA题解——也许是全网最详)

前言

本人是算法小白,甚至也没有做过Leetcode。所以,我相信【同为菜鸡的我更能理解作为菜鸡的你们的痛点】。

题干

1. 题目描述

张兵和王武是五子棋迷,工作之余经常切磋棋艺。走了一会儿,轮到张兵了,他对着一条线思考起来了,这条线上的棋子分布如下:
用数组表示:-1 0 1 1 1 0 1 0 1 -1
棋子分布说明:

  1. -1代表白子,0代表空位,1代表黑子:
  2. 数组长度L,满足1<L<40,且L为奇数:

请帮他写一个程序,算出最有利的出子位置。最有利定义如下:

  1. 找到一个空位(0),用棋子(1/-1)填充该位置,可以使得当前子的最大连续长度变大;
  2. 如果存在多个位置,返回最靠近中间的较小的那个坐标;
  3. 如果不存在可行位置,直接返回-1;
  4. 连续长度不能超过5个(五子棋约束);

2. 输入描述

第一行:当前出子颜色
第二行:当前的棋局状态

3. 输出描述

一个整数,表示出子位置的数组下标

4. 示例

示例1:
输入:

1
-1 0 1 1 1 0 1 0 1 -1 1

输出:

5

说明:当前为黑子(1),放置在下表为5的位置,黑子的最大连续长度由3->5,所以满足条件

示例2:
输入:

-1
-1 0 1 1 1 0 1 0 1 -1 1

输出:

1

说明:当前为白子(-1),唯一可以防止的位置下标为1,婊子的最大长度由1->2,所以满足条件

示例3:
输入:

1
0 0 0 0 1 0 0 0 0 1 0

输出:

5

说明:可行的位置很多,但是5是最接近中间的位置坐标

解答

遇到的问题

这题整体难度不是很大,但还是遇到了一些问题。

  1. 如何从控制台输入一个变长的数组(哈,确实不会,没怎么用过Scanner
  2. 在实现过程中,其实我还发现,输入多行、不定长数据还存在无法停止输入的情况(只能通过输入非目标类型数据来停止,但我希望的是【回车】停止)
  3. 虽然脑海里大概能想到一个暴力解题办法,但总觉得怪怪的,应该有更好的方式才对

解题思路

暴力解题版:
根据题目给出的条件,做出如下思考:

  1. 新增一个方法,用来寻找【下一个空位】。由于是下一个,所以需要一个检索的起始点
  2. 新增一个方法,用来获取当前数组的中间位置的下标(其实可以不新增一个方法,单纯是个人喜欢这么做,我比较追求语义清晰跟代码可读性)
  3. 新增一个方法,用来计算给定线上棋子的【最大连续长度】
  4. 整体思路是,循环遍历每一个可以下子的点,然后记录当前点的位置,以及最大连续长度,还有距离中心点的位置。接着判断最大连续长度是否变大且<5。最后比较距离中心点的位置是否更近了

但我看了网上答案之后,发现了更好的解题方法。那就是【滑动窗口法】,这应该才是本题真正的考点。
滑动窗口法:

  1. 滑动窗口在这里的应用,主要是在求落子后新的最大连续长度。而且这个滑动起点跟终点,不是从0开始,而是从引起变化的【落子节点】开始。怎么理解?这个我们在代码解读中给大家解释一下。

滑动窗口示意图:(随着起点、终点变化,[start, end]区间也在变化)
在这里插入图片描述

代码示例

暴力破解版:但其实我不推荐,我贴出来完全是因为这是我个人自己的努力,所以为了鼓励自己就贴上,哈哈

public class FiveInRow {/*** 白棋*/static final int WHITE_CHESS = -1;/*** 黑棋*/static final int BLACK_CHESS = 1;/*** 空白*/static final int BLANK_SPACE = 0;/*** 最大连续长度*/static final int MAX_CONTINOUS_LENGTH = 5;/*** 数组长度*/static final int MAX_LENGTH = 40;public static void main(String[] args) {// 数据准备Scanner scanner = new Scanner(System.in);int currChess = scanner.nextInt();scanner.nextLine();String nextLine = scanner.nextLine();String[] nums = nextLine.split(" ");List<Integer> chesses = new ArrayList<>();for (String num : nums) {chesses.add(Integer.parseInt(num));}// 获取最有利下子位置int bestPlace = getBestPlace(currChess, chesses);System.out.println("最佳下子位置:" + bestPlace);}/*** 找到最有利的位置** @param currChess 当前棋子颜色* @param chesses   一条线上棋子分布* @return -1-找不到可以下的位置;其他-最有利下棋处*/private static int getBestPlace(int currChess, List<Integer> chesses) {int bestPlace = -1;// 获取当前连续长度int currContinuous = getCurrContinuous(currChess, chesses);int midLocation = getMidLocation(chesses.size());// 获取下一个空白点int nearest = 99;int start = 0;int nextBlankPlace = getNextBlankPlace(start, chesses);while (nextBlankPlace != -1) {List<Integer> newChesses = new ArrayList<>(chesses);newChesses.set(nextBlankPlace, currChess);int newCurrContinuous = getCurrContinuous(currChess, newChesses);if (newCurrContinuous > currContinuous && newCurrContinuous <= MAX_CONTINOUS_LENGTH) {int interval = Math.abs(nextBlankPlace - midLocation);if (interval < nearest) {bestPlace = nextBlankPlace;nearest = interval;}}start = nextBlankPlace + 1;nextBlankPlace = getNextBlankPlace(start, chesses);}return bestPlace;}/*** 获取当前连续度** @param currChess 当前棋子颜色* @param chesses   一条线上棋子分布* @return 当前连续长度*/private static int getCurrContinuous(int currChess, List<Integer> chesses) {// 当前棋局下最大连续长度int curMaxConsecutive = 0;// 当前连续长度int consecutiveCount = 0;for (int i = 0; i < chesses.size(); ++i) {if (chesses.get(i) == currChess) {consecutiveCount += 1;} else {consecutiveCount = 0;}curMaxConsecutive = Math.max(curMaxConsecutive, consecutiveCount);}return curMaxConsecutive;}/*** 从指定位置开始检索空白位置** @param start   开始检索位置* @param chesses 一条线上棋子分布* @return 下一个空白位置*/private static int getNextBlankPlace(int start, List<Integer> chesses) {if (start >= chesses.size()) {return -1;}for (int i = start; i < chesses.size(); i++) {Integer chess = chesses.get(i);if (chess == BLANK_SPACE) {return i;}}return -1;}/*** 获取中间位置的索引** @param length 数组长度* @return 中间位置的索引*/private static int getMidLocation(int length) {return length / 2;}
}

代码解读:整体来说我还是按照了解题思路完成的

  1. 多行不定长输入,我是这么完成的。我也不是很理解为什么,没有细看API源码
        // 数据准备Scanner scanner = new Scanner(System.in);int currChess = scanner.nextInt();scanner.nextLine();String nextLine = scanner.nextLine();String[] nums = nextLine.split(" ");List<Integer> chesses = new ArrayList<>();for (String num : nums) {chesses.add(Integer.parseInt(num));}

滑动窗口法:(推荐版本)
新增一个方法getBestPlaceUsingSlidingWindows替换旧方法getBestPlace

 /*** 找到最有利的位置,滑动窗口法** @param currChess 当前棋子颜色* @param chesses   一条线上棋子分布* @return -1-找不到可以下的位置;其他-最有利下棋处*/private static int getBestPlaceUsingSlidingWindows(int currChess, List<Integer> chesses) {int bestPlace = -1;// 获取当前连续长度int currContinuous = getCurrContinuous(currChess, chesses);int midLocation = getMidLocation(chesses.size());// 获取下一个空白点int nearest = 99;for (int i = 0; i < chesses.size(); i++) {Integer chess = chesses.get(i);if (chess != BLANK_SPACE) {continue;}int start = i - 1, end = i + 1;// 确定窗口真实起点while (start >= 0 && chesses.get(start).equals(currChess)) {start--;}// 确定窗口真实终点while (end < chesses.size() && chesses.get(end).equals(currChess)) {end++;}// 由于是开区间(不包含区间范围的两个节点),所以需要-1int newCurrContinuous = end - start - 1;if (newCurrContinuous > currContinuous && newCurrContinuous <= MAX_CONTINOUS_LENGTH) {int interval = Math.abs(i - midLocation);if (interval < nearest) {bestPlace = i;nearest = interval;}}}return bestPlace;}

我们解释回解题思路中,所谓【滑动起点跟终点,不是从0开始,而是从引起变化的【落子节点】开始】这段话,我们结合示例3看看,不知道大家发现没有,假设我们落子在0/1/2下标处,再求它的新的最大连续度的时候,其实真正引起连续度变化的点,就是我们落子开始的点。

例如:示例3,落子在2处
0 0 0 0 1 0 0 0 0 1 0(落子前)
0 0 1 0 1 0 0 0 0 1 0(落子后)
看,如果使用暴力解题的方法,还是会去遍历0/1坐标,有必要吗?其实可以不需要的

代码解读:滑动窗口在这里的应用,重点是里面的两个while循环,这里就不过多解释了

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

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

相关文章

leetcode 每日一题复盘(10.9~10.15)

leetcode 101 对称二叉树 这道题一开始想是用层序遍历,看每一层是否都对称,遇到一个问题就是空指针(子树为空)无法记录下来,同时会导致操作空指针的问题,因此需要修改入队条件,并用一个标志去表示空指针 vector<int>numv;for(int i0;i<size;i){TreeNode*frontque.fro…

2023年中国香樟木家具行业分析:定制化和个性化的需求不断增加[图]

香樟木是一种常见的木材&#xff0c;它在家具行业中被广泛使用。香樟木家具行业定义是指使用香樟木材料制造的家具产品的生产、销售和相关业务活动。 香樟木家具行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 香樟木家具的生产主要集中在少数大型…

(一)Apache log4net™ 手册 - 介绍

0、相关概念 Log4j 几乎每个大型应用程序都包含自己的日志记录或跟踪 API。根据这一规则&#xff0c;E.U. SEMPER &#x1f339;项目决定编写自己的跟踪 API。那是在 1996 年初。经过无数次的增强、几个化身和大量的工作&#xff0c;API 已经发展成为 log4j —— 一个流行的 Ja…

word重复上次操作的快捷键的F4没效果了

word重复上次操作的快捷键的F4没效果了 word编辑文档的时候&#xff0c;以前都是用F4快捷键解决重复上次操作的&#xff0c;或者ctrly&#xff0c;现在没效果了&#xff0c;在哪里设置回去呢&#xff1f;也没开什么软件不存在快捷键冲突的&#xff0c;F4键也没坏。咋弄哦&…

redis分布式秒杀锁

-- 获取锁标识&#xff0c;是否与当前线程一致&#xff1f; if(redis.call(get, KEYS[1]) ARGV[1]) then-- 一致&#xff0c;删除return redis.call(del, KEYS[1]) end -- 不一致&#xff0c;直接返回 return 0package com.platform.lock;public interface ILock {/*** 获取锁…

Avalonia环境搭建

1.开发文档 开发文档&#xff0c; GitHub项目地址 https://github.com/avaloniaui/avalonia 2.VS2022 及扩展安装 建议使用vs2022最新版本下载并安装扩展Avalonia for Visual Studio 2022 3.安装Avalonia UI模板 dotnet new install Avalonia.Templates 查看安装版本 dot…

【MyBatis】MyBatis 详解

MyBatis 详解 一. MyBatis 是什么二. MyBatis 在整个框架中的定位三. MyBatis 的操作1. 先创建好数据库和表2. 添加MyBatis框架⽀持3. 修改配置文件4. 添加业务代码5. 增、删、改操作① 增加⽤户② 修改用户操作③ 删除操作 6. 查询操作① 单表查询② 多表查询 一. MyBatis 是什…

Mojo 正式发布,Rust 能否与之匹敌?

9 月 7 日&#xff0c;Modular 公司宣布正式发布 Mojo&#xff1a;Mojo 现在已经开放本地下载——初步登陆 Linux 系统&#xff0c;并将很快提供 Mac 与 Windows 版本。据介绍&#xff0c;Mojo 最初的目标是比 Python 快 35000 倍&#xff0c;近日该团队表示&#xff0c;Mojo 将…

设计模式 - 观察者模式

目录 一. 前言 二. 实现 三. 优缺点 一. 前言 观察者模式属于行为型模式。在程序设计中&#xff0c;观察者模式通常由两个对象组成&#xff1a;观察者和被观察者。当被观察者状态发生改变时&#xff0c;它会通知所有的观察者对象&#xff0c;使他们能够及时做出响应&#xf…

基于Dockerfile创建镜像

基于现有镜像创建 1.首先启动一个镜像&#xff0c;在容器里做修改 docker create -it centos:7 /bin/bash #常用选项&#xff1a; -m 说明信息&#xff1b; -a 作者信息&#xff1b; -p 生成过程中停止容器的运行。 2.然后将修改后的容器提交为新的镜像&#xff0c;需要使用…

基于SSM+Vue的学习交流论坛的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

用delphi7将excel导入access并查询及其分析(一)

开发环境&#xff1a;win7 64&#xff08;win10 64&#xff09;两个系统环境&#xff0c;delphi7。 一、安装delphi7&#xff08;已经放在阿里云盘的soft中&#xff09; 解压安装&#xff0c;文件夹里自带SN.txt。直接默认路径安装&#xff08;关系到后续的控件安装时方便&…

Hive窗口函数回顾

1.语法 1.1 基于行的窗口函数 Hive的窗口函数分为两种类型&#xff0c;一种是基于行的窗口函数&#xff0c;即将某个字段的多行限定为一个范围&#xff0c;对范围内的字段值进行计算&#xff0c;最后将形成的字段拼接在该表上。 注意&#xff1a;在进行窗口函数计算之前&#…

不用休眠的 Kotlin 并发:深入对比 delay() 和 sleep()

本文翻译自&#xff1a; https://blog.shreyaspatil.dev/sleepless-concurrency-delay-vs-threadsleep 毫无疑问&#xff0c;Kotlin 语言中的协程 Coroutine 极大地帮助了开发者更加容易地处理异步编程。该特性中封装的诸多高效 API&#xff0c;可以确保开发者花费更小的精力去…

Mysql--内置函数

字符串函数 1、拼接字符串 concat(str1,str2...) select concat(12,34,abccc) select CONCAT(name,的家乡是,hometown) from students 2、包含字符个数 length(abc) 注&#xff1a;一个中文占3个字符&#xff0c;一个字母或数字占1个字符 3、截取字符串 left(str,len)返回字…

Elasticsearch:使用 huggingface 模型的 NLP 文本搜索

本博文使用由 Elastic 博客 title 组成的简单数据集在 Elasticsearch 中实现 NLP 文本搜索。你将为博客文档建立索引&#xff0c;并使用摄取管道生成文本嵌入。 通过使用 NLP 模型&#xff0c;你将使用自然语言在博客文档上查询文档。 安装 Elasticsearch 及 Kibana 如果你还没…

计算机竞赛 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

Safran与是德科技合作为蔚来提供电动汽车中的5G和C-V2X连接测试

概述 虹科Safran GNSS模拟器助力是德科技&#xff08;Keysight&#xff09;为中国顶级电动汽车制造商之一——蔚来汽车&#xff08;NIO&#xff09;提供了业界领先的UXM 5G测试解决方案以验证5G和C-V2X的连接性&#xff0c;能够根据3GPP和其他标准组织定义的最新5G新无线电&am…

解决扬声器异常

之前使用的是PulseAudio PulseAudio 是默认的音频服务器和音频框架&#xff0c;因此大多数应用程序通过 PulseAudio 来处理音频 但也有一些应用程序直接使用 ALSA&#xff08;Advanced Linux Sound Architecture&#xff09;来与音频硬件交互。在这些情况下&#xff0c;ALSA …

深入理解计算机系统(1):系统组成

一、系统硬件组成 1、控制器&#xff08;CPU&#xff09;&#xff1a;解释和执行内存中的指令 &#xff08;1&#xff09;、控制器 程序控制器&#xff1a;指令指针&#xff0c;指向主存中的机器语言指令&#xff0c;为一个字大小的存储设备或寄存器。 指令寄存器、指令译码器、…