文章目录
- 前言
- 🎨 1、二叉树中和为某一值的路径
- 题目描述
- 思路(深度优先搜索)
- 🎨 2、复杂链表的复制
- 题目描述
- 思路
- 🎨 3、二叉搜索树与双向链表
- 题目描述
- 思路
- 🎨 4、字符串的排列
- 题目描述
- 思路(递归+回溯)
前言
题目来源参考阿秀学长的刷题笔记,小戴只是把 C++的题解改成了 Java版本,并整理了其他思路,便于自己的学习~
如果解题有更好的方法,本文也会及时进行更新~
希望对你有帮助~ 一起加油哇~
🎨 1、二叉树中和为某一值的路径
牛客原题链接
题目描述
输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径
思路(深度优先搜索)
import java.util.ArrayList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
private ArrayList<ArrayList<Integer>> res;
private ArrayList<Integer> path;
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int expectNumber) {
res = new ArrayList<>();
path = new ArrayList<>();
dfs(root,expectNumber);
return res;
}
public void dfs(TreeNode root,int expectNumber){
// 处理树为空
if(root == null) return;
path.add(root.val);
expectNumber -= root.val;
if(root.left == null && root.right == null && expectNumber == 0){
res.add(new ArrayList<>(path));
}
// 左右子树递归
dfs(root.left,expectNumber);
dfs(root.right,expectNumber);
// 回溯
path.remove(path.size()-1);
}
}
🎨 2、复杂链表的复制
牛客原题链接
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if(pHead == null) return null;
RandomListNode cur = pHead;
// 遍历原始链表,复制链表节点
while(cur != null){
// 拷贝节点
RandomListNode clone = new RandomListNode(cur.label);
// 将新节点插入到被拷贝的节点之后
clone.next = cur.next;
cur.next = clone;
cur = clone.next;
}
// 遍历原始链表,复制随机节点
cur = pHead;
RandomListNode clone = pHead.next;
while(cur != null){
if(cur.random == null){
clone.random = null;
}else{
clone.random = cur.random.next;
}
cur = cur.next.next;
if(clone.next != null){
clone = clone.next.next;
}
}
RandomListNode res = pHead.next;
// 遍历链表,进行拆分
cur = pHead;
clone = pHead.next;
while(cur != null){
cur.next = cur.next.next;
cur = cur.next;
if(clone.next != null){
clone.next = clone.next.next;
}
clone = clone.next;
}
return res;
}
}
🎨 3、二叉搜索树与双向链表
牛客原题链接
题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
// 返回的第一个指针,即为最小值,先定为null
public TreeNode head = null;
// 中序遍历当前值的上一位,初值为最小值,先定为null
public TreeNode pre = null;
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null){
return null;
}
// 首先递归到最左最小值
Convert(pRootOfTree.left);
// 找到最小值,初始化head和pre
if(pre == null){
head = pRootOfTree;
pre = pRootOfTree;
}
// 当前节点与上一节点建立连接,将pre设置为当前值
else{
pre.right = pRootOfTree;
pRootOfTree.left = pre;
pre = pRootOfTree;
}
Convert(pRootOfTree.right);
return head;
}
}
🎨 4、字符串的排列
牛客原题链接
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba
思路(递归+回溯)
- 先对字符串按照字典序排序,获取第一个排列情况。
- 准备一个空串暂存递归过程中组装的排列情况。使用额外的vis数组用于记录哪些位置的字符被加入了。
- 每次递归从头遍历字符串,获取字符加入:首先根据vis数组,已经加入的元素不能再次加入了;同时,如果当前的元素str[i]与同一层的前一个元素str[i-1]相同且str[i-1]已经用,也不需要将其纳入。
- 进入下一层递归前将vis数组当前位置标记为使用过。
- 回溯的时候需要修改vis数组当前位置标记,同时去掉刚刚加入字符串的元素,
- 临时字符串长度到达原串长度就是一种排列情况。
import java.util.*;
public class Solution {
public void recursion(ArrayList<String> res,char[] str,StringBuffer temp,boolean[] vis){
if(temp.length() == str.length){
res.add(new String(temp));
return;
}
// 遍历所有元素选取一个加入
for(int i = 0; i < str.length; i++){
// 如果该元素已经被加入,则不需要再加入了
if(vis[i]){
continue;
}
if(i > 0 && str[i-1] == str[i] && !vis[i-1]){
// 当前元素str[i]与同一层的前一个元素str[i-1]相同且str[i-1]已经被使用
continue;
}
// 标记为使用过
vis[i] = true;
// 加入临时字符串
temp.append(str[i]);
recursion(res,str,temp,vis);
//回溯
vis[i] = false;
temp.deleteCharAt(temp.length()-1);
}
}
public ArrayList<String> Permutation(String str) {
ArrayList<String> res = new ArrayList<String>();
if(str == null || str.length() == 0){
return res;
}
// 转字符数组
char[] charStr = str.toCharArray();
// 按字典序排序
Arrays.sort(charStr);
boolean[] vis = new boolean[str.length()];
// 标记每个位置的字符是否被使用过
Arrays.fill(vis,false);
StringBuffer temp = new StringBuffer();
// 递归获取
recursion(res,charStr,temp,vis);
return res;
}
}