【经典算法】LeetCode 22括号生成(Java/C/Python3/Go实现含注释说明,中等)

  • 作者主页: 🔗进朱者赤的博客

  • 精选专栏:🔗经典算法

  • 作者简介:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名

  • ❤️觉得文章还不错的话欢迎大家点赞👍➕收藏⭐️➕评论,💬支持博主,记得点个大大的关注,持续更新🤞
    ————————————————-

首先,请注意题目链接有误,您提供的链接是LeetCode 14,但题目描述应该是关于LeetCode 22(括号生成)。以下是按照您提供的格式和要求,针对LeetCode 22题目“括号生成”的多种语言实现方式。

目录

  • 题目描述
  • 思路及实现
    • 方式一:回溯法
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
        • Go语言版本
      • 复杂度分析
    • 方式二:动态规划
        • 思路**
        • **Java实现**
        • **C++实现**
        • **Python3实现**
        • **Go实现**
      • 复杂度分析
      • 总结
  • 相似题目

  • 标签(题目类型):动态规划

题目描述

给定 n 对括号,生成所有由 n 对括号组成的合法(有效)括号组合。例如,给出 n = 3,生成结果为:
["((()))","(()())","(())()","()(())","()()()"
]

思路及实现

方式一:回溯法

思路

使用回溯法来递归地生成所有可能的括号组合,并在递归过程中检查括号的有效性。

代码实现

Java版本
import java.util.ArrayList;
import java.util.List;public class Solution {public List<String> generateParenthesis(int n) {List<String> result = new ArrayList<>();backtrack(result, "", 0, 0, n);return result;}private void backtrack(List<String> result, String current, int open, int close, int max) {if (current.length() == max * 2) {result.add(current);return;}if (open < max) {backtrack(result, current + "(", open + 1, close, max);}if (close < open) {backtrack(result, current + ")", open, close + 1, max);}}
}

说明:使用回溯法,在递归过程中跟踪已打开的括号数量(open)和已关闭的括号数量(close)。只有当open小于max时,才添加左括号;只有当close小于open时,才添加右括号。

C语言版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>void backtrack(char*** result, int* returnSize, char* current, int open, int close, int max, int* currentIndex) {if (strlen(current) == max * 2) {char* temp = (char*)malloc(max * 2 + 1);strcpy(temp, current);result[*returnSize] = temp;(*returnSize)++;return;}if (open < max) {current[(*currentIndex)++] = '(';backtrack(result, returnSize, current, open + 1, close, max, currentIndex);(*currentIndex)--;}if (close < open) {current[(*currentIndex)++] = ')';backtrack(result, returnSize, current, open, close + 1, max, currentIndex);(*currentIndex)--;}
}char** generateParenthesis(int n, int* returnSize) {char* current = (char*)malloc((n * 2 + 1) * sizeof(char));char** result = (char**)malloc(10000 * sizeof(char*)); // Assuming max number of results*returnSize = 0;int currentIndex = 0;backtrack(result, returnSize, current, 0, 0, n, &currentIndex);free(current); // Don't forget to free the allocated memoryreturn result;
}

说明:在C语言中,我们使用动态内存分配来存储结果和当前路径。同样,我们跟踪已打开的括号和已关闭的括号数量。

Python3版本
class Solution:def generateParenthesis(self, n: int) -> List[str]:def backtrack(current, open, close, result):if len(current) == 2 * n:result.append(current)returnif open < n:backtrack(current + '(', open + 1, close, result)if close < open:backtrack(current + ')', open, close + 1, result)result = []backtrack("", 0, 0, result)return result

说明:Python版本相对简洁,利用递归和字符串拼接来生成所有可能的

Go语言版本
package mainimport ("fmt""strconv"
)func generateParenthesis(n int) []string {var result []stringbacktrack(&result, "", 0, 0, n)return result
}func backtrack(result *[]string, current string, open, close, max int) {if len(current) == max*2 {*result = append(*result, current)return}if open < max {backtrack(result, current+"(", open+1, close, max)}if close < open {backtrack(result, current+")", open, close+1, max)}
}func main() {n := 3res := generateParenthesis(n)for _, s := range res {fmt.Println(s)}
}

说明:在Go语言中,我们使用切片来存储结果,并通过backtrack函数递归地生成所有可能的括号组合。

复杂度分析

