<<剑指Offer>>java实现(每日更新)

基础类:

public class CQueue {
    private Stack<Object> stack1;
    private Stack<Object> stack2;
}

链表

public class ListNode {
    public Object value=null;
    public ListNode next=null;
}

树:

public class TreeNode {
    public int sign = 0;
    public Object val;
    public TreeNode left;
    public TreeNode right;
    public ArrayList<TreeNode> nodes = new ArrayList<>();
    public TreeNode root;
    public TreeNode parent;
}

    /*面试题12*/
    public static boolean hasPath(char[][] matrix, String str) {
        if (matrix.length < 1 || matrix[0].length < 1 || str.isEmpty())
            return false;
        int rows = matrix.length;
        int cols = matrix[0].length;

        boolean[] visited = new boolean[rows * cols];   //已经初始化为false了

        int pathLength = 0;
        //从左上角点开始
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                if (hasPathCore(matrix, row, rows, col, cols, pathLength, visited, str))
                    return true;
            }
        }
        return false;
    }

    private static boolean hasPathCore(char[][] matrix, int row, int rows, int col, int cols, int pathLength, boolean[] visited, String str) {
        //路径字符串上所有的字符都在矩阵中找到合适的位置,则结束。
        if (pathLength == str.length())
            return true;
        boolean hasPath = false;
        if (row >= 0 && row < rows && col >= 0 && col < cols && matrix[row][col] == (str.charAt(pathLength)) && !visited[row * cols + col]) {
            ++pathLength;
            visited[row * cols + col] = true;

            /*上下左右*/
            hasPath = hasPathCore(matrix, row, rows, col - 1, cols, pathLength, visited, str) ||
                    hasPathCore(matrix, row, rows, col + 1, cols, pathLength, visited, str) ||
                    hasPathCore(matrix, row - 1, rows, col, cols, pathLength, visited, str) ||
                    hasPathCore(matrix, row + 1, rows, col, cols, pathLength, visited, str);
            /*如果上下左右都没有匹配到相同的,回到前一个字符(pathLength-1)*/
            if (!hasPath) {
                --pathLength;
                visited[row * cols + col] = false;
            }
        }
        return hasPath;
    }

    /*面试题13*/
    public static int movingCount(int cols, int rows, int threshold) {
        if (cols < 1 && rows < 1 && threshold < 0)
            return 0;

        boolean[] visited = new boolean[cols * rows];
        int count;

        count = movingCountCore(0, rows, 0, cols, threshold, visited);//从(0,0)开始移动

        return count;
    }

    private static int movingCountCore(int row, int rows, int col, int cols, int threshold, boolean[] visited) {
        int count = 0;
        /*从坐标点来判断是不是能进入(row, col)这个格子*/
        if (row >= 0 && row < rows && col >= 0 && col < cols && getDigitSum(col, row) <= threshold && !visited[row * cols + col]) {
            visited[row * cols + col] = true;
            /*然后进入下一个格子,将结果相加,用1加上下一步的结果。*/
            count = 1 + movingCountCore(row + 1, rows, col, cols, threshold, visited) +
                    movingCountCore(row - 1, rows, col, cols, threshold, visited) +
                    movingCountCore(row, rows, col + 1, cols, threshold, visited) +
                    movingCountCore(row, rows, col - 1, cols, threshold, visited);
        }
        return count;

    }

    private static int getDigitSum(int x, int y) {
        int sum = 0;
        while (x > 0 && y > 0) {
            sum += x % 10;
            sum += y % 10;
            x = x / 10;
            y = y / 10;
        }
        return sum;
    }

  /*面试题14,动态规划,剪绳子*/
    public static int maxProductAfterCutting_solution1(int length) {
        if (length < 2)
            return 0;
        if (length == 2)
            return 1;
        if (length == 3)
            return 2;

        int[] products = new int[length + 1];

        products[0] = 0;
        products[1] = 1;
        products[2] = 2;
        products[3] = 3;

        int max;
        for (int i = 4; i <= length; i++) {
            max = 0;
            for (int j = 1; j <= i / 2; j++) {
                int product = products[j] * products[i - j];
                if (max < product)
                    max = product;
            }
            products[i] = max;
        }
        max = products[length];

        return max;

    }

 /*面试题15
    * NumbeOf1没有考虑负数情况。
    * */
    public static int NumberOf1(int n) {
        int count = 0;
        while (n > 0) {
            if ((n & 1 ) != 0) //与1与操作,如果等于1,则最右边一位是1.
                count++;
            n = n >> 1;//整数右移一位
        }
        return count;
    }

    /*因为负数的右移要在末尾添加1,这样会导致死循环,所以干脆左移
    * 从1开始,一次左移一位,然后与n做与运算。
    * 这种解法循环的次数等于整数二进制的位数,32位整数需要循环32次。
    * */
    public static int NumberOf2(int n){
        int count = 0;
        int flag = 1;
        while (flag != 0){
            if ((n & flag) != 0)
                count++;
            flag = flag << 1;
        }
        return count;
    }

    /*一个整数减去1的结果与原整数做与运算,会把该整数最右边的1变成0.
    * 基于这个,一个整数有多少个1,就可以做多少次这种操作!*/
    public static int NumberOf3(int n){
        int count = 0;
        while (n>0){
            count++;
            n = n & (n - 1);
        }
        return count;
    }

    /*判断一个整数是不是2的整数次方,(一个整数减去1的结果与原整数做与运算,会把改整数最右边的1变为0),
    * 如果一个数是2的整数次方,则这个整数的二进制中只有一个1,则只可以做一次这种运算!
    * */
    public static boolean is2IntPower(int n){
        int count = 0;
        while (n>0){
            if (count>1) {
                break;
            }
            count++;
            n = n & (n - 1);
        }

        return count <= 1;
    }

    /*面试题16,求c中的power(base,exponent)求base的exponent次方函数java实现,
    * 需要考虑的问题:
    * 1.边界,base=0无意义
    * 2.exponent是正数和负数的处理不同,(负数时先求exponent的绝对值次方然后求倒数).
    *
    * */
    private static double Power(double base, int exponent) throws Exception {

        if (base == 0)
            throw new Exception("error input!");
//        if (base == 1 || exponent==0)
//            return 1;
        double result;
        int absExponent = exponent;
        if (exponent < 0)
            absExponent = -exponent;

        result = PowerWithUnsignedExponent1(base, absExponent);

        if (exponent < 0)
            return 1.0 / result;
        else
            return result;

    }

    private static double PowerWithUnsignedExponent1(double base, int exponent) {
        double result = 1.0;
        for (int i = 0; i < exponent; i++) {
            result *= base;
        }
        return result;
    }

    /*如果exponent是32,需要循环32次,可以用递归优化之,并用位运算来代替‘/’,‘%’运算*/
    private static double PowerWithUnsignedExponent2(double base, int exponent) {
        if (exponent == 0)
            return 1;
        if (exponent == 1)
            return base;

        // “ a/2 ==> a>>1 ”
        double result = PowerWithUnsignedExponent2(base, exponent >> 1);
        result *= result;

        // “ a%2 == 1(奇数)  ==>  a&1 == 1(奇数)  ”
        if ((exponent & 1) == 1)  //如果n为奇数,还需要另外乘以一个base
            result *= base;

        return result;

    }

    /*面试题20*/
    static int s = 0;

    private static boolean isNumeric(String string) {
        if (string.isEmpty())
            return false;
        char[] str = string.toCharArray();
        boolean numeric = scanInteger(str);
        if (s < str.length && str[s] == '.') {
            s++;
            numeric = scanUnsignedInteger(str) || numeric;
        }
        if (s < str.length && (str[s] == 'e' || str[s] == 'E')) {
            s++;
            numeric = numeric && scanInteger(str);
        }

        return numeric && (s == str.length);
    }

    private static boolean scanInteger(char[] str) {
        if (str[s] == '+' || str[s] == '-')
            s++;
        return scanUnsignedInteger(str);
    }

    private static boolean scanUnsignedInteger(char[] str) {
        int numEnd = s;
        while (s < str.length && str[s] >= '0' && str[s] <= '9')
            s++;
        return numEnd < s;
    }

