6.8 回溯+数组

This commit is contained in:
zhangsan 2025-06-08 19:52:25 +08:00
parent 5871e339f1
commit a26333688a
3 changed files with 130 additions and 14 deletions

View File

@ -0,0 +1,42 @@
package array;
/**
* 题目 941. 有效的山脉数组 (validMountainArray)
* 描述给定一个整数数组 arr如果它是有效的山脉数组就返回 true否则返回 false
*
* 让我们回顾一下如果 arr 满足下述条件那么它是一个山脉数组
*
* arr.length >= 3
* 0 < i < arr.length - 1 条件下存在 i 使得
* arr[0] < arr[1] < ... arr[i-1] < arr[i]
* arr[i] > arr[i+1] > ... > arr[arr.length - 1]
示例 1
输入arr = [2,1]
输出false
* 链接https://leetcode.cn/problems/valid-mountain-array/
*/
public class ValidMountainArray {
public boolean validMountainArray(int[] arr) {
if (arr.length < 3) { // 此时一定不是有效的山脉数组
return false;
}
// 双指针
int left = 0;
int right = arr.length - 1;
// 注意防止指针越界
while (left + 1 < arr.length && arr[left] < arr[left + 1]) {
left++;
}
// 注意防止指针越界
while (right > 0 && arr[right] < arr[right - 1]) {
right--;
}
// 如果left或者right都在起始位置说明不是山峰
if (left == right && left != 0 && right != arr.length - 1) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,55 @@
package backtrack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 题目 491. 非递减子序列 (findSubsequences)
* 描述给你一个整数数组 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]]
* 链接https://leetcode.cn/problems/palindrome-partitioning/
*/
//不会做
public class FindSubsequences {
/**
* 用一个局部 Set<Integer> used 来去重保证同一深度只选一次相同的数字
* 只有当当前路径为空或新加入的数字 路径最后一个数字时才继续深入
* 每次路径长度达到 2 就收集一组结果
* @param nums
* @return
*/
public List<List<Integer>> findSubsequences(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
backtrack(nums, 0, new ArrayList<>(), res);
return res;
}
private void backtrack(int[] nums, int start, List<Integer> path, List<List<Integer>> res) {
// 只要当前 path 长度 2就把它加入结果集
if (path.size() >= 2) {
res.add(new ArrayList<>(path));
}
// 用来在本层去重防止同一层重复使用相同数字 这一步太妙了
Set<Integer> used = new HashSet<>();
for (int i = start; i < nums.length; i++) {
// 如果本层已经用过 nums[i]跳过
if (used.contains(nums[i])) continue;
// 如果 path 为空或满足非递减条件就可以选 nums[i]
if (path.isEmpty() || nums[i] >= path.get(path.size() - 1)) {
used.add(nums[i]);
path.add(nums[i]);
// 递归到下一层 i+1 开始选
backtrack(nums, i + 1, path, res);
// 撤销选择
path.remove(path.size() - 1);
}
}
}
}

View File

@ -1,5 +1,6 @@
package backtrack;
import java.util.ArrayList;
import java.util.List;
@ -17,23 +18,41 @@ import java.util.List;
* 链接https://leetcode.cn/problems/restore-ip-addresses/
*/
public class RestoreIpAddresses {
void dfs(List<String>res,List<String>path,String s,int minStep){
if(path.size()==4){
StringBuilder sb=new StringBuilder();
sb.append(path.get(0));
for (int i = 1; i < path.size(); i++) {
sb.append('.').append(path.get(i));
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
dfs(s, 0, 0, new StringBuilder(), res);
return res;
}
private void dfs(String s, int start, int segment, StringBuilder sb, List<String> res) {
// 如果已经凑够 4 且正好遍历完字符串
if (segment == 4) {
if (start == s.length()) {
// 去掉最后多余的 .
res.add(sb.substring(0, sb.length() - 1));
}
res.add(sb.toString());
return;
}
for (int i = minStep; i < s.length(); i++) {
// 剩余字符太少或太多提前剪枝
int remain = s.length() - start;
if (remain < (4 - segment) || remain > (4 - segment) * 3) return; //很妙
// 尝试长度为 123 的子段
for (int len = 1; len <= 3 && start + len <= s.length(); len++) {
String part = s.substring(start, start + len);
if (!isValidPart(part)) continue;
int before = sb.length();
sb.append(part).append('.');
dfs(s, start + len, segment + 1, sb, res);
// 回溯删除 数字 + 的长度
sb.delete(before, sb.length());
}
}
public List<String> restoreIpAddresses(String s) {
List<String>res=new ArrayList<>();
List<String>path=new ArrayList<>();
StringBuilder sb=new StringBuilder();
return null;
private boolean isValidPart(String part) {
// 单字符0合法多于 1 位时不能以 0 开头且数值 255
if (part.length() > 1 && part.startsWith("0")) return false;
return Integer.parseInt(part) <= 255;
}
}