剑指Offer(38-47)
38.输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
//递归做法
public class Test38 {
public int TreeDepth(TreeNode root) {
//到达叶子的子节点,返回上一级,从0开始加
if (root==null){
return 0;
}
//递归左右子树
int left = TreeDepth(root.left);
int right = TreeDepth(root.right);
//从0开始加,每返回上一级就加一,比较左右子树,返回大的。
return Math.max(left,right)+1;
}
}
//思路二:利用树的层次搜索
public class Test38_2 {
public int TreeDepth(TreeNode root) {
if (root==null) return 0;
Queue<TreeNode> queue = new LinkedList();
queue.offer(root);
//cur记录访问到当前层的第几个,widtd为当前层的宽度
int size;
int deep=0;
while (!queue.isEmpty()){
//定义每层的结点数
size = queue.size();
//层数增加的条件,当每层结点遍历完后,遍历下一层
for (int i=0;i<size;i++){
//root = 推出来的结点
root = queue.poll();
if (root.left!=null)queue.offer(root.left);
if (root.right!=null)queue.offer(root.right);
System.out.println(size+" ");
}
//遍历一层后,deep(深度)加一
deep++;
}
return deep;
}
}
39.输入一棵二叉树,判断该二叉树是否是平衡二叉树。
是上一题的改编
//平衡二叉树:左右子树也是平衡二叉树,左右子树的高度差小于1
public class Test39 {
public boolean IsBalanced_Solution(TreeNode root) {
return deep(root) != -1;
}
public int deep(TreeNode root){
if(root==null) return 0;
int left = deep(root.left);
if (left==-1) return -1;//判断左子树是不是平衡二叉树
int right = deep(root.right);
if (right==-1) return -1;//判断右子树是不是平衡二叉树
//比较高度差,也是上一题的附加步骤
if (right-left<-1||right-left>1)
return -1;
else
return Math.max(left,right)+1;
}
}
40.一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
//思路一
//用hash算法,存入hashmap,值为1,如果键存在,值设置为2
public class Test40 {
//题目给出的:
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
HashMap<Integer,Integer> map = new HashMap<>();
for (int i=0;i<array.length;i++){
if (map.containsKey(array[i])){
map.put(array[i],2);
}else {
map.put(array[i],1);
}
}
int j=0;
for (int i=0;i<array.length;i++){
if((int)map.get(array[i])==1){
if (j==0){
num1[0] = array[i];
j++;
}else {
num2[0] = array[i];
}
}
}
}
}
//思路二
//1、数组排序
//2、使用栈进行从小到大入栈,一样的则弹出,不一样则入栈
//3、取栈中剩余的元素
public class Test40_2 {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
//冒泡排序
for(int i=0;i<array.length-1;i++){
for(int j=array.length-1;j>i;j--){
if (array[j]<array[j-1]){
swap(array,j-1,j);
}
}
}
Stack<Integer> stack = new Stack<>();
for (int i=0;i<array.length;i++){
if(stack.empty()||stack.peek()!=array[i]){
stack.push(array[i]);
}else if (stack.peek() == array[i]){
stack.pop();
}
}
num1[0] = stack.pop();
num2[0] = stack.pop();
}
private void swap(int[] array,int i,int j){
int tem = array[i];
array[i] = array[j];
array[j] = tem;
}
}
##41.小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。
###现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
//利用双指针和滑动窗口,plow和phigh分别指向前后两个数
public class Test41 {
public ArrayList<ArrayList
int plow = 1, phigh = 2;
List<ArrayList<Integer>> result = new ArrayList<>();
while (plow<phigh){
//差为一的等差数列,用等差数列求和公式(a0+an)*n/2
int count = (phigh-plow+1)*(phigh+plow)/2;
if (count==sum){
List<Integer> list = new ArrayList<>();
for (int i=plow;i<=phigh;i++){
list.add(i);
}
result.add((ArrayList)list);
phigh++; plow++;
}else if (count>sum){
plow++;
}else {
phigh++;
}
}
return (ArrayList)result;
}
}
##42.输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
//和上一题看似差不多,头一次也是类似的做法,但是上一题是连续的数,这一题没有
//所以上一题用滑动窗口,这一题可以用夹逼,两个指针指向两端并不断逼近
//PS:如果和相同,那么差越大,乘积越小
public class Test42 {
public ArrayList
List
if (array.length<2||arraynull){
return (ArrayList)result;
}
int i=0, j=array.length-1;
while (i<j){
int count = array[i]+array[j];
if (countsum){
result.add(array[i]);
result.add(array[j]);
return (ArrayList)result;
}else if(count<sum){
i++;
}else {
j--;
}
}
return (ArrayList)result;
}
}

浙公网安备 33010602011771号