/*面试题21,调整整数数组,奇数在前,偶数在后*/
    private static int[] reorderOddEven(int[] nums) throws Exception {
        if (nums.length == 0)
            throw new Exception("null arrays");

        int head = 0, tail = nums.length - 1;
        int temp;
        while (head <= tail) {
            if (((nums[head] & 1) == 1) && ((nums[tail] & 1) == 1)) { //都为奇数
                head++;
            } else if (((nums[head] & 1) == 0) && ((nums[tail] & 1) == 0)) {
                tail--;
            } else if (((nums[head] & 1) == 0) && ((nums[tail] & 1) == 1)) {
                temp = nums[head];
                nums[head] = nums[tail];
                nums[tail] = temp;
                head++;
                tail--;
            } else {
                head++;
                tail--;
            }
        }

        return nums;
    }

  /*面试提22, 链表中倒数地k个节点,
    * 两个指针,头指针先走到k-1个节点,然后尾指针开始一起走,当头指针走到链表结尾,此时尾指针所在的节点就是倒数第k个
    * */
    private static ListNode findKthToTail(ListNode head, int k) {
        if (head==null||k==0)
            return null;
        ListNode pHead = head;
        ListNode pBehind = head;

        for (int i=0;i<k-1;i++){
            if (pHead.next!=null)
                pHead = pHead.next;
            else
                return null;
        }

        while (pHead.next!=null){
            pHead = pHead.next;
            pBehind = pBehind.next;
        }

        return pBehind;
    }

