61序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
思路:
对于序列化:使用前序遍历,递归的将二叉树的值转化为字符,并且在每次二叉树的节点不为空时,在转化val所得的字符之后添加一个’,‘作为分割,对于空节点则使用’#'代替
对于反序列化:按照前序顺序,递归的使用字符串的字符创建一个二叉树
package com.matajie;
/**
* 61序列化二叉树
* 题目描述
*
* 请实现两个函数,分别用来序列化和反序列化二叉树
*
* 我的程序才不会有bug!
* author:年仅18岁的天才少年程序员丶mata杰
**/
public class Serialize {
public int index = -1;
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
String Serialize(TreeNode root) {
StringBuffer sb = new StringBuffer();
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();
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;
}
}
62.二叉搜索树的第K个节点
题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路:
二叉搜索树按照中序遍历的顺序打印出来正好就是排序号的顺序,所以按照中序遍历顺序找到第K个节点就是结果
package com.matajie;
/**
* 62.二叉搜索树的第K个节点
* 题目描述
*
* 给定一棵二叉搜索树,请找出其中的第k小的结点。
* 例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
*
* #
*
* 我的程序才不会有bug!
* author:年仅18岁的天才少年程序员丶mata杰
**/
public class KthNode {
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
int index = 0;//放在方法里每一次都重置
TreeNode KthNode(TreeNode pRoot, int k)
{
if(pRoot != null){
TreeNode node = KthNode(pRoot.left,k);
if(node != null)
return node;
index++;
if(index == k)
return pRoot;
node = KthNode(pRoot.right,k);
if(pRoot != null)
return node;
}
return null;
}
}
解释: if(pRoot != null)这行代码
如果没有这行代码,那么pRoot就是返回给上一级的父节点的,而不是递归结束的条件了,有了这行代码,一旦返回了pRoot,那么node就不会为空了,就一直一层一层的递归出去到结束了.
例如{8,6,5,7},K=1答案应该时是5,如果不加的话,
开始pRoot = 8,node = KthNode(6,1)
继续pRoot = 6,node = KthNode(5,1)
pRoot返回null
这时向下执行index = k =1了,返回5给pRoot = 6递归时候的node,这时回到pRoot = 8了.往后面调右孩子的时候为空而把5给覆盖了,有了这句话虽然为空,但不把null返回,而是继续返回5
63.数据流中的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:
用Java集合priorityQueue来设置一个小顶堆和大顶堆.因为要求是中位数,那么这两个堆,大顶堆用来存较小的数,从大到小排序,小顶堆存较大的数,从小到大排序.显然中位数就是大顶堆的根节点和小顶堆的根节点的和的平均数.
- 小顶堆中的元素都大于等于大顶堆中的元素,所以每次塞值,并不是直接塞进去,而是从另一个堆中poll出一个最大(最小)的塞值.
- 当数目为偶数时,将这个值插入大顶堆中,再将大顶堆中根节点(即最大值)插入到小顶堆中.
- 当数目为奇数时,将这个值插入小顶堆中,再将小顶堆中根节点(即最小值)插入到大顶堆中.
- 取中位数时如果当前个数为偶数,显然是取小顶堆和大顶堆根节点的平均值,如果当前个数为奇数,显然是取小顶堆的根节点.
例如:[5,2,3,4,1,6,7,0,8]
- 5先进入大顶堆,然后将大顶堆中最大值放入小顶堆中,min = [5],max = [无],avg = [5.00].
- 5先进入小顶堆,然后将大顶堆中最小值放入大顶堆中,min = [5],max = [2],avg = [3.50].
- 5先进入大顶堆,然后将大顶堆中最大值放入小顶堆中,min = [3.5],max = [2],avg = [3.00].
- 5先进入小顶堆,然后将大顶堆中最小值放入大顶堆中,min = [4,5],max = [3,2],avg = [3.50].
- 5先进入大顶堆,然后将大顶堆中最大值放入小顶堆中,min = [3,45],max=[2,1],avg = [3.00].
…
package com.matajie;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* 我的程序才不会有bug!
* author:年仅18岁的天才少年程序员丶mata杰
**/
public class Insert {
private PriorityQueue<Integer> minHeap = new PriorityQueue();
private PriorityQueue<Integer> maxHeap = new PriorityQueue(15, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
int count = 0;//记录偶数个还是奇数个
public void Insert(Integer num) {
if(count % 2 == 0){
maxHeap.offer(num);
int max = maxHeap.poll();
minHeap.offer(max);
}else {
minHeap.offer(num);
int min = minHeap.poll();
maxHeap.offer(min);
}
count++;
}
public Double GetMedian() {
if(count % 2 == 0)
return new Double(minHeap.peek()+maxHeap.peek())/2;//偶数个求平均
else {
return new Double (minHeap.peek());//奇数个取小顶堆即可
}
}
}
64.滑动窗口的最大值
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
思路:
滑动窗口应当是队列,但为了得到滑动窗口的最大值,队列序可以从两端删除元素,因此使用双端队列.
对新来的元素K,将其与双端队列中的元素相比较.
- 前面比K小的,直接移出队列(因为不可能成为后面滑动窗口的最大值了)
- 前面比K大的X,比较两者下标判断X是否已经不在窗口之内,不在了直接移出队列,队列第一个位置保存当前窗口的最大值.
package com.matajie;
import java.util.ArrayDeque;
import java.util.ArrayList;
/**
* 64.滑动窗口的最大值
* 题目描述
*
*
* 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
* 例如,如果输入数组{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]}。
*
* 我的程序才不会有bug!
* author:年仅18岁的天才少年程序员丶mata杰
**/
public class MaxInWindows {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> res = new ArrayList<>();
if(size == 0) return res;
int begin;
ArrayDeque<Integer> q = new ArrayDeque<>();//双端队列保存的是下标
for(int i = 0;i<num.length;i++){
begin = i - size + 1;//begin用来保存当前窗口的第一个值在原始数组中的下标,这样写的目的是为了少些一些判断边界条件.
if(q.isEmpty()){
q.add(i);
}else if(begin > q.peekFirst())
q.pollFirst();
while ((!q.isEmpty() && num[q.peekLast()] <= num[i]))
q.pollLast();//返回队列第一个元素,但不删除这个元素
q.add(i);
if(begin >= 0)
res.add(num[q.peekFirst()]);
}
return res;
}
}
65.矩阵中的路径
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路:
用一个状态数组保存之前访问过的字符,然后再分别按上下左右递归
package com.matajie;
/**
* 65.矩阵中的路径
* 题目描述
*
* 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
* 路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
* 如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。
* 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,
* 但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
*
* 我的程序才不会有bug!
* author:年仅18岁的天才少年程序员丶mata杰
**/
public class HasPath {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
int flag[] = new int[matrix.length];
for(int i = 0 ;i<rows;i++){
for(int j = 0;j<cols;j++){
if(helper(matrix,rows,cols,i,j,str,0,flag))//回溯法:循环遍历二维数组,找到七点等于str第一个元素的值,再递归判断四周是否又符合条件的
return true;
}
}
return false;
}
//初始矩阵 矩阵行数 矩阵列数 索引行坐标i,索引纵坐标j, k:字符串索引初始为0,即先判断字符串的第一位
private boolean helper(char[] matrix,int rows,int cols,int i ,int j, char[] str,int k,int[] flag){
int index = i * cols + j;//i是行数,每行有cols个数,所以i*cols,第j列就+j,,即根据i和j计算匹配的第一个元素转为一维数组的位置
if(i < 0 || i >= rows || j <0 || j >= cols || matrix[index] != str[k] || flag[index] == 1)//递归终止条件
return false;
if( k == str.length-1)//若k已经到达str末尾,说明之前的已经匹配成功,直接返回true即可
return true;
flag[index] = 1;//要走的位置置为1,表示已经走过
//如果4个判断条件全部为false,说明不应该来到index寻找路径,也就是我们不走index这个位置了,回到index之前的位置,所以flag[index] = 0,
//表示我们暂时不走index了,但是以后是可能走的,如果不重设flag[index] = 0,以后也走不了了
//递归寻找,每次找到了就给k+1,找不到还原
if(helper(matrix,rows,cols,i-1,j,str,k+1,flag)//
||helper(matrix,rows,cols,i+1,j,str,k+1,flag)
||helper(matrix,rows,cols,i,j-1,str,k+1,flag)
||helper(matrix,rows,cols,i,j+1,str,k+1,flag)){
return true;
}
flag[index] = 0;//条件不符合,还原为未访问过的标记.
return false;
}
}
66.机器人的运动范围
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。
例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:回溯法
当机器人准备进入坐标为(i,j)的格子时,通过检查坐标的数位和来判断机器人是否能够进入,如果能进,再判断它能否进入四个相邻的格子(i,j-1),(i-1,j),(i,j+1)和(i+1,j).
package com.matajie;
/**
* 66.机器人的运动范围
* 题目描述
*
*
* 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,
* 每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。
* 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
* 但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
*
* 我的程序才不会有bug!
* author:年仅18岁的天才少年程序员丶mata杰
**/
public class MovingCount {
public int movingCount(int threshold, int rows, int cols)
{
int flag[][] = new int[rows][cols];//记录是否已经走过
return helper(0,0,rows,cols,flag,threshold);
}
private int helper(int i ,int j,int rows,int cols,int[][] flag,int threshold){
//判断flag[i][j],如果它为1,则说明已经走过,就会返回0
if(i < 0 || i >= rows || j < 0 || j >= cols || numSum(i) + numSum(j) > threshold||flag[i][j] == 1){
return 0;
}
flag[i][j] = 1;
return helper(i-1,j,rows,cols,flag,threshold)
+ helper(i+1,j,rows,cols,flag,threshold)
+ helper(i,j-1,rows,cols,flag,threshold)
+ helper(i,j+1,rows,cols,flag,threshold)
+1;
}
private int numSum(int i){
int sum = 0;
do {
sum += i%10;
}while ((i = i/10) > 0);
return sum;
}
}