当前位置: 首页 > article >正文

Leetcode百题斩-回溯

回溯是一个特别经典的问题,也被排在了百题斩的第一部分,那么我们接下来来过一下这个系列。

这个系列一共八道题,偶然间发现我两年前还刷到这个系列的题,回忆起来当时刚经历淘系大变动与jf出走海外事件,大量同事离职闹得人心慌心慌,可能是当时也心生担忧于是未雨绸缪了一下。

不知不觉已经过了三年安稳的日子了,生于忧患死于安乐,该努力起来了

时间有点久远,记忆逐渐忘却了,之前用c++去攻取,那么这次用java重写一轮看看感觉如何

17. Letter Combinations of a Phone Number[medium]

思路:手机9键打字,根据按得数字枚举可能打印的字母。这个就是典型的递归,记录当前递归的位数,然后每位再扩展可能组成的字符串,最终位数到达结尾时结束

class Solution {private final List<String> phoneNumberLetter = Arrays.asList("abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz");public List<String> letterCombinations(String digits) {if (Objects.equals(digits, "")) {return Collections.emptyList();}return getLetter(0, digits, "");}public List<String> getLetter(Integer pos, String digits, String currentLetter) {List<String> newLetter = new ArrayList<>();int dLen = digits.length();if (pos == dLen) {newLetter.add(currentLetter);return newLetter;}int currentDigit = digits.charAt(pos) - '2';String currentChars = phoneNumberLetter.get(currentDigit);int cLen = currentChars.length();for (int i = 0; i < cLen; i++) {String newCurrentLetter = currentLetter + currentChars.charAt(i);newLetter.addAll(getLetter(pos + 1, digits, newCurrentLetter));}return newLetter;}
}

22. Generate Parentheses[medium]

思路:括号生成,给定括号数量,枚举可能出现的情况。这种,又是个按位递归的问题,但其实这次要记录的并不是位数,记录一下剩余左右括号的数量即可,因为需要保证左括号数量一定大于右括号数量。

class Solution {public List<String> generateParenthesis(int n) {return getParenthesis(n, n, "");}private List<String> getParenthesis(int leftNum, int rightNum, String currentString) {List<String> result = new ArrayList<>();if (rightNum == 0 && leftNum == 0) {result.add(currentString);return result;}if (rightNum - 1 >= leftNum) {result.addAll(getParenthesis(leftNum, rightNum - 1, currentString + ")"));}if (leftNum > 0) {result.addAll(getParenthesis(leftNum - 1, rightNum, currentString + "("));}return result;}
}

39. Combination Sum[medium]

思路:又是求特地和问题,但这次的区别就是,集合内的元素可以重复使用,且不限制顺序。要求枚举所有可能的情况。于是再来一个递归,将所需求和的数量作为递归参数,每个数字挨个往里面加即可,最后注意一下,因为集合问题,不用考虑顺序,于是直接按顺序添加,并再加一个位置变量来记录当前添加的字符即可。

class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {return combinationSum(candidates, target, 0);}private List<List<Integer>> combinationSum(int[] candidates, int target, int pos) {List<List<Integer>> result = new java.util.ArrayList<>();int len = candidates.length;for (int i = pos; i < len; i++) {int current = candidates[i];if (current >= target) {if (current == target) {result.add(new java.util.ArrayList<>(Collections.singletonList(current)));}continue;}combinationSum(candidates, target - current, i).forEach(list -> {list.add(current);result.add(list);});}return result;}
}

46. Permutations[medium]

思路:求全排列,这题如果用c++,可以直接用模板库,再方便不过了,但现在自己选择了用java,那就自己暴力写呗

依旧是递归位置,然后需要一个参数记录一下已经投入的变量集合,当然注意一下。由于这个变量共享,因此一定要在每轮递归结束的时候将变量清除

class Solution {public List<List<Integer>> permute(int[] nums) {return getPermutation(0, nums, new HashSet<>());}private List<List<Integer>> getPermutation(int pos, int[] nums, Set<Integer> used) {List<List<Integer>> result = new java.util.ArrayList<>();int len = nums.length;for (int i = 0; i < len; i++) {if (used.contains(i)) {continue;}used.add(i);int currentNum = nums[i];if (pos == len - 1) {List<Integer> list = new ArrayList<>();list.add(currentNum);result.add(list);used.remove(i);return result;} else {result.addAll(getPermutation(pos + 1, nums, used).stream().peek(list -> list.add(currentNum)).collect(Collectors.toList()));}used.remove(i);}return result;}
}

78. Subsets[Meduim]

思路:求集合的子集,这就是最经典的递归回溯问题了。按位回溯,每个位置回溯是否包含当前字符的两种情况

