9.28lc:
今日首次接触 回溯算法的
初次理解: 所谓的回溯 本质依然是 暴力破解: 只不过是在原有递归的基础上,进行了 往回倒转的操作 来达到目的!
常见的算法题型: 组合 排列 棋盘 数独 等
今日总结: 5道题 写了 3个小时… 越写越难受。还是太菜了 >~<…
77. 组合 - 力扣(LeetCode) (leetcode-cn.com)
:常见的模板:
将原有的组合问题 转换转换成了 “多叉树”来解决~:
-
使用 for 循环 表示 横向的
-
使用 递归 表示 纵向的
-
模板:
-
//一般没有返回值 public void backtracking(int n,int k,int start){ //结束条件 if(path.size() == k){ result.add(new LinkedList<>(path) ); return; } //剪枝操作 就是去掉 多余的结果 减少时间 //横向发展条件 for(int i=start;i<=n-(k-path.size())+1;i++){ path.add(i); //纵向发展条件 backtracking(n,k,i+1); //回溯动作 path.removeLast(); }
class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backtracking(n,k,1);
return result;
}
public void backtracking(int n,int k,int start){
if(path.size() == k){
result.add(new LinkedList<>(path) );
return;
}
//剪枝操作 就是去掉 多余的结果 减少时间
for(int i=start;i<=n-(k-path.size())+1;i++){
path.add(i);
backtracking(n,k,i+1);
path.removeLast();
}
}
}
46. 全排列 - 力扣(LeetCode) (leetcode-cn.com)
:解题思路类似于 上一题:
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
backTracking(nums);
return res;
}
public void backTracking(int[] nums){
if(path.size() == nums.length){
//new 是因为 后面是 list变化的 所以就是new 比影响后面
res.add(new ArrayList<>(path));
return;
}
for(int i=0;i<nums.length;i++){
if(! path.contains(nums[i])){
path.add(nums[i]);
backTracking(nums);
path.remove(path.size()-1);
}
}
}
}
112. 路径总和 - 力扣(LeetCode) (leetcode-cn.com)
又到了最爱的 二叉树 递归环节~~
类似于 前缀和的感觉~
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 从下往上走的好理解
//每个节点的值 并不是通过 和 找的
//而是通过 target-root.val = 当前的值 来
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) return false;
else if (root.val == targetSum && root.left == null && root.right ==null ) return true;
return hasPathSum(root.left, targetSum - root.val)
|| hasPathSum(root.right, targetSum - root.val);
}
}
226. 翻转二叉树 - 力扣(LeetCode) (leetcode-cn.com)
这道题看似简单: 上来我就写错了…
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
//交换子树的值
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)
这题的递归没弄懂 看的题解的答案。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int post_idx;
int[] postorder;
int[] inorder;
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
public TreeNode helper(int in_left, int in_right) {
// 如果这里没有节点构造二叉树了,就结束
if (in_left > in_right) {
return null;
}
// 选择 post_idx 位置的元素作为当前子树根节点
int root_val = postorder[post_idx];
TreeNode root = new TreeNode(root_val);
// 根据 root 所在位置分成左右两棵子树
int index = idx_map.get(root_val);
// 下标减一
post_idx--;
// 构造右子树
root.right = helper(index + 1, in_right);
// 构造左子树
root.left = helper(in_left, index - 1);
return root;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postorder = postorder;
this.inorder = inorder;
// 从后序遍历的最后一个元素开始
post_idx = postorder.length - 1;
// 建立(元素,下标)键值对的哈希表
int idx = 0;
for (Integer val : inorder) {
idx_map.put(val, idx++);
}
return helper(0, inorder.length - 1);
}
}