请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
理解不了题意
但是回过头来一看还是挺简单的 但是他“以 ! 表示一个结点值的结束(value!)” 体现在哪?
链接:https://www.nowcoder.com/questionTerminal/cf7e25aa97c04cc1a68c8f040e71fb84?f=discussion
来源:牛客网
/*
算法思想:根据前序遍历规则完成序列化与反序列化。所谓序列化指的是遍历二叉树为字符串;所谓反序列化指的是依据字符串重新构造成二叉树。
依据前序遍历序列来序列化二叉树,因为前序遍历序列是从根结点开始的。当在遍历二叉树时碰到Null指针时,这些Null指针被序列化为一个特殊的字符“#”。
另外,结点之间的数值用逗号隔开。
*/
public class Solution {
int index = -1; //计数变量
String Serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
if(root == null){
sb.append("#,");
return sb.toString();
}
//先序遍历
sb.append(root.val + ",");
sb.append(Serialize(root.left));
sb.append(Serialize(root.right));
return sb.toString();
}
TreeNode Deserialize(String str) {
index++;
//int len = str.length();
//if(index >= len){
// return null;
// }
String[] strr = str.split(",");
TreeNode node = null;
if(!strr[index].equals("#")){
node = new TreeNode(Integer.valueOf(strr[index]));
node.left = Deserialize(str);
node.right = Deserialize(str);
}
return node;
}
}
中序遍历,到第k个就结束遍历,k为0或k大于节点数就返回null
import java.util.*;
public class Solution {
static ArrayList<TreeNode> nodes;
static int count;
static int k;
public void midOrder(TreeNode root) {
if (count == k) return;
if (root == null) return;
if (root.left != null) {
midOrder(root.left);
}
nodes.add(root);
count++;
if (root.right != null) {
midOrder(root.right);
}
return;
}
TreeNode KthNode(TreeNode pRoot, int k) {
count = 0;
nodes = new ArrayList<TreeNode>();
if (k == 0) return null;
this.k = k;
midOrder(pRoot);
if (k > count) return null;
return nodes.get(k - 1);
}
}
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数
我的暴力写法
import java.util.*;
public class Solution {
static ArrayList<Integer> nums=new ArrayList<Integer>();
public void Insert(Integer num) {
nums.add(num);
}
public Double GetMedian() {
int len= nums.size();
//每一次查询中位数,都需要先排序,根据这一特点其实可以考虚优先队列
Collections.sort(nums);
if(len%2==0){
return (Double.valueOf(nums.get(len/2))+Double.valueOf(nums.get(len/2-1)))/2;
}
else{
return Double.valueOf(nums.get(len/2));
}
}
}
参考
private int cnt = 0;
private PriorityQueue<Integer> low = new PriorityQueue<>();
// 默认维护小顶堆
private PriorityQueue<Integer> high = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
public void Insert(Integer num) {
// 数量++
cnt++;
// 如果为奇数的话
if ((cnt & 1) == 1) {
// 由于奇数,需要存放在大顶堆上
// 但是呢,现在你不知道num与小顶堆的情况
// 小顶堆存放的是后半段大的数
// 如果当前值比小顶堆上的那个数更大
if (!low.isEmpty() && num > low.peek()) {
// 存进去
low.offer(num);
// 然后在将那个最小的吐出来
num = low.poll();
} // 最小的就放到大顶堆,因为它存放前半段
high.offer(num);
} else {
// 偶数的话,此时需要存放的是小的数
// 注意无论是大顶堆还是小顶堆,吐出数的前提是得有数
if (!high.isEmpty() && num < high.peek()) {
high.offer(num);
num = high.poll();
} // 大数被吐出,小顶堆插入
low.offer(num);
}
}
public Double GetMedian() {// 表明是偶数
double res = 0;
// 奇数
if ((cnt & 1) == 1) {
res = high.peek();
} else {
res = (high.peek() + low.peek()) / 2.0;
}
return res;
}
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
我的代码,依旧暴力
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{ ArrayList<Integer> res=new ArrayList<Integer>();
if(size<=0||size>num.length){
return res;
}
int len = num.length;
int start=0;
int end=size-1;
int flag=0;
while(end<len){
int max=num[start];
for(int i=start;i<=end;i++){
if(num[i]>max){
max=num[i];
}
}
res.add(max);
start++;
end++;
}
return res;
}
}
import java.util.*;
//思路:用一个大顶堆,保存当前滑动窗口中的数据。滑动窗口每次移动一格,就将前面一个数出堆,后面一个数入堆。
public class Solution {
public PriorityQueue<Integer> maxQueue = new PriorityQueue<Integer>((o1,o2)->o2-o1);//大顶堆
public ArrayList<Integer> result = new ArrayList<Integer>();//保存结果
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
if(num==null || num.length<=0 || size<=0 || size>num.length){
return result;
}
int count=0;
for(;count<size;count++){//初始化滑动窗口
maxQueue.offer(num[count]);
}
while(count<num.length){//对每次操作,找到最大值(用优先队列的大顶堆),然后向后滑动(出堆一个,入堆一个)
result.add(maxQueue.peek());
maxQueue.remove(num[count-size]);
maxQueue.add(num[count]);
count++;
}
result.add(maxQueue.peek());//最后一次入堆后没保存结果,这里额外做一次即可
return result;
}
}
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。
我的代码,只过了30%,其实跟参考的也是类似的,但就是不知道哪里不对
public class Solution {
static int flag;
static int row;
static int col;
static boolean[][] vis;
public static void dfs(char[] matrix,int x,int y ,char[] str, int cur){
int len=str.length;
if(cur==len){
flag=1;
return;
}
if(flag==1){
return;
}
if((x>=0&&x<row)&&(y<col&&y>=0)){
if(!vis[x][y]&&matrix[x*col+y]==str[cur]){
vis[x][y]=true;
int[] x_index={0,0,-1,1};
int[] y_index={1,-1,0,0};
for(int i=0;i<4;i++){
dfs(matrix,x+x_index[i],y+y_index[i],str,cur+1);
}
}
}
return;
}
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
flag=0;
row=rows;
col=cols;
vis=new boolean[row][col];
for (int i = 0; i <rows ; i++) {
for (int j = 0; j <cols ; j++) {
if(flag==1){
return true;
}
if(matrix[i*cols+j]==str[0]){
dfs(matrix,i,j,str,0);
}
}
}
return false;
}
}
参考
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//标志位,初始化为false
boolean[] flag = new boolean[matrix.length];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
//循环遍历二维数组,找到起点等于str第一个元素的值,再递归判断四周是否有符合条件的----回溯法
if(judge(matrix,i,j,rows,cols,flag,str,0)){
return true;
}
}
}
return false;
}
//judge(初始矩阵,索引行坐标i,索引纵坐标j,矩阵行数,矩阵列数,待判断的字符串,字符串索引初始为0即先判断字符串的第一位)
private boolean judge(char[] matrix,int i,int j,int rows,int cols,boolean[] flag,char[] str,int k){
//先根据i和j计算匹配的第一个元素转为一维数组的位置
int index = i*cols+j;
//递归终止条件
if(i<0 || j<0 || i>=rows || j>=cols || matrix[index] != str[k] || flag[index] == true)
return false;
//若k已经到达str末尾了,说明之前的都已经匹配成功了,直接返回true即可
if(k == str.length-1)
return true;
//要走的第一个位置置为true,表示已经走过了
flag[index] = true;
//回溯,递归寻找,每次找到了就给k加一,找不到,还原
if(judge(matrix,i-1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i+1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i,j-1,rows,cols,flag,str,k+1) ||
judge(matrix,i,j+1,rows,cols,flag,str,k+1) )
{
return true;
}
//走到这,说明这一条路不通,还原,再试其他的路径
flag[index] = false;
return false;
}}
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
//经典的dfs,反而在细节上踩了不少坑,醉了
public class Solution {
static int count;
static boolean[][] vis;
static int row;
static int col;
public boolean judge(int x, int y, int threshold) {
String s1 = String.valueOf(x);
String s2 = String.valueOf(y);
char[] c = (s1 + s2).toCharArray();
int sum = 0;
for (int i = 0; i < c.length; i++) {
sum += Integer.parseInt(String.valueOf(c[i]));
}
if (sum > threshold) {
return false;
} else {
return true;
}
}
public void dfs(int x, int y, int threshold) {
int[] x_index = {0, 0, -1, 1};
int[] y_index = {-1, 1, 0, 0};
if ((x >= 0 && x < row) && (y >= 0 && y < col)) {
if (judge(x, y, threshold) && !vis[x][y]) {
vis[x][y] = true;
count++;
for (int i = 0; i <4 ; i++) {
dfs(x+x_index[i],y+y_index[i],threshold);
}
}
}
return;
}
public int movingCount(int threshold, int rows, int cols) {
row = rows;
count=0;
col = cols;
vis = new boolean[rows][cols];
dfs(0, 0, threshold);
return count;
}}
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
public class Solution {
public int cutRope(int n) {
// n<=3的情况,m>1必须要分段,例如:3必须分成1、2;1、1、1 ,n=3最大分段乘积是2,
if(n==2)
return 1;
if(n==3)
return 2;
int[] dp = new int[n+1];
/*
下面3行是n>=4的情况,跟n<=3不同,4可以分很多段,比如分成1、3,
这里的3可以不需要再分了,因为3分段最大才2,不分就是3。记录最大的。
*/
dp[1]=1;
dp[2]=2;
dp[3]=3;
int res=0;//记录最大的
for (int i = 4; i <= n; i++) {
for (int j = 1; j <=i/2 ; j++) {
res=Math.max(res,dp[j]*dp[i-j]);
}
dp[i]=res;
}
return dp[n];
}
}