对于所有语言版本,其时间复杂度和空间复杂度都是相同的。

  • 时间复杂度:O(2^n * n),因为对于n对括号,左括号有n个位置可以放置,每个位置有放和不放两种选择,所以总共有2^n种可能,但是每种可能都需要O(n)的时间来生成和验证括号串。
  • 空间复杂度:O(n * 2^n),在最坏情况下,即所有可能的括号串都需要被存储时,我们需要O(n * 2^n)的空间来存储这些串。在递归过程中,我们还需要额外的栈空间来保存递归调用的上下文,但这部分空间相对于结果空间来说较小,因此通常忽略不计。

方式二:动态规划

(由于动态规划在生成所有可能的组合时不如回溯法直观,通常用于求解某个最优解问题,而不是直接生成所有解,因此这里不给出动态规划的直接实现。但我们可以理解其思路是构建一个表格,其中每个单元格存储了给定括号对数量时的所有有效括号组合。)

当然,以下是使用Markdown语言书写的之前提到的四种编程语言的实现示例,以及关于动态规划结合回溯的额外说明:

思路**

在方式二中,我们将动态规划(DP)与回溯算法结合使用。这种方法的核心思想是,先利用动态规划预处理一些信息,在回溯过程中利用这些信息来减少无效搜索。然而,在生成有效括号这个问题中,由于问题的特殊性,我们实际上可以通过简单的条件判断来实现隐式剪枝,而无需显式构建动态规划表。

Java实现
public class Solution {public List<String> generateParenthesis(int n) {List<String> result = new ArrayList<>();backtrack(result, "", 0, 0, n);return result;}private void backtrack(List<String> result, String current, int open, int close, int max) {if (current.length() == max * 2) {result.add(current);return;}if (open < max) {backtrack(result, current + "(", open + 1, close, max);}if (close < open) {backtrack(result, current + ")", open, close + 1, max);}}
}
C++实现
#include <vector>
#include <string>using namespace std;class Solution {
public:vector<string> generateParenthesis(int n) {vector<string> result;backtrack(result, "", 0, 0, n);return result;}private:void backtrack(vector<string>& result, string current, int open, int close, int max) {if (current.size() == max * 2) {result.push_back(current);return;}if (open < max) {backtrack(result, current + "(", open + 1, close, max);}if (close < open) {backtrack(result, current + ")", open, close + 1, max);}}
};
Python3实现
def generateParenthesis(n):def backtrack(path, open_count, close_count, res):if len(path) == 2 * n:res.append(path)returnif open_count < n:backtrack(path + '(', open_count + 1, close_count, res)if close_count < open_count:backtrack(path + ')', open_count, close_count + 1, res)res = []backtrack("", 0, 0, res)return res
Go实现
package mainimport "fmt"func generateParenthesis(n int) []string {var result []stringbacktrack(&result, "", 0, 0, n)return result
}func backtrack(result *[]string, current string, open, close, max int) {if len(current) == max*2 {*result = append(*result, current)return}if open < max {backtrack(result, current+"(", open+1, close, max)}if close < open {backtrack(result, current+")", open, close+1, max)}
}func main() {res := generateParenthesis(3)for _, s := range res {fmt.Println(s)}
}

复杂度分析

  • 时间复杂度:

由于需要生成并检查所有可能的括号序列(包括无效的),算法在最坏情况下可能会检查接近 2^n 个序列,其中 n 是括号对的数量。
然而,由于算法中使用了隐式剪枝(即确保在任何前缀中左括号数量不少于右括号数量),实际检查的序列数量会远少于 2^n。
因此,虽然时间复杂度是指数级的,但由于剪枝的存在,实际运行时间会比 O(2^n) 要好。
空间复杂度:

  • 空间复杂度
    主要由递归栈的深度和存储结果的列表决定。
    递归栈的深度在最坏情况下为 O(n),其中 n 是括号对的数量。
    存储结果的列表最终会包含所有有效的括号序列,其数量是卡特兰数 C_n,渐进复杂度为 O(4^n / (n^(3/2) * sqrt(π))),但算法运行时的空间复杂度主要由递归栈决定,为 O(n)。
    简而言之,时间复杂度是指数级的但剪枝有效,空间复杂度为 O(n)。

关于动态规划结合回溯

