剑指offer题解15

60 二叉搜索树的第k个节点

题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

分析:根据性质,中序遍历即可


//中序遍历
public class Solution {
    int count=0;
    TreeNode KthNode(TreeNode pRoot, int k)
    {
       if(pRoot==null){
           return null;
       }
        
        TreeNode node=KthNode(pRoot.left,k);
        //如果没有达到目标,一定返回null,根据返回是否是null来判断是否成功获取到了值
        if(node!=null){
            return node;
        }
        
        count++;
        if(count==k){
            return pRoot;
        }
        
        node=KthNode(pRoot.right,k);
        if(node!=null){
            return node;
        }
        return node;
    }
}


//非递归
public class Solution {
    int count=0;
    TreeNode KthNode(TreeNode pRoot, int k)
    {
       if(pRoot==null||k==0){
           return null;
       }
        Stack<TreeNode> stack=new Stack<>();
        
        while(pRoot!=null||!stack.isEmpty()){
            if(pRoot!=null){
                stack.push(pRoot);
                pRoot=pRoot.left;
            }else{
                pRoot=stack.pop();
                count++;
                if(count==k){
                    return pRoot;
                }
                pRoot=pRoot.right;
                
            }
        }
        return null;
        
    }


}

61 数据流中的中位数

题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

分析:维护两个堆,一个大顶堆,一个小顶堆,并且大小堆的大小相差不能超过1,大顶堆中的顶小于等于小顶堆的顶,那么中位数就是大顶堆堆顶或者小顶堆堆顶或者他们的中位数.


public class Solution {
    //大小顶堆
   private PriorityQueue<Integer> maxHeap=new PriorityQueue<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2-o1;
        }
    });
    private PriorityQueue<Integer> minHeap=new PriorityQueue<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1-o2;
        }
    });
    //判断应该插入哪一个,保证相差不能超过一,并且可以确定奇数情况下是小顶堆数目多一
    private boolean isMinHeap=false;

    //从最开始,每一次,小顶堆将最小的值给大顶堆,大顶堆将最大值给小顶堆,保证了大顶堆中的顶小于等于小顶堆的顶
    public void Insert(Integer num) {
        if (isMinHeap){
            minHeap.offer(num);
            int smaller=minHeap.poll();
            maxHeap.offer(smaller);
        }else {
            maxHeap.offer(num);
            int bigger=maxHeap.poll();
            minHeap.offer(bigger);
        }
        isMinHeap=!isMinHeap;
    }

    public Double GetMedian() {
        if (minHeap.isEmpty()){
            return null;
        }
        if(isMinHeap){
            return Double.valueOf(minHeap.peek());
        }
        return (double) (maxHeap.peek() + minHeap.peek()) /2;
    }
}

62 滑动窗口的最大值

题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

分析:直接使用滑动窗口即可

public class Solution {
    public ArrayList<Integer> maxInWindows(int[] num, int size) {
        //大顶
        PriorityQueue<Integer> queue=new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        ArrayList<Integer> res=new ArrayList<>();
        if (num==null||num.length<size||size==0){
            return res;
        }
        int index=0;
        //每一次取出最大值,删除过期值
        for (int i = 0; i < num.length; i++) {
            if (i>=size){
                res.add(queue.peek());
                queue.remove(Integer.valueOf(num[index++]));
            }
            queue.offer(num[i]);
        }
        //处理剩余的值:一共是length-size+1个结果
        res.add(queue.peek());
        return res;
    }
}

63 矩阵中的路径

题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

分析:经典的dfs,处理好以为数组和二维数组之间的映射关系即可i*col+j=index

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
        for (int i = 0; i <rows ; i++) {
            for (int j = 0; j < cols; j++) {
                if (help(matrix,rows,cols,i,j,str,0,new boolean[matrix.length])){
                    return true;
                }
            }
        }
        return false;
    }

    private boolean help(char[] matrix, int row,int col,int i,int j,char[] str,int indexOfStr,boolean[] visited){
        //到头了,正确
        if (indexOfStr==str.length){
            return true;
        }
        //判断是否i,j是否合法,此位置是否访问过,此位置是否和str相应位置值相同
        if (i<0||j<0||i>=row||j>=col||visited[i*col+j]||matrix[i*col+j]!=str[indexOfStr]){
            return false;
        }
        visited[i*col+j]=true;
        indexOfStr+=1;
        //上下左右移动
        boolean res=help(matrix,row,col,i-1,j,str,indexOfStr,visited)
                ||help(matrix,row,col,i,j-1,str,indexOfStr,visited)
                ||help(matrix,row,col,i+1,j,str,indexOfStr,visited)
                ||help(matrix,row,col,i,j+1,str,indexOfStr,visited);
        //visited归位
        visited[i*col+j]=false;
        return res;

    }


}

64 机器人的运动范围

题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

分析:深搜即可

public class Solution {
    public int movingCount(int threshold, int rows, int cols) {
        boolean[] visited=new boolean[rows*cols];
        return moving(threshold,rows,cols,0,0,visited);
    }

    private int moving(int threshold, int rows, int cols, int i, int j, boolean[] visited) {
        if (i<0||j<0||i>=rows||j>=cols||visited[i*cols+j]||!checkSum(threshold,i,j)){
            return 0;
        }
        visited[i*cols+j]=true;
        return 1+moving(threshold,rows,cols,i+1,j,visited)
                +moving(threshold,rows,cols,i,j+1,visited);
                //+moving(threshold,rows,cols,i-1,j,visited)
                //+moving(threshold,rows,cols,i,j-1,visited);

    }

    private boolean checkSum(int threshold, int i, int j) {
        int res=0;
        while (i>0){
            res+=(i%10);
            i/=10;
        }
        while (j>0){
            res+=(j%10);
            j/=10;
        }
        return res<=threshold;
    }
}

65 整数中1出现的次数(从1到n整数中1出现的次数)

题目描述
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

分析:假如现在有一个数各位是abcdefg,现在求每个为是1的个数那么假如现在这个位是千位
这个位是0,那么此位出现1的情况仅由高位决定,比如230874,出现1的:1000-1999,11000-11999,21000-21999…221000-221999,出现的个数是:1000高位;
这个位是1,那么此位出现1的情况由高位和低位决定,比如231874,出现1的:1000-1874,11000-231874,…231000-231874,出现的个数是:高位
1000+低位+1
这个为是2-9,那么此位出现1的情况仅由高位决定,比如233874,出现1的:1000-1999,11000-11999,…231000-231999,出现1的个数是:(高位+1)*1000

因此:可以按照个十百千万的次序按位来计算每一位出现1的次数

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {

        int res=0,i=1;
        while (n/i!=0){
            int curr=n/i%10;
            int low=n-n/i*i;
            int high=n/(i*10);
            //当前位为0,该位出现1的次数由高位决定
            if(curr==0){
                res+=high*i;
            //此位为1,由高位和低位共同决定
            }else if(curr==1){
                res+=high*i+low+1;
            //当前位是2-9由高位决定
            }else {
                res+=(high+1)*i;
            }
            i*=10;
        }
        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/gentlezuo/article/details/91493396