class Solution {public List<List<Integer>> subsets(int[] nums) {return getSubsets(0, nums);}private List<List<Integer>> getSubsets(int pos, int[] nums) {List<List<Integer>> result = new ArrayList<>();int len = nums.length;if (pos == len - 1) {List<Integer> list1 = new ArrayList<>();list1.add(nums[pos]);result.add(list1);List<Integer> list2 = new ArrayList<>();result.add(list2);return result;}result.addAll(getSubsets(pos + 1, nums).stream().peek(list -> list.add(nums[pos])).collect(Collectors.toList()));result.addAll(getSubsets(pos + 1, nums));return result;}
}

79. Word Search[Medium]

思路:棋盘搜索问题,二维递归回溯的经典问题,回溯四个方向即可,注意一下为了避免往回回溯形成死循环,每次回溯点需要抹掉,回溯完成后恢复即可

class Solution {public boolean exist(char[][] board, String word) {int xLen = board.length;for (int i = 0; i < xLen; i++) {int yLen = board[i].length;for (int j = 0; j < yLen; j++) {if (search(i, j, board, word, 0)) {return true;}}}return false;}private boolean search(int x, int y, char[][] board, String word, int pos) {char currentChar = board[x][y];//System.out.println(x + "*" + y + "*" + currentChar + "*" + pos);if (board[x][y] != word.charAt(pos)) {return false;}board[x][y] = 0;boolean bingo = false;if (pos == word.length() - 1) {bingo = true;} else if (x > 0 && search(x - 1, y, board, word, pos + 1)) {bingo = true;} else if (y > 0 && search(x, y - 1, board, word, pos + 1)) {bingo = true;} else if (x < board.length - 1 && search(x + 1, y, board, word, pos + 1)) {bingo = true;} else if (y < board[x].length - 1 && search(x, y + 1, board, word, pos + 1)) {bingo = true;}board[x][y] = currentChar;return bingo;}
}

131. Palindrome Partitioning[Medium]

思路:将字符串分割成多个回文子串,求所有分割方案。其实分隔子串这类问题,首先想到的就是递归回溯。按位进行回溯,从每个位置开始,先枚举添加的回文串,再递归剩余的子串。至于回文串判断,这里就采用最暴力的双指针进行判断,为了避免重复,将已经判断过的结果进行持久化记录一下。如果想优化预处理回文串,可以看之前的一篇回文串的文章,那里介绍了从立方复杂度的暴力求法到最佳常数复杂度的Manarch算法。

class Solution {private Map<String, Boolean> palindromeSet = new HashMap<>();public List<List<String>> partition(String s) {List<List<String>> result = getPartition(s, 0);result.forEach(Collections::reverse);return result;}private List<List<String>> getPartition(String s, int pos) {List<List<String>> result = new ArrayList<>();int len = s.length();if (pos == len) {List<String> endResult = new ArrayList<>();result.add(endResult);return result;}for (int i = pos; i < len; i++) {String current = s.substring(pos, i + 1);if (isPalindrome(current)) {List<List<String>> partition = getPartition(s, i + 1);for (List<String> list : partition) {list.add(current);}result.addAll(partition);}}return result;}private boolean isPalindrome(String s) {if (palindromeSet.containsKey(s)) {return palindromeSet.get(s);}int left = 0;int right = s.length() - 1;boolean palindrome = true;while (left <= right) {if (s.charAt(left) != s.charAt(right)) {palindrome = false;break;}left++;right--;}palindromeSet.put(s, palindrome);return palindrome;}
}

51. N-Queens[Hard]

思路:N皇后问题,可以算是递归回溯系列经典中的经典。给定边长为N的棋盘大小,要求所有能摆出N个不相攻击的皇后摆法(皇后可以任意横着走或者斜着走)。这题显然需要遍历每个棋格去进行递归,递归时维护已经摆上的皇后数量,所需的皇后数量,以及当前棋盘的状态。当摆上皇后时,遍历更新棋盘,标记不可继续放置棋盘的位置。由于棋盘需要反复被标记,导致复杂度变高,这里根据皇后的特性不难发现,只需要维护三个集合 y,x+y,x-y,即可分别表示皇后所在列,以及所在的两个斜线,从而避免反复标记棋盘。而针对皇后所在行,每次放置皇后时跳到下一行即可避免同行皇后。此外,由于按顺序遍历所有棋格,因此可以直接用一维字符数组代替二维棋盘,最后转换一下即可表示棋盘最终形态

class Solution {public List<List<String>> solveNQueens(int n) {char[] board = new char[n * n];for (int i = 0; i < n * n; i++) {board[i] = '.';}Set<Integer> s1 = new HashSet<>();Set<Integer> s2 = new HashSet<>();Set<Integer> s3 = new HashSet<>();return getNQueens(0, board, 0, n, s1, s2, s3);}private List<List<String>> getNQueens(int pos, char[] board, int now, int n, Set<Integer> s1,Set<Integer> s2, Set<Integer> s3) {List<List<String>> result = new ArrayList<>();if (now == n) {List<String> endResult = getResult(board, n);result.add(endResult);return result;} else if (pos >= n * n) {return Collections.emptyList();}int x = pos / n;int y = pos % n;if (!s1.contains(x + y) && !s2.contains(x - y) && !s3.contains(y)) {board[pos] = 'Q';s1.add(x + y);s2.add(x - y);s3.add(y);int nextPos = (x + 1) * n;result.addAll(getNQueens(nextPos, board, now + 1, n, s1, s2, s3));s1.remove(x + y);s2.remove(x - y);s3.remove(y);board[pos] = '.';}result.addAll(getNQueens(pos + 1, board, now, n, s1, s2, s3));return result;}private List<String> getResult(char[] board, int n) {List<String> result = new ArrayList<>();for (int i = 0; i < n; i++) {StringBuilder sb = new StringBuilder();for (int j = 0; j < n; j++) {sb.append(board[i * n + j]);}result.add(sb.toString());}return result;}
}

最终,递归回溯完结

相关文章:

Leetcode百题斩-回溯

回溯是一个特别经典的问题&#xff0c;也被排在了百题斩的第一部分&#xff0c;那么我们接下来来过一下这个系列。 这个系列一共八道题&#xff0c;偶然间发现我两年前还刷到这个系列的题&#xff0c;回忆起来当时刚经历淘系大变动与jf出走海外事件&#xff0c;大量同事离职闹…...

超小多模态视觉语言模型MiniMind-V 训练

简述 MiniMind-V 是一个超适合初学者的项目&#xff0c;让你用普通电脑就能训一个能看图说话的 AI。训练过程就像教小孩&#xff1a;先准备好图文材料&#xff08;数据集&#xff09;&#xff0c;教它基础知识&#xff08;预训练&#xff09;&#xff0c;再教具体技能&#xf…...

边缘云的定义、实现与典型应用场景!与传统云计算的区别!

一、什么是边缘云&#xff1f;‌ 边缘云是一种‌分布式云计算架构‌&#xff0c;将计算、存储和网络资源部署在‌靠近数据源或终端用户的网络边缘侧‌&#xff08;如基站、本地数据中心或终端设备附近&#xff09;&#xff0c;而非传统的集中式云端数据中心。 ‌核心特征‌&…...

HarmonyOS 鸿蒙应用开发基础:父组件和子组件的通信方法总结

在鸿蒙开发中&#xff0c;ArkUI声明式UI框架提供了一种现代化、直观的方式来构建用户界面。然而&#xff0c;由于其声明式的特性&#xff0c;父组件与子组件之间的通信方式与传统的命令式框架有所不同。本文旨在详细探讨在ArkUI框架中&#xff0c;父组件和子组件通信的方法总结…...

小白的进阶之路系列之三----人工智能从初步到精通pytorch计算机视觉详解下

我们将继续计算机视觉内容的讲解。 我们已经知道了计算机视觉,用在什么地方,如何用Pytorch来处理数据,设定一些基础的设置以及模型。下面,我们将要解释剩下的部分,包括以下内容: 主题内容Model 1 :加入非线性实验是机器学习的很大一部分,让我们尝试通过添加非线性层来…...

Scrapy爬取heima论坛所有页面内容并保存到MySQL数据库中

前期准备&#xff1a; Scrapy入门_win10安装scrapy-CSDN博客 新建 Scrapy项目 scrapy startproject mySpider # 项目名为mySpider 进入到spiders目录 cd mySpider/mySpider/spiders 创建爬虫 scrapy genspider heima bbs.itheima.com # 爬虫名为heima &#xff0c;爬…...

HarmonyOS NEXT~鸿蒙系统下的Cordova框架应用开发指南

HarmonyOS NEXT&#xff5e;鸿蒙系统下的Cordova框架应用开发指南 1. 简介 Apache Cordova是一个流行的开源移动应用开发框架&#xff0c;它允许开发者使用HTML5、CSS3和JavaScript构建跨平台移动应用。随着华为鸿蒙操作系统(HarmonyOS)的崛起&#xff0c;将Cordova应用适配到…...

com.alibaba.fastjson2 和com.alibaba.fastjson 区别

1&#xff0c;背景 最近发生了一件很奇怪的事&#xff1a;我们的服务向第三方发送请求参数时&#xff0c;第三方接收到的字段是首字母大写的 AppDtoList&#xff0c;但我们需要的是小写的 appDtoList。这套代码是从其他项目A原封不动复制过来的&#xff0c;我们仔细核对了项目…...

探索数据结构的时间与空间复杂度:编程世界的效率密码

在计算机科学的世界里&#xff0c;数据结构是构建高效算法的基石。而理解数据结构的时间复杂度和空间复杂度&#xff0c;则是评估算法效率的关键。无论是优化现有代码&#xff0c;还是设计新的系统&#xff0c;复杂度分析都是程序员必须掌握的核心技能。本文将深入探讨这两个重…...

std::ranges::views::stride 和 std::ranges::stride_view

std::ranges::views::stride 是 C23 中引入的一个范围适配器&#xff0c;用于创建一个视图&#xff0c;该视图只包含原始范围中每隔 N 个元素的元素&#xff08;即步长为 N 的元素&#xff09;。 基本概念 std::ranges::stride_view 是一个范围适配器&#xff0c;接受一个输…...

了解Android studio 初学者零基础推荐(2)

在kotlin中编写条件语句 if条件语句 fun main() {val trafficLight "gray"if (trafficLight "red") {println("Stop!")} else if (trafficLight "green") {println("go!")} else if (trafficLight "yellow")…...

矩阵短剧系统:如何用1个后台管理100+小程序?技术解析与实战应用

引言&#xff1a;短剧行业的效率革命 2025年&#xff0c;短剧市场规模已突破千亿&#xff0c;但传统多平台运营模式面临重复开发成本高、用户数据分散、内容同步效率低等痛点。行业亟需一种既能降本增效又能聚合流量的解决方案——“矩阵短剧系统”。通过“1个后台管理100小程…...

C# 初学者的 3 种重构模式

(Martin Fowlers Example) 1. 积极使用 Guard Clause&#xff08;保护语句&#xff09; "如果条件不满足&#xff0c;立即返回。将核心逻辑放在最少缩进的地方。" 概念定义 Guard Clause&#xff08;保护语句&#xff09; 是一种在函数开头检查特定条件是否满足&a…...

MySQL 数据类型深度全栈实战,天花板玩法层出不穷!

在 MySQL 数据库的世界里&#xff0c;数据类型是构建高效、可靠数据库的基石。选择合适的数据类型&#xff0c;不仅能节省存储空间&#xff0c;还能提升数据查询和处理的性能 目录 ​编辑 一、MySQL 数据类型总览 二、数值类型 三、字符串类型 四、日期时间类型 五、其他…...

前端vscode学习

1.安装python 打开Python官网&#xff1a;Welcome to Python.org 一定要点PATH&#xff0c;要不然要自己设 点击install now,就自动安装了 键盘winR 输入cmd 点击确定 输入python&#xff0c;回车 显示这样就是安装成功了 2.安装vscode 2.1下载软件 2.2安装中文 2.2.1当安…...

自动驾驶传感器数据处理:Python 如何让无人车更智能?

自动驾驶传感器数据处理:Python 如何让无人车更智能? 1. 引言:为什么自动驾驶离不开数据处理? 自动驾驶一直被誉为人工智能最具挑战性的应用之一,而其背后的核心技术正是 多传感器融合与数据处理。 一辆智能驾驶汽车,通常搭载: 激光雷达(LiDAR) —— 3D 环境感知,…...

从电商角度设计大模型的 Prompt

从电商角度设计大模型的 Prompt&#xff0c;有一个关键核心思路&#xff1a;围绕具体业务场景明确任务目标输出格式&#xff0c;帮助模型为运营、客服、营销、数据分析等工作提效。以下是电商场景下 Prompt 设计的完整指南&#xff0c;包含通用思路、模块范例、实战案例等内容。…...

利用 SQL Server 作业实现异步任务处理:一种简化系统架构的实践方案

在中小型企业系统架构中&#xff0c;很多业务场景需要引入异步任务处理机制&#xff0c;例如&#xff1a; 订单完成后异步生成报表&#xff1b; 用户操作后触发异步推送&#xff1b; 后台批量导入数据后异步校验&#xff1b; 跨系统的数据同步与转换。 传统做法是引入消息…...

平安健康2025年一季度深耕医养,科技赋能见成效

近日&#xff0c;平安健康医疗科技有限公司&#xff08;股票简称“平安好医生”&#xff0c;1833.HK&#xff09;公布截至2025年3月31日止三个月的业绩报告&#xff0c;展现出强劲的发展势头与潜力。 2025年一季度&#xff0c;中国经济回升向好&#xff0c;平安健康把握机遇&a…...

Index-AniSora技术升级开源:动漫视频生成强化学习

B站升级动画视频生成模型Index-AniSora技术并开源&#xff0c;支持番剧、国创、漫改动画、VTuber、动画PV、鬼畜动画等多种二次元风格视频镜头一键生成&#xff01; 整个工作技术原理基于B站提出的 AniSora: Exploring the Frontiers of Animation Video Generation in the So…...

LLVM编译C++测试

安装命令 sudo apt install clang sudo apt-get install llvm 源码 hello.cpp #include <iostream> using namespace std; int main(){cout << "hello world" << endl;return 0; }编译 clang -emit-llvm -S hello.cpp -o hello.ll 执行后&#…...

ubuntu24.04+RTX5090D 显卡驱动安装

初步准备 Ubuntu默认内核太旧&#xff0c;用mainline工具安装新版&#xff1a; sudo add-apt-repository ppa:cappelikan/ppa sudo apt update && sudo apt full-upgrade sudo apt install -y mainline mainline list # 查看可用内核列表 mainline install 6.13 # 安装…...

MATLAB贝叶斯超参数优化LSTM预测设备寿命应用——以航空发动机退化数据为例

原文链接&#xff1a;tecdat.cn/?p42189 在工业数字化转型的浪潮中&#xff0c;设备剩余寿命&#xff08;RUL&#xff09;预测作为预测性维护的核心环节&#xff0c;正成为数据科学家破解设备运维效率难题的关键。本文改编自团队为某航空制造企业提供的智能运维咨询项目成果&a…...

鸿蒙应用开发:Navigation组件使用流程

一、编写navigation相关代码 1.在index.ets文件中写根视图容器 2.再写两个子页面文件 二、创建rote_map.json文件 三、在module.json5文件中配置路由导航 子页配置信息 4.跳转到其他页面 但是不支持返回到本页面的 用以下方式 以下是不能返回的情况 onClick(()>{this.pag…...

javaweb的拦截功能,自动跳转登录页面

我们开发系统时候&#xff0c;肯定希望用户登录后才能进入主页面去访问其他服务&#xff0c;但要是没有拦截功能的话&#xff0c;他就可以直接通过url访问或者post注入攻击了。 因此我们可以通过在后端添加拦截过滤功能把没登录的用户给拦截下来&#xff0c;让他去先登录&#…...

【Linux】系统在输入密码后进入系统闪退锁屏界面

问题描述 麒麟V10系统&#xff0c;输入密码并验证通过后进入桌面&#xff0c;1秒左右闪退回锁屏问题 问题排查 小白鸽之前遇到过类似问题&#xff0c;但是并未进入系统桌面内直接闪退到锁屏。 之前问题链接&#xff1a; https://blog.csdn.net/qq_51228157/article/details/140…...

当物联网“芯”闯入纳米世界:ESP32-S3驱动的原子力显微镜能走多远?

上次咱们把OV2640摄像头“盘”得明明白白&#xff0c;是不是感觉ESP32-S3这小东西潜力无限&#xff1f;今天&#xff0c;咱们玩个更刺激的&#xff0c;一个听起来就让人肾上腺素飙升的挑战——尝试用ESP32-S3这颗“智慧芯”&#xff0c;去捅一捅科学界的“马蜂窝”&#xff0c;…...

微信小程序webview与VUE-H5实时通讯,踩坑无数!亲测可实现

背景&#xff1a;微信小程序、vue3搭建开发的H5页面 在微信小程序开发中&#xff0c;会遇到嵌套H5页面&#xff0c;H5页面需要向微信小程序发消息触发微信小程序某个函数方法&#xff0c;微信开发文档上写的非常不清楚&#xff0c;导致踩了很多坑&#xff0c;该文章总结可直接使…...

Web请求与相应

目录 HTTP协议 一、协议基础特性 二、协议核心组成 三、完整通信流程&#xff08;TCP/IP层&#xff09; 1. 基础方法 2. 扩展方法 3. 安全性与幂等性 4. 应用场景示例 三、关键版本演进 四、典型工作流程 HTTP状态码 一、状态码分类体系 二、详细状态码表格&#…...

LeetCode222_完全二叉树的结点个数

LeetCode222_完全二叉树的结点个数 标签&#xff1a;#位运算 #树 #二分查找 #二叉树Ⅰ. 题目Ⅱ. 示例 0. 个人方法 标签&#xff1a;#位运算 #树 #二分查找 #二叉树 Ⅰ. 题目 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&…...