首页 > 其他分享 >LeetCode题练习与总结:火柴拼正方形--473

LeetCode题练习与总结:火柴拼正方形--473

时间:2024-12-16 15:32:20浏览次数:14  
标签:正方形 -- matchsticks 473 int edges 数组 火柴 LeetCode

一、题目描述

你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。

如果你能使这个正方形,则返回 true ,否则返回 false 。

示例 1:

输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。

示例 2:

输入: matchsticks = [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。

提示:

  • 1 <= matchsticks.length <= 15
  • 1 <= matchsticks[i] <= 10^8

二、解题思路

  1. 首先计算所有火柴棒的总长度,如果总长度不能被4整除,则直接返回false,因为无法拼成正方形。
  2. 确定正方形的边长,即总长度除以4。
  3. 将火柴棒数组从大到小排序,这样可以优先使用较长的火柴棒,减少搜索空间。
  4. 使用深度优先搜索(DFS)来尝试将火柴棒拼成正方形的四条边。每次尝试将一根火柴棒放入一条边,如果当前边加上这根火柴棒超过边长,则回溯到上一步,尝试其他火柴棒。
  5. 如果所有火柴棒都能放入四条边中,且每条边的长度等于正方形的边长,则返回true,否则返回false。

三、具体代码

import java.util.Arrays;

class Solution {
    public boolean makesquare(int[] matchsticks) {
        // 计算所有火柴棒的总长度
        int totalLength = 0;
        for (int length : matchsticks) {
            totalLength += length;
        }
        
        // 如果总长度不能被4整除,则无法拼成正方形
        if (totalLength % 4 != 0) {
            return false;
        }
        
        // 确定正方形的边长
        int sideLength = totalLength / 4;
        
        // 将火柴棒数组从大到小排序
        Arrays.sort(matchsticks);
        reverse(matchsticks);
        
        // 初始化四条边的长度
        int[] edges = new int[4];
        
        // 使用深度优先搜索尝试拼成正方形
        return dfs(matchsticks, edges, sideLength, 0);
    }
    
    // 深度优先搜索
    private boolean dfs(int[] matchsticks, int[] edges, int sideLength, int index) {
        // 如果所有火柴棒都尝试过了,检查四条边的长度是否相等
        if (index == matchsticks.length) {
            return edges[0] == sideLength && edges[1] == sideLength && edges[2] == sideLength && edges[3] == sideLength;
        }
        
        // 尝试将当前火柴棒放入四条边中的任意一条
        for (int i = 0; i < 4; i++) {
            // 如果当前边加上这根火柴棒超过边长,或者这根火柴棒和上一根相同且上一根放入该边失败,则跳过
            if (edges[i] + matchsticks[index] > sideLength || (i > 0 && edges[i] == edges[i - 1])) {
                continue;
            }
            
            // 将火柴棒放入当前边
            edges[i] += matchsticks[index];
            
            // 递归尝试下一根火柴棒
            if (dfs(matchsticks, edges, sideLength, index + 1)) {
                return true;
            }
            
            // 回溯,移除火柴棒
            edges[i] -= matchsticks[index];
        }
        
        // 所有边都无法放入当前火柴棒,返回false
        return false;
    }
    
    // 反转数组
    private void reverse(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            left++;
            right--;
        }
    }
}

这段代码首先计算火柴棒的总长度,然后进行排序和深度优先搜索,最后检查是否能拼成正方形。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 计算火柴棒总长度:O(n),其中n是火柴棒的数量。
  • 排序火柴棒数组:O(n log n),因为使用了数组的排序方法。
  • 反转数组:O(n),遍历数组一半的长度进行交换。
  • 深度优先搜索(DFS):最坏情况下,每个火柴棒都有4种选择(放入四条边中的任意一条),因此时间复杂度为O(4^n)。但是,由于我们使用了剪枝(如果当前边加上这根火柴棒超过边长,或者这根火柴棒和上一根相同且上一根放入该边失败,则跳过),实际上时间复杂度会小于O(4^n)。

综上所述,总的时间复杂度主要取决于DFS,即O(4^n),但由于剪枝的存在,实际运行时间会小于这个值。

2. 空间复杂度
  • 边长数组:O(1),因为它的长度是固定的4。
  • DFS递归栈:最坏情况下,递归的深度为n(火柴棒的数量),因此空间复杂度为O(n)。

综上所述,总的空间复杂度为O(n),其中n是火柴棒的数量。这是因为DFS递归过程中,系统栈会保存每次递归的状态,而每个状态都需要存储火柴棒数组的当前索引和边长数组的状态。尽管边长数组的大小是固定的,但递归栈的深度与火柴棒数量成线性关系。

