剑指Offer java实现(更新中)

以下为博主自己实现的剑指Offer里面的题目,使用java语言,不一定是最好的解法,参考书上的代码,以及使用牛客网的平台进行测试是否通过编程。
完整代码链接:
https://github.com/Parallelline1996/offer

面试题3:数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
解法:1. 不考虑空间限制,使用hashtable

// duplication[0] 用于记录重复的数字
    public static boolean duplicate(int numbers[],int length,int [] duplication) {

        // 对输入情况的判断,判断数组是否为空
        if (numbers == null) {
            return false;
        }

        // 判断数组内容是否符合要求
        for (int i : numbers) {
            if (i >= length || i < 0) {
                return false;
            }
        }

        // 采用哈希表的方式进行
        Hashtable<Integer, Integer> hashtable = new Hashtable<>();
        for (int i = 0; i < numbers.length; i++) {
            if (hashtable.containsValue(numbers[i])) {
                duplication[0] = numbers[i];
                return true;
            } else {
                hashtable.put(i, numbers[i]);
            }
        }
        return false;
    }

考虑空间限制:

// 下面采用不需要空间开销的解法:
    public static boolean duplicate_(int numbers[],int length,int [] duplication) {

        // 对输入情况的判断,判断数组是否为空
        if (numbers == null) {
            return false;
        }

        // 判断数组内容是否符合要求
        for (int i : numbers) {
            if (i >= length || i < 0) {
                return false;
            }
        }

        for (int i = 0; i < numbers.length; i++) {
            // 注意要有这一个判断
            while (numbers[i] != i) {           
                // 将数组每一个元素的值与其下标进行比较,如果不同,与元素值对应的下标进行交换
                // 元素与下标相对应。当重复元素存在时,会碰到,即停止
                if (numbers[i] == numbers[numbers[i]]) {
                    duplication[0] = numbers[i];
                    return true;
                } else {
                    int temp = numbers[i];
                    numbers[i] = numbers[temp];
                    numbers[temp] = temp;
                }
            }
        }
        return false;
    }

面试题4:二维数组中的查找

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数

public static boolean Find(int target, int [][] array) {

        // 判断输入的合法
        if (array == null) {
            return false;
        }

        // 提取行列
        int row = array.length;
        int column = array[0].length;

        // 进行寻找
        for(int i = column - 1; i >= 0; i--) {
            for(int j = 0; j < row; j++) {
                if(array[j][i] == target) {
                    return true;
                }else if (array[j][i] > target) {
                    break;
                }else if (array[j][i] < target) {
                    continue;
                }
            }
        }
        return false;
    }

面试题5:替换空格

请实现一个函数,将一个字符串中的空格替换成“%20”。
例如,当字符串为“We Are Happy”.则经过替换之后的字符串为“We%20Are%20Happy”
这个题对于java来说,因为有string的存在,所以省去了很多麻烦,如果对于C/C++,因为使用的是char[],为了节省移位的时间,可以采取先扫描一遍,获取空格数,然后求出新数组的长度并创建,然后从后往前进行复制,遇到空格则用“%20”进行替代。

/*
补充java基础:
String字符串常量, StringBuilder、StringBuffer是字符串变量
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
*/
public static String replaceSpace(StringBuffer str) {
        StringBuilder sBuilder = new StringBuilder();
        for(int i = 0; i < str.length(); i++) {
            if(str.charAt(i) != ' ') {
                sBuilder.append(str.charAt(i));
            }else {
                sBuilder.append("%20");
            }
        }
        return sBuilder.toString();
    }

面试题6:从尾到头打印链表

思路:只是进行打印,因此,递归,或者通过栈进行操作

public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        // 用于返回最后的结果
        ArrayList<Integer> temp = new ArrayList<>();

        // 对输入进行判断
        if (listNode == null) {
            return temp;            
        }

        Stack<ListNode> aIntegers = new Stack<>();
        ListNode head = listNode;

        // 进行压栈
        while (head != null) {
            aIntegers.push(head);
            head = head.next;
        }

        // 进行出栈
        while (!aIntegers.empty()) {
            temp.add(aIntegers.pop().val);
        }
        return temp;
    }

面试题7:重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回

public static TreeNode reConstructBinaryTree(int[] pre, int pre_start, int pre_end, 
            int[] in, int in_start, int in_end) {
        // 判断是否符合要求
        if (pre_start > pre_end || in_start  > in_end) {
            return null;
        }
        TreeNode root = new TreeNode(pre[pre_start]);

        // 根据先序和中序的特点,通过先序确定根节点,再使用根节点的位置对中序进行划分
        for (int i = in_start; i <= in_end; i++) {
            // 中序的划分: 左子树:in_start ~ i - 1; 右子树: i + 1 ~ in_end;
            // 前序的划分: 左子树:pre_start + 1 ~ pre_start + (i - in_start); 右子树:pre_start + (i - in_start) + 1 ~ pre_end
            // 原因:对于中序遍历,i刚好就是划分左右子树的中间值,所以分成两个,一边从头到i-1,一边从i+1到结束
            // 对于先序遍历,因为每次都是先取走pre[pre_start],所以实际上是划分pre[]的pre_start + 1 ~ pre_end,划分成两段
            // 重点就是将前后分开,通过中序确定前序的左右子树的大小,进而进行划分
            if (in[i] == pre[pre_start]) {
                // 先序遍历的理解也可以理解为:通过中序来判断前序左侧的数目
                root.left = reConstructBinaryTree(pre, pre_start + 1, pre_start + i - in_start, in, in_start, i - 1);
                root.right = reConstructBinaryTree(pre, pre_start + i - in_start + 1, pre_end, in, i + 1, in_end);
                break;
            }
        }
        return root;
    }

面试题9:用两个栈实现队列

// 这个用于进栈
    static Stack<Integer> stack1 = new Stack<Integer>();
    // 这个用于出栈
    static Stack<Integer> stack2 = new Stack<Integer>(); 

    // 实现入队列操作
    public static void push(int node) {
        stack1.push(node);
    }

    // 出队列
    public static int pop() {
        // 查看用于出栈的栈是否空
        if (!stack2.isEmpty()) {
            return stack2.pop();
        } else {
            // 当用于出栈的栈为空时,将所有用于入栈的栈里的元素全部移动到出栈的
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

面试题10:斐波那契数列

public static int Fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        int number1 = 0, number2 = 1, totalNumber = 0;
        for (int i = 1; i < n; i++) {
            totalNumber = number1 + number2;
            number1 = number2;
            number2 = totalNumber;
        }
        return totalNumber;
    }

面试题11:旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

// 顺序查找的方式:
    public int minNumberInRotateArray(int [] array) {
        if (array == null || array.length == 0) {
            return 0;
        }
        if (array.length == 1) {
            return array[0];
        }
        for (int i = 1; i < array.length; i++) {
            if (array[i] < array[i - 1]) {
                return array[i];
            }
        }
        return array[0];
    }
    // 二分法待补充

面试题12:矩阵中的路径

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

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)) {
                    return true;            
                }
            }        
        }        
        return false;    
    }     

    private boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) {   
        // 确定在矩阵中的位置
        int index = i * cols + j;        
        // 不符合条件
        if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1) {
            return false;        
        }
        if(k == str.length - 1) {
            return true;        
        }
        flag[index] = 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;    
        }

猜你喜欢

转载自blog.csdn.net/Applying/article/details/81105281