第二章

Posted youzoulalala

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二章相关的知识,希望对你有一定的参考价值。

第二章 面试需要的基础知识

    /**
     * 面试题3(一) 找到数组中任意一个相同的数字
     * 思路:
     * 以整数的值为散列值,通过交换将该值放到相应的位置上
     * 总结:
     * 小型正整数的值可以直接作为散列值(hashcode),存放到相应的位置,以O(n)的时间复杂度实现排序
     * @param arr
     * @return
     */
    public int findSameNumber(int[] arr) 
        //非法输入
        if (arr == null || arr.length <= 1) return -1;
        //下面假设输入中符合题目要求
        for (int i = 0; i < arr.length; i++) 
            while (arr[i] != i) 
                if (arr[arr[i]] != arr[i]) //不相等则交换
                    exch(arr, i, arr[i]);
                else return arr[i]; //相等,则找到了相同的数字
            
        
        return -1;


    private void exch(int[] arr, int a, int b) 
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    

    public static void main(String[] args) 
        int[] ints = 2, 3, 1, 0, 2, 5, 3;
        System.out.println(new Solution().findSameNumber(ints));
    

 

    /**
     * 面试题4 在二维数组中查找是否包含数组
     * 思路:不断地将问题的范围缩小
     * 总结:找规律,找出可以用循环或者递归的方法解决
     *
     * @param arr
     * @param num
     * @return
     */
    public boolean findNumber(int[][] arr, int num) 
        //非法输入
        if (arr == null) 
            return false;
        
        for (int i = 0; i < arr.length; i++) 
            if (arr[i] == null) return false;
        
        //从右上角开始
        int length = arr.length;
        int row = 0;
        int col = length - 1;
        while (row < length && col >= 0) 
            if (arr[row][col] < num) row++;
            else if (arr[row][col] > num) col--;
            else return true;
        
        return false;
    

 

    /**
     * 面试题5  将空格替换为%02
     * 解法:从后到前替换,将字符一次移动到位,避免了数组的频繁移动
     * 注意:位运算优先级低于加减
     * @param str
     */
    public String replaceBlank(String str) 
        //非法输入
        int length = str.length();
        if (str == null || length == 0) return null;
        //转化成数组
        char[] chars = str.toCharArray();
        int count = 0; //字符串中空格的数量
        for (int i = 0; i < length; i++) 
            if (chars[i] == ‘ ‘) count++;
        
        char[] tempChars = new char[length + (count << 1)];
        int p = length - 1; //两个指针
        int q = tempChars.length - 1;
        while (p >= 0) 
            if (chars[p] != ‘ ‘) 
                tempChars[q--] = chars[p];
             else 
                tempChars[q--] = ‘0‘;
                tempChars[q--] = ‘2‘;
                tempChars[q--] = ‘%‘;
            
            p--;
        
        return String.valueOf(tempChars);
    

    public static void main(String[] args) 
        Solution solution = new Solution();
        String str = "we are world.";
        System.out.println(solution.replaceBlank(str));
    

 

    /**
     * 面试题6:反向打印链表
     * 解法一:用递归的逆序遍历的方式
     * 解法二:顺序访问链表,将需要打印的值存入栈中
     *
     * @param node
     */
    public void printReverse(Node node) 
        //采用解法一
        //非法输入
        if (node == null) return;
        printReverse(node.next);
        System.out.println(node.val);
    

    public void printReverseUseStack(Node node) 
        //采用解法二
        if (node == null) return;
        Stack<Integer> s = new Stack<>(); //使用栈
        for (Node i = node; i != null; i = i.next)  //顺序遍历链表
            s.push(i.val);
        
        while (!s.empty())  //出栈
            System.out.println(s.pop());
        
    

 

    /**
     * 面试题7
     * 根据前序遍历和中序遍历的结果数组重建二叉树
     * 解法:根据不同遍历的特点 找到根结点,然后再递归地处理子树
     *
     * @param pre
     * @param in
     * @return
     */
    public TreeNode construct(int[] pre, int[] in) 
        //非法输入
        if (pre == null || in == null || pre.length == 0 || in.length == 0)
            return null;
        try 
            return constructCore(pre, in, 0, pre.length - 1, 0, in.length - 1);
         catch (Exception e) 
            e.printStackTrace();
        
        return null;
    

    /**
     * @param pre
     * @param in
     * @param pp1      前序数组的范围指针
     * @param pp2
     * @param ip1      中序数组的范围指针
     * @param ip2
     * @return
     */
    private TreeNode constructCore(int[] pre, int[] in, int pp1, int pp2, int ip1, int ip2) throws Exception 
        if (pp1 > pp2 || ip1 > ip2) return null;//无子树,返回null
        TreeNode node = new TreeNode(); //根节点
        node.val = pre[pp1];
        int nodeIndexInInOder = -1; //根结点在中序遍历中的索引
        for (int i = ip1; i <= ip2; i++)  //从中序遍历中寻找根结点
            if (in[i] == node.val) 
                nodeIndexInInOder = i;
                break;
            
        
        if (nodeIndexInInOder == -1) throw new Exception("Invalide Input");//在中序中没有找到
        node.left = constructCore(pre, in, pp1 + 1, pp1 + (nodeIndexInInOder - ip1), ip1, nodeIndexInInOder - 1);
        node.right = constructCore(pre, in, pp1 + 1 + (nodeIndexInInOder - ip1), pp2, nodeIndexInInOder + 1, ip2);
        return node;
    

 

    /**
     * 面试题8 二叉树的下一个结点
     * 分析:有右子树的情况下,下一个节点是右子树的最左侧(最小)结点;
     * 无右子树的情况下,下一个结点是沿着父结点向上查找,第一个遇到的左链接父结点。如果查找到父节点都没有找到下一结点则无下一节点。
     */
    public BTreeNode findNextNode(BTreeNode node) 
        //非法输入处理
        if (node == null) return null;
        //有右子树的情况
        if (node.right != null)
            return min(node.right); //取最小的结点
        //没有右子树的情况
        while (node.parent != null)  //有父结点,沿着父结点向上走
            if (node.parent.left == node)
                return node.parent;
            node = node.parent;
        
        return null; //没有找到父节点
    

    private BTreeNode min(BTreeNode node) 
        if (node.left == null) return node;
        return min(node.left);
    

 

    /**
     * 面试题9:用两个栈实现队列
     * 分析:一个栈用来入,一个栈用来出
     */
    class queueStack 
        //用两个栈来实现
        //为了方便使用了Integer
        private Stack<Integer> sIn;
        private Stack<Integer> sOut;

        public queueStack() 
            sIn = new Stack<>();
            sOut = new Stack<>();
        

        //实现尾部添加
        public void appendTail(Integer val) 
            sIn.push(val);
        

        //实现头部删除
        public Integer deleteHead() 
            if (sOut.empty())  //出栈是空的情况
                while (!sIn.empty())
                    sOut.push(sIn.pop());
            
            if (sOut.empty()) return null; //出栈依旧是空
            return sOut.pop();
        
    

 

    /**
     * 面试题9:用两个队列实现栈操作
     * 分析:交替地从一个队列复制到另外一个队列,复制过去时留下最后添加的元素用于弹出
     */
    class StackQueue 
        private LinkedQueue<Integer> que1;
        private LinkedQueue<Integer> que2;
        private boolean isQue1 = true;//true表示当前使用Que1

        //入栈
        public void push(Integer val) 
            if (isQue1)
                que1.enqueue(val);
            else
                que2.enqueue(val);
        
        //出
        public Integer pop() 
            if (isQue1) 
                if (que1.isEmpty()) return null;
                while (que1.count != 1)
                    que2.enqueue(que1.dequeue());
                isQue1 = false;
                return que1.dequeue();
             else 
                if (que2.isEmpty()) return null;
                while (que2.count != 1)
                    que1.enqueue(que2.dequeue());
                isQue1 = true;
                return que2.dequeue();
            
        
    

 

    /**
     * 面试题10 斐波那契数
     * 分析:一般来说,循环算法占用的空间比递归的方法更加少
     * 普通青蛙
     * 分析:可以变为斐波那契数列问题
     * 变态青蛙
     * 分析:通过数学的分析,可以得到n台阶跳法的函数表达式
     */
    public int fibonacci(int n) 
        if (n < 0) return -1;//-1表示错误输入
        if (n == 0) return 0;
        if (n == 1) return 1;
        //用数组保存前两个计算结果
        int[] result = 0, 1;
        int num = 2;
        while (num != n) 
            int currentResult = result[0] + result[1];
            result[0] = result[1];
            result[1] = currentResult;
        
        return result[0] + result[1];
    

 

以上是关于第二章的主要内容,如果未能解决你的问题,请参考以下文章

Python自学:第二章 注释

组原第二章作业

《HeadFirst Python》第二章学习笔记

《HeadFirst Python》第二章学习笔记

第二章代码

半条命2第二章Half.Life.2.Episode.Two-Unleashed