/*面试题23,链表中环的入口节点*/
    private static ListNode meetingNode(ListNode head){
        if (head == null)
            return null;
        ListNode p1 = head.next;
        if (p1 == null)
            return null;
        ListNode p2 = p1.next;
        while (p2 != null && p1!=null){
            if (p2 == p1){
                return p2;
            }
            p1 = p1.next;
            p2 = p2.next;
            if (p2 != null)
                p2 = p2.next;
        }
        return null;
    }
    private static ListNode entryNodeOfFloop(ListNode head) {
        ListNode nodeInLoop = meetingNode(head);
        if (nodeInLoop == null)
            return null;

        //获得环中节点个数
        int loopNodes_count = 1;
        ListNode temp = nodeInLoop;
        while (temp.next != nodeInLoop){
            temp = temp.next;
            loopNodes_count++;
        }

        //环入口节点
        ListNode p1 = head;
        ListNode p2 = head;
        for (int i=0;i<loopNodes_count;i++)
            p1 = p1.next;

        while (p1 != p2){
            p1 = p1.next;
            p2 = p2.next;
        }
        return p1;
    }


    /*面试题24,反转链表*/
    private static ListNode reverseList(ListNode head) {
        if (head == null)
            return null;
        ListNode p1 = head;
        ListNode p2 = null;
        ListNode reversedHead = null;
        while (p1 != null) {
            ListNode p1Next = p1.next;
            //当p1Next为空,说明到结尾了,把头指针赋值给reversedHead,用于返回
            if (p1Next == null)
                reversedHead = p1;
            p1.next = p2;
            p2 = p1;
            p1 = p1Next;
        }
        return reversedHead;
    }

/*面试题25,合并两个递增链表*/
    private static ListNode Merge(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null)
            return pHead2;
        if (pHead2 == null)
            return pHead1;

        ListNode pMergeHead;
        if ((int) pHead1.value < (int) pHead2.value) {
            pMergeHead = pHead1;
            pMergeHead.next = Merge(pHead1.next, pHead2);
        } else {
            pMergeHead = pHead2;
            pMergeHead.next = Merge(pHead1, pHead2.next);
        }
        return pMergeHead;
    }

  /*面试题26, 数的子结构*/
    private static boolean hasSubTree(TreeNode t1, TreeNode t2) {
        boolean result = false;
        //如果t1,t2有一个为null,则返回为false;
        if (t1 != null && t2 != null) {
            if (t1.val == t2.val){
                result = DoesTree1HasTree2(t1, t2);
            }
            if (!result)
                result = hasSubTree(t1.left, t2);
            if (!result)
                result = hasSubTree(t1.right, t2);
        }
        return result;
    }
    private static boolean DoesTree1HasTree2(TreeNode tree1, TreeNode tree2){
        boolean ISHAVE = false;
        if (tree2 == null)
            return true;
        if (tree1 == null)
            return false;
        if (tree1.val == tree2.val)
            ISHAVE = true;
        ISHAVE = ISHAVE&DoesTree1HasTree2(tree1.left, tree2.left);
        ISHAVE = ISHAVE&DoesTree1HasTree2(tree1.right, tree2.right);
        return ISHAVE;
    }
    //书上版本
    private static boolean DoesTree1HasTree2_1(TreeNode tree1, TreeNode tree2){
        if (tree2 == null)
            return true;
        if (tree1 == null)
            return false;
        if (tree1.val != tree2.val)
            return false;
        return DoesTree1HasTree2_1(tree1.left, tree2.left) && DoesTree1HasTree2_1(tree1.right, tree1.right);
    }


    /*面试题27, 二叉树的镜像*/
    //1.层次遍历实现
    private static TreeNode Mirror(TreeNode root){
        //鲁棒性
        if (root == null)
            return null;
        if (root.right == null || root.left == null)
            return null;

        for (int i=1;i<= TreeNode.getTreeHeight(root);i++){
            mirrorRecursively(root, i);
        }
        TreeNode.printTree(root);
        return root;
    }

    private static void mirrorRecursively(TreeNode root, int level){
        if (root == null || level<1)
            return ;

        if (level == 1){
            TreeNode temp = root.right;
            root.right = root.left;
            root.left = temp;
            return ;
        }
        mirrorRecursively(root.left, level - 1);
        mirrorRecursively(root.right, level - 1);
    }

    //2.前序遍历来实现
    private static void pre_mirror(TreeNode root){
        //鲁棒性
        if (root == null)
            return ;
        if (root.right == null || root.left == null)
            return ;
        TreeNode temp = root.right;
        root.right = root.left;
        root.left = temp;

        if (root.left != null)
            pre_mirror(root.left);
        if (root.right != null)
            pre_mirror(root.right);
    }

    /*面试题28,对称的二叉树*/
    private static boolean isSymmetrical(TreeNode root){
        if (root == null)
            return false;
        List<Object> pre_order = new ArrayList<>();
        List<Object> mirror_order = new ArrayList<>();
        pre_order = preOrder(root, pre_order);
        System.out.println(pre_order.toString());
        mirror_order = mirror_order(root, mirror_order);
        System.out.println(mirror_order.toString());
        return pre_order.equals(mirror_order);
    }

    private static List<Object> mirror_order(TreeNode root, List<Object> result){
        if (root == null) {
            result.add(null);
            return result;
        }
        result.add(root.val);
        mirror_order(root.right, result);
        mirror_order(root.left, result);
        return result;
    }
        /* preorder on binary tree, using recursive way*/
    private static List<Object> preOrder(TreeNode root,List<Object> result){
        if (root==null){
            result.add(null);
            return result;
        }
        result.add(root.val);
        preOrder(root.left, result);
        preOrder(root.right, result);
        return result;
    }
    //<<剑指offer>>上的解法
    private static boolean isSymmetrical_1(TreeNode root) {
        return isSymmetrical_1(root, root);
    }

    private static boolean isSymmetrical_1(TreeNode root1, TreeNode root2) {
        if (root1 == null && root2==null)
            return true;
        if (root1 == null || root2==null)
            return false;
        if (root1.val != root2.val)
            return false;
        return isSymmetrical_1(root1.right, root2.left) && isSymmetrical_1(root1.left, root2.right);
    }

  /*面试题29,顺时针打印矩阵*/
    private static void clockwise_print(int[][] num, int width, int height, int start_x, int start_y) {
        if (width <= 0 || height <= 0)
            return;
        //如果是一排,直接输出
        if (width == 1 || height == 1) {
            for (int i = start_x; i < width + start_x; i++) {
                for (int j = start_y; j < height + start_y; j++) {
                    System.out.println(num[i][j]);
                }
            }
            return;
        }
        //否则,输出四周
        //打印第一行
        for (int i = 0; i < width - 1; i++) {
            System.out.println(num[start_y][i + start_x]);
        }
        //打印最后一列
        for (int j = 0; j < height - 1; j++) {
            System.out.println(num[j + start_y][width - 1 + start_x]);
        }
        //打印最后一行
        for (int i = width - 1 + start_x; i > start_x; i--) {
            System.out.println(num[height - 1 + start_y][i]);
        }
        //打印第一列
        for (int j = height - 1 + start_y; j > start_y; j--) {
            System.out.println(num[j][start_x]);
        }
        clockwise_print(num, width - 2, height - 2, start_x + 1, start_y + 1);
    }