在更复杂的问题中,动态规划表可以用来存储子问题的解,以减少重复计算,并在回溯过程中提供快速查找。然而,在本问题中,由于括号的有效性检查相对简单,我们直接通过递归函数中的参数进行条件判断,实现了高效的回溯,无需额外的动态规划表。这种方法称为“隐式剪枝”,它避免了不必要的搜索,从而提高了算法效率。

总结

方式优点缺点时间复杂度空间复杂度
方式一(回溯法)直观易理解,可以生成所有解可能产生大量重复计算(可通过记忆化搜索优化)O(2^n * n)O(n * 2^n)
方式二(动态规划)(理论上可以优化,但不适合直接生成所有解)实现复杂,不直观O(2^n) 要好。
O(n)

相似题目

相似题目难度链接
LeetCode 32. 最长有效括号困难LeetCode-32
LeetCode 20. 有效的括号简单LeetCode-20

注意:相似题目链接指向的是英文LeetCode,如果需要中文版本,请替换为leetcode-cn.com

欢迎一键三连(关注+点赞+收藏),技术的路上一起加油!!!代码改变世界

  • 关于我:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名),回复暗号,更能获取学习秘籍和书籍等

  • —⬇️欢迎关注下面的公众号:进朱者赤,认识不一样的技术人。⬇️—

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

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

相关文章

urllib3版本与系统openssl版本不兼容

urllib3版本与系统openssl版本不兼容 报错信息 ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1, currently the ssl 解决办法 安装urllib3的1.x.xx版本&#xff0c;如&#xff1a; pip install urllib31.25.11

UsersGUI.java用户界面

完成效果图&#xff1a; 点击阅读按钮&#xff1a; 点击删除按钮&#xff1a; 点击新建按钮&#xff1a; Code /* This GUI application allows users to manage their diaries: ​ Read: Users can read existing diaries. Create: Users can create new diaries. Delete: Us…

ARC学习(3)基本编程模型认识(三)

笔者来介绍arc的编程模型的中断流程和异常流程 1、中断介绍 主要介绍一下中断进入的流程&#xff0c;包括需要配置的寄存器等信息。 中断号&#xff1a;16-255&#xff0c;总共240个中断。触发类型&#xff1a;脉冲或者电平触发中断优先级&#xff1a;16个&#xff0c;0最大&…

【git1】指令,commit,免密

文章目录 1.常用指令&#xff1a;git branch查看本地分支&#xff0c; -r查看远程分支&#xff0c; -a查看本地和远程&#xff0c;-v查看各分支最后一次提交, -D删除分支2.commit规范&#xff1a;git commit进入vi界面&#xff08;进入前要git config core.editor vim设一下vi模…

DVWA-XSS(Stored)-httponly分析

拿DVWA的XSS为例子 httponly是微软对cookie做的扩展。这个主要是解决用户的cookie可能被盗用的问题。 接DVWA的分析&#xff0c;发现其实Impossible的cookie都是设置的httponly1&#xff0c;samesite1. 这两个参数的意思参考Set-Cookie HttpOnly:阻止 JavaScript 通过 Documen…

Java项目:基于SSM框架实现的精品酒销售管理系统分前后台【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的精品酒销售管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功…

文本三剑客—sed命令

sed命令 一、概念 sed是一种流编辑器&#xff0c;一次处理一行内容。 处理方式&#xff1a;一行一行处理&#xff0c;处理完当前行&#xff0c;才会处理下一行&#xff0c;直到文件末尾。 如果只是展示&#xff0c;会放在缓冲区&#xff08;模式空间&#xff09;&#xff0…

微信公众号 H5授权登录实现(最详细)

一、微信公众号 &#xff08;一&#xff09;基础信息 微信授权类型 自己的网站、APP等第三方&#xff0c;要实现接入微信授权登录&#xff0c;有多种方式&#xff1a;微信公众号&#xff08;网页&#xff09;、微信小程序、微信开放平台&#xff08;APP&#xff09;等等。 【…

面试:关于word2vec的相关知识点Hierarchical Softmax和NegativeSampling

1、为什么需要Hierarchical Softmax和Negative Sampling 从输入层到隐含层需要一个维度为NK的权重矩阵&#xff0c;从隐含层到输出层又需要一个维度为KN的权重矩阵&#xff0c;学习权重可以用反向传播算法实现&#xff0c;每次迭代时将权重沿梯度更优的方向进行一小步更新。但…

