leetcode:491. 递增子序列、17. 电话号码的字母组合、31. 分割回文串、93. 复原 IP 地址(JavaScript)
文章目录
- 491. 递增子序列
- 分析
- 去重
- 如何保证递增呢?
- 17. 电话号码的字母组合
- 思路:
- 单层递归逻辑
- 递归终止条件
- 完整代码
- 另一种写法
- 31. 分割回文串
- 思路:分析题目本题可分为两步
- 93. 复原 IP 地址
- 思路:分析题目可以得出要解此题需要做两步工作
491. 递增子序列
给你一个整数数组 nums
,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
示例 1:
输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
示例 2:
输入:nums = [4,4,3,2,1]
输出:[[4,4]]
提示:
1 <= nums.length <= 15
-100 <= nums[i] <= 100
分析
去重
由题目给出的例子中可以看出不能改变数组元素的位置,所以不能给数组排序,由上一篇博客可以子集2的分析得知排序是为了方便在递归过程中去重,那么现在不能排序了,该怎么去重呢?
其实还有另一种方法:就是将used变为一个数组,里边存放着本层使用过的元素,在判断要不要使用当前元素时,先判断used数组中是否包含该元素,若包含则不使用该元素。若不包含,那么在回溯到当前元素时,就将当前元素保存到used中标记当前元素已使用过了。
如何保证递增呢?
同样在判断要不要使用当前元素时,可以将当前元素与path的最后一个元素比较,如果当前元素更小,那么就不使用它,因为若是用它就会使path为非递增序列,最后添加到结果数组中时就与题目意思相悖。
var findSubsequences = function(nums) {const res = [], path = [];const dfs = function(start) {// 结果限制条件至少有两个元素if (path.length >= 2)res.push([...path]);let used = [];for (let i = start; i < nums.length; i++) {// 使用过后非递增则跳过该元素if (used.includes(nums[i]) || path[path.length - 1] > nums[i])continue;path.push(nums[i]);dfs(i + 1);path.pop();// 记录当前元素used.push(nums[i]);}}dfs(0);return res;
};
17. 电话号码的字母组合
给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = ""
输出:[]
示例 3:
输入:digits = "2"
输出:["a","b","c"]
提示:
0 <= digits.length <= 4
digits[i]
是范围['2', '9']
的一个数字。
思路:
可以先将每个数字代表的字符串放在一个数组里,然后使用递归取给出的数字字符串中数字的映射,for循环遍历该映射取得每个字符。
单层递归逻辑
分析本题可以看出每层遍历都是取不同的集合字母且要取完每个集合中的字母,所以递归的需要for循环取字母且每层循环都从下标0开始,不需要给递归传入循环开始位置。
for (let i = 0; i < n; i++) {path.push(map[digits[len] - 2][i]);dfs (path, digitslen, len + 1);path.pop();
}
递归终止条件
因为是每层是从一个数字所映射的字符串中取一个字符,所以可以用一个变量记录当前递归层数,当该变量与传入的数字字符串长度相等时说明已经得到一个组合。
if (len === digitslen) {res.push (path.join(""));return;
}
完整代码
var letterCombinations = function(digits) {// 记录映射关系const map = ["abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"];const res = [];const dfs = function (path, digitslen, len) {// 递归终止条件if (len === digitslen) {res.push (path.join(""));return;}// 取得每个数字映射字符串长度const n = map[digits[len] - 2].length;for (let i = 0; i < n; i++) {path.push(map[digits[len] - 2][i]);dfs (path, digitslen, len + 1);path.pop();}}// 传入数字字符串不为空时才进入递归if (digits !== "") dfs([], digits.length, 0)return res;
};
另一种写法
var letterCombinations = function(digits) {const map = ["abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"];const res = [];const dfs = function (path, digitslen, len) {if (len === digitslen) {res.push (path.join(""));return;}for (const c of map[digits[len] - 2]) {path.push(c);dfs (path, digitslen, len + 1);path.pop();}}if (digits !== "") dfs([], digits.length, 0)else if (digits.length === 1){return map[digits].split("");}return res;
};
31. 分割回文串
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a"
输出:[["a"]]
提示:
1 <= s.length <= 16
s
仅由小写英文字母组成
思路:分析题目本题可分为两步
- 分割字符串
- 验证字符串是否是回文字符串
怎么分割呢? 利用递归不断地将分割向前推进(调整开始标记),利用每层的for循环不断调整子串的长度,每调整一次长度的同时就验证一次字符串是否合法,若当前截取的字符串是有效的那么就将其保存,递归进入下一层且将开始标记变为当前字符串结束位置下标加1。
使用双指针方法来检查字符串是否是回文字符串。
var partition = function(s) {const res = [], path = [];// 递归分割字符串let dfs = function (start) {// 递归终止条件if (start >= s.length) {res.push ([...path]);return;} for (let i = start; i < s.length; i++) {// 这里当前字符串不合法不能直接退出循环,因为你不能保证字符串调整后也不是回文串if (!isTrue(start, i)) continue;path.push(s.substring(start, i + 1));dfs (i + 1);path.pop();}}// 验证是否是回文字符串let isTrue = function(l, r) {while (l < r) {if (s[r] !== s[l]) {return false;}l++;r--;}return true;}dfs (0);return res;
};
93. 复原 IP 地址
有效 IP 地址 正好由四个整数(每个整数位于 0
到 255
之间组成,且不能含有前导 0
),整数之间用 '.'
分隔。
- 例如:
"0.1.2.201"
和"192.168.1.1"
是 有效 IP 地址,但是"0.011.255.245"
、"192.168.1.312"
和"192.168@1.1"
是 无效 IP 地址。
给定一个只包含数字的字符串 s
,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s
中插入 '.'
来形成。你 不能 重新排序或删除 s
中的任何数字。你可以按 任何 顺序返回答案。
示例 1:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
示例 2:
输入:s = "0000"
输出:["0.0.0.0"]
示例 3:
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
提示:
1 <= s.length <= 20
s
仅由数字组成
思路:分析题目可以得出要解此题需要做两步工作
- 分割字符串
- 验证字符串的合法性
利用递归不断地将分割向前推进(调整开始标记),利用每层的for循环不断调整子串的长度,每调整一次长度的同时就验证一次字符串是否合法,若当前截取的字符串是有效的那么就将其保存,递归进入下一层且将开始标记变为当前字符串结束位置下标加1。
验证合法性, 长度不为1且首字符为0的字符串则是含前导0的字符串,不合法,若字符串的整数值大于255也不合法。
递归终止条件,只要字符串分割完了就需要结束递归,只有path的长度为四才是合法IP,记录进结果数组中。
var restoreIpAddresses = function(s) {const res = [], path = [];// 递归分割字符串let dfs = function (start) {// 递归终止条件if (start >= s.length ) {// 若path长度为四那么就是有效IPif (path.length === 4)res.push (path.join('.'));return;} for (let i = start; i < s.length; i++) {// 截取字符串const ipItem = s.substring(start, i + 1);// 验证是否合法,如果不合法那么包含当前字符串的所有IP都不合法,直接退出循环(剪枝)if (!isTrue(ipItem)) break;path.push(ipItem);dfs (i + 1);path.pop();}}// 验证子串是否合法let isTrue = function(ipItem) {if ((ipItem[0] === '0' && ipItem.length !== 1) || ipItem > 255) return false;return true;}dfs (0);return res;
};
leetcode:491. 递增子序列、17. 电话号码的字母组合、31. 分割回文串、93. 复原 IP 地址(JavaScript)相关推荐
- LeetCode刷题记录——17电话号码的字母组合
LeetCode刷题记录--17电话号码的字母组合 一 题目描述: 给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合.给出数字到字母的映射如下.注意1不对应任何字母 示例: 输入:&quo ...
- leetcode 93. 复原IP地址 思考分析
题目 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255之间组成,且不能含有前导 0),整数之间用 '.' 分隔. ...
- 【python】一道LeetCode搞懂递归算法!#131分割回文串 #以及刷LeetCode的一点点小心得 [数据结构与算法基础]
题目:给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串.返回 s 所有可能的分割方案. # 示例 输入: "aab" 输出: [["aa",&q ...
- LeetCode 1278. 分割回文串 III
截止到目前我已经写了 600多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载 下载链接:https://pan.baidu.com/s/1hj ...
- Java实现 LeetCode 491递增子序列
491. 递增子序列 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, ...
- LeetCode 491. 递增子序列【数组,回溯算法,哈希表去重】
491. 递增子序列 给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 .你可以按 任意顺序 返回答案. 数组中可能含有重复元素,如出现两个整数相等, ...
- LeetCode 2131. 连接两字母单词得到的最长回文串
文章目录 1. 题目 2. 解题 1. 题目 给你一个字符串数组 words .words 中每个元素都是一个包含 两个 小写英文字母的单词. 请你从 words 中选择一些元素并按 任意顺序 连接它 ...
- LeetCode 1278. 分割回文串 III(区间DP)
文章目录 1. 题目 2. 解题 1. 题目 给你一个由小写字母组成的字符串 s,和一个整数 k. 请你按下面的要求分割字符串: 首先,你可以将 s 中的部分字符修改为其他的小写英文字母. 接着,你需 ...
- LeetCode 132. 分割回文串 II(DP)
文章目录 1. 题目 2. 解题 1. 题目 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回符合要求的最少分割次数. 示例: 输入: "aab" 输出: ...
最新文章
- java的byte php_java_浅谈java的byte数组的不同写法,(由于篇幅原因阐述的不够详 - phpStudy...
- MATLAB垂直搜索图片中的白段
- golang 开发常见坑
- mysql输入select now()_mysql 中select now(); 是怎么执行的?没有指定FROM tablename?
- 关于ABAP排序不稳定的问题
- save()、saveOrUpdate()、merge()的区别
- 十、input与跳转
- 证券期货行业监管大数据治理方案研究
- 让两个灯隔断时间交替闪烁的电路
- 热议:为什么近些年硕士生考博意愿偏低?
- 海康SDK设备信息NET_DVR_GET_DEVICECFG解析
- HEVC中的样点自适应补偿——Sample Adaptive Offset (SAO)
- java如何使用移位运算符_JAVA移位运算符使用教程
- 影响因子在10的计算机杂志什么水平,国人无人发表的TOP期刊,影响因子翻倍,5分变10分,不收版面费!...
- 消息队列原理和应用场景总结
- JDK 内置的轻量级 HTTP 服务器 --- HttpServer
- 菜鸟Python实战-05爬虫之爬取视频
- 计算机睡眠和休眠哪个更好,电脑睡眠和休眠哪个好?电脑休眠和睡眠的区别介绍...
- RecyclerView 实现横向滚动效果
- encode()和decode()