/*面试题30,包含min函数的栈*/
    static Stack<Integer> m_data = new Stack();
    static Stack<Integer> m_min = new Stack();

    private static void push(Integer value) {
        m_data.push(value);
//        Integer peek_value = m_data.peek();
//        m_min.push(peek_value < value ? peek_value : value);
        if (m_min.empty() && value < m_data.peek())
            m_min.push(value);
        else
            m_min.push(m_min.peek());
    }

    private static Integer pop() {
        if (!m_data.empty() && !m_min.empty()) {
            m_min.pop();
            return m_data.pop();
        }
        return 0;
    }

    private static Integer min() {
        if (!m_min.empty() && !m_data.empty()) {
            return m_min.pop();
        }
        return 0;
    }

  /*面试题31,栈的压入,弹出序列
    * 利用一个辅助栈来完成.
    * 1.如果下一个弹出数字刚好是栈顶元素,则直接弹出.
    * 2.如果下一个弹出数字P不是栈顶元素,且push_seq中还有数字,则继续讲push_seq中的数字压入栈中,直到压入的是数字P.
    * 3.如果所有数字都已经压入栈中,还没有找到P,则返回false;
    * */
    private static boolean isPopOrder(int[] push_seq, int[] pop_seq) {
        if (push_seq == null || pop_seq == null)
            return false;
        Stack<Integer> s1 = new Stack();
        Stack<Integer> s2 = new Stack();
        int i = 0; //push_seq
        int p = 0;
        while (p<pop_seq.length){
            if (!s1.empty() && s1.peek() == pop_seq[p]) {
                s2.push(s1.pop());
                p++;
            }else if (i<push_seq.length){
                while (i<push_seq.length && push_seq[i] != pop_seq[p])
                    s1.push(push_seq[i++]);

                if (i > push_seq.length-1)
                    return false;
                else
                    s1.push(push_seq[i++]);
            }else if (s1.peek() != pop_seq[p]){
                return false;
            }

        }
        return true;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值