五、总结知识点

  • 数组操作:

    • 使用for循环遍历数组,计算所有元素的和。
    • 使用Arrays.sort()方法对数组进行排序。
    • 实现了一个reverse()方法来反转数组元素的顺序。
  • 数学运算:

    • 计算数组元素的总和。
    • 检查总和是否能被4整除,以确定是否可能构成正方形。
  • 递归算法:

    • 实现了一个深度优先搜索(DFS)算法来尝试将火柴棒拼成正方形的四条边。
    • 在递归函数中,使用回溯法来尝试所有可能的组合。
  • 剪枝策略:

    • 在DFS中,通过判断当前边加上火柴棒是否会超过边长来剪枝,避免不必要的递归调用。
    • 通过比较当前边与上一边的长度来避免重复尝试相同的组合。
  • 逻辑判断:

    • 使用if语句来检查是否所有火柴棒都已尝试,以及是否所有边的长度都相等。
    • 使用continue语句来跳过不符合条件的迭代。
  • 基本编程概念:

    • 变量声明和初始化。
    • 函数定义和调用。
    • 递归的概念和应用。
  • 问题解决策略:

    • 将问题分解为更小的子问题(将火柴棒分配到四条边)。
    • 使用穷举法(DFS)来探索所有可能的解决方案。
    • 在探索过程中使用剪枝来优化性能。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

标签:正方形,--,matchsticks,473,int,edges,数组,火柴,LeetCode
From: https://blog.csdn.net/weixin_62860386/article/details/144494995

相关文章

  • 如何在 Spring Boot 应用程序中使用 WireMock 模拟外部 rest api 调用进行测试
    模拟外部API调用是集成或端到端测试中的常见做法,因为它允许开发人员将他们的代码与外部隔离。如果我们使用付费API并希望避免在测试时进行调用以节省资金,这也会有所帮助。有两种方法可以模拟外部API使用Mockito使用WireMock在集成测试和端到端测试中,我更喜欢使用Wir......
  • 接口数据做缓存,响应飞快似天神
    概述在商业中“现金为王”,而在互联网整个软件世界中,有一个与之相近的说法是“缓存为王”。本文我们重点说明缓存方向:将方法的返回值缓存起来,下次再调用该方法时,如果方法的参数与之前调用时的参数相同,则会直接返回缓存中的结果,而不会再执行方法体。这样可以提高方法的执......
  • WEB集群--HTTP协议
    HTTP概述默认端口:80HTTP(超文本传输协议):数据请求与响应请求request:访问网站响应response:显示网站,返回客户端想要的内容#curl-vwww.baidu.com#wget--debugwww.baidu.com---requestbegin---GET/HTTP/1.1User-Agent:Wget/1.14(linux-gnu)Accept:*/*Host:b......
  • JavaScript的对象相关概念
    当然可以,以下是将上述对话整理成Markdown格式的内容:JavaScript面向对象编程相关概念原型链(PrototypeChain)原型链是JavaScript中查找对象属性和方法的机制。它从对象的__proto__属性开始,向上逐层搜索直到找到属性或方法或到达Object.prototype。原型(Prototype)每个Java......
  • Spring Cloud 面试锦集
    2020-SpringCloud面试锦集一:什么是微服务架构?二:Ribbon?1:负载均衡的核心组件?2:负载均衡算法?3:负载均衡的替换?4:Ribbon轮询负载均衡算法?三:Springcloud和springboot版本依赖关系四:eureka?五:openFeign六:Hystrix一:什么是微服务架构?微服务架构是一种架构模式,他提倡......
  • 使用wsimport命令生成webService客户端代码
    wsimport 是JDK自带的一个工具,可以根据WSDL文件生成Java类。1.进入JDK/bin目录,从地址栏进入cmd 2.执行如下命令:wsimport-keep-sD:\tmp-pcom.cn.phone-verbosehttp://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl-keep:是否生成java源文件-s:指定.ja......
  • 闲置物品交易平台-毕业设计源码04508
    摘要本项目旨在基于SSM框架开发一款闲置物品交易平台,为用户提供一个便捷、安全的平台,实现用户间的二手物品交易和共享。该平台将包括用户管理、商品管理、交易管理和支付管理等模块,通过前端页面设计和后端技术的结合,为用户提供良好的交易体验和安全保障。用户可以注册账......
  • (附源码)springboot高校大学生就业管理信息系统-计算机毕设 33061
    高校大学生就业管理信息系统设计与实现摘 要在网络飞速发展的信息时代,各个行业都离不开信息的处理,在这种时代背景下,学校以学生的信息管理为导向,根据这点,为当前形势最重要的高校大学生就业管理信息设计一个就业信息管理系统就很有必要。高校大学生高校大学生就业管理信......
  • 呕心沥血上万字——详解 TCP 协议!!
    目录1.TCP协议特点2.TCP报文格式 2.1源端口/目的端口2.24位首部长度2.3选项2.4保留位2.516位校验和2.66位标志位3.TCP核心机制一:确认应答3.1先发后至3.2序号/确认序号3.2.1如何编排3.2.2排序4.TCP核心机制二:超时重传4.1丢包 4.1.1丢......
  • DES(请自行忽略我写的第一篇,这个才是真的)
    1.DES特点(1)是对称加密算法(2)56位密钥进行加密。(原有64位,其中有8位校验位)(3)对明文块进行加密,以64位为一个块,不足64填充为64,超过64,以分组模式进行分组加密2.DES加密流程(1)首先把64位的明文进行初始IP置换(把64位明文按照规定的置换表进行排序),然后分成L0和R0两个部分,每个部分32位......