100337. 最大化子数组的总成本

Powered by:NEFU AB-IN Link 文章目录 100337. 最大化子数组的总成本题意思路代码 100337. 最大化子数组的总成本 题意 给你一个长度为 n 的整数数组 nums。 子数组 nums[l…r]&#xff08;其中 0 < l < r < n&#xff09;的 成本 定义为&#xff1a; cost(l, r)…

详细解析MATLAB和Simulink中的文件格式:mat, mdl, mexw32, 和 m 文件

matlab 探索MATLAB和Simulink中的文件格式&#xff1a;MAT, MDL, MEXW32, 和 M 文件**MAT 文件 (.mat)****MDL 文件 (.mdl)****MEX 文件 (.mexw32/.mexw64)****M 文件 (.m)****总结** 探索MATLAB和Simulink中的文件格式&#xff1a;MAT, MDL, MEXW32, 和 M 文件 当你开始使用M…

Python 虚拟环境 requirements.txt 文件生成 ;pipenv导出pip安装文件

搜索关键词: Python 虚拟环境Pipenv requirements.txt 文件生成;Pipenv 导出 pip requirements.txt安装文件 本文基于python版本 >3.9 文章内容有效日期2023年01月开始(因为此方法从这个时间开始是完全ok的) 上述为pipenv的演示版本 使用以下命令可精准生成requirement…

【Vue】图片懒加载的实现

封装全局指令img-lazy // 定义懒加载插件 import { useIntersectionObserver } from vueuse/coreexport const lazyPlugin {install (app) {// 懒加载指令逻辑app.directive(img-lazy, {mounted (el, binding) {// el: 指令绑定的那个元素 img// binding: binding.value 指令…

總結電磁學

參考: 陈曦<<电磁学讲义>>http://ithatron.phys.tsinghua.edu.cn/downloads/electricty_and_magnetism.pdf 4 电磁学的实验基础 我们已经回顾了经典物理学的框架。在现代物理学中,人们经常从一些基本的原则(如相对论协变性、对称性等等)出发来建立模型,然后…

Java8 --- Gradle7.4整合IDEA

目录 一、Gradle整合IDEA 1.1、Groovy安装 1.1.1、配置环境变量 ​编辑 1.2、创建项目 ​编辑 1.3、Groovy基本语法 1.3.1、基本语法 1.3.2、引号 1.3.3、语句结构 1.3.4、数据类型 1.3.5、集合操作 1.4、使用Gradle创建普通Java工程 1.5、使用Gradle创建Java ss…

深入理解go语言反射机制

1、前言 每当我们学习一个新的知识点时&#xff0c;一般来说&#xff0c;最关心两件事&#xff0c;一是该知识点的用法&#xff0c;另外就是使用场景。go反射机制作为go语言特性中一个比较高级的功能&#xff0c;我们也需要从上面两个方面去进行学习&#xff0c;前者告诉我们如…

如何在Java中进行网络编程?

如何在Java中进行网络编程&#xff1f; 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Java中进行网络编程&#xff0c;这是实现客户端和服…

Vite: 关于静态资源的处理机制

概述 随着前端技术的飞速发展&#xff0c;项目规模和复杂度不断增加&#xff0c;如何高效地处理静态资源成为了提升开发效率和应用性能的关键Vite&#xff0c;作为新一代前端构建工具&#xff0c;以其轻量级、快速启动和热更新著称&#xff0c;同时也为静态资源的管理和优化提…

使用 axios 进行 HTTP 请求

使用 axios 进行 HTTP 请求 文章目录 使用 axios 进行 HTTP 请求1、介绍2、安装和引入3、axios 基本使用4、axios 发送 GET 请求5、axios 发送 POST 请求6、高级使用7、总结 1、介绍 什么是 axios axios 是一个基于 promise 的 HTTP 库&#xff0c;可以用于浏览器和 Node.js 中…

计算机组成入门知识

前言&#x1f440;~ 数据库的知识点先暂且分享到这&#xff0c;接下来开始接触计算机组成以及计算机网络相关的知识点&#xff0c;这一章先介绍一些基础的计算机组成知识 一台计算机如何组成的&#xff1f; 存储器 CPU cpu的工作流程 主频 如何衡量CPU好坏呢&#xff1f…