1. 程式人生 > >劍指offer題目答案集合

劍指offer題目答案集合

package org.nix.learn.offer;

import org.junit.jupiter.api.Test;
import sun.rmi.transport.tcp.TCPChannel;

import java.util.*;
import java.util.concurrent.*;

/**
 * 在一個二維陣列中(每個一維陣列的長度相同),每一行都按照從左到右遞增的順序排序,
 * 每一列都按照從上到下遞增的順序排序。請完成一個函式,
 * 輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。
 *
 * @author zhangpei
 * @version 1.0
 * @date 2018/10/8
 */
public class Solution {

    public static boolean Find(int target, int[][] array) {
        int len = array.length;

        if (array[0].length == 0 || array[0][0] > target) {
            return false;
        }
        if (array[0][len - 1] < target) {
            if (serch(target, array, len, len)) {
                return true;
            }
        }
        for (int i = 1; i < len; i++) {
            // 找到在第一排找到一個大於他的值,那麼存在
            // 等於他的值就在i-1列中的
            if (array[0][i] > target) {
                if (serch(target, array, len, i)) {
                    return true;
                }
            }
        }
        return false;
    }

    private static boolean serch(int target, int[][] array, int len, int i) {
        for (int[] anArray : array) {
            if (anArray[i - 1] == target) {
                return true;
            }
            if (anArray[len - 1] > target) {
                for (int k = len - 1; k > 0; k--) {
                    if (anArray[k] == target) {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    // -------------------------------------------------------

    /**
     * 請實現一個函式,將一個字串中的每個空格替換成“%20”。例如,當字串為We Are Happy.則經過替換之後的字串為We%20Are%20Happy。
     *
     * @param str
     * @return
     */
    public String replaceSpace(StringBuffer str) {
        return str.toString().replace(" ", "%20");
    }

    // -------------------------------------------------------

    /**
     * 輸入一個連結串列,按連結串列值從尾到頭的順序返回一個ArrayList
     */
    private class ListNode {
        int val;
        ListNode next;

        public ListNode(int val) {
            this.val = val;
        }

        public ListNode() {
        }
    }

    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<>();
        while (listNode != null) {
            list.add(listNode.val);
            listNode = listNode.next;
        }
        int len = list.size();
        ArrayList<Integer> returnV = new ArrayList<>(len);
        for (int i = len - 1; i >= 0; i--) {
            returnV.add(list.get(i));
        }
        return returnV;
    }

    public ArrayList<Integer> printListFromTailToHeadTwo(ListNode listNode) {
        Stack<Integer> stack = new Stack<>();
        while (listNode != null) {
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        int len = stack.size();
        ArrayList<Integer> va = new ArrayList<>(len);
        while (true) {
            try {
                Integer value = stack.peek();
                if (value == null) {
                    return va;
                }
                va.add(stack.pop());
            } catch (Exception e) {
                return va;
            }
        }
    }

    // -------------------------------------------------------

    /**
     * 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
     * 例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
     */
    class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        if (pre.length == 0 || in.length == 0) {
            return null;
        }
        TreeNode node = new TreeNode(pre[0]);
        for (int i = 0; i < in.length; i++) {
            if (pre[0] == in[i]) {
                node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
                node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length), Arrays.copyOfRange(in, i + 1, in.length));
            }
        }
        return node;
    }

    @Test
    public void reConstructBinaryTreeTest() {
        int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
        int[] in = {4, 7, 2, 1, 5, 3, 8, 6};
        reConstructBinaryTree(pre, in);
        System.out.println();
    }

    // -------------------------------------------------------

    /**
     * 把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。 輸入一個非減排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。
     * 例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該陣列的最小值為1。 NOTE:給出的所有元素都大於0,若陣列大小為0,請返回0。
     *
     * @param array
     * @return
     */
    public int minNumberInRotateArray(int[] array) {
        int len = array.length;
        if (len == 0) {
            return 0;
        }
        Integer integer = null;
        for (int value : array) {
            if (integer == null) {
                integer = value;
            } else {
                if (integer > value) {
                    return value;
                } else {
                    integer = value;
                }
            }
        }
        return 0;
    }

    @Test
    public void minNumberInRotateArray() {
        System.out.println(minNumberInRotateArray(new int[]{3, 4, 5, 1, 2}));
    }

    // -------------------------------------------------------

    /**
     * 用兩個棧來實現一個佇列,完成佇列的Push和Pop操作。 佇列中的元素為int型別。
     */

    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

    public void push(int node) {
        stack1.push(node);
    }

    public int pop() {
        List<Integer> integers = new ArrayList<>(stack2.size());
        while (!stack2.empty()) {
            integers.add(stack2.pop());
        }
        while (!stack1.empty()) {
            stack2.push(stack1.pop());
        }
        for (int i = integers.size() - 1; i >= 0; i--) {
            stack2.push(integers.get(i));
        }
        return stack2.pop();
    }

    @Test
    public void stackTest() {
        for (int i = 0; i < 20; i++) {
            push(i);
        }
        for (int i = 0; i < 10; i++) {
            System.out.print(pop() + " ");
        }
        for (int i = 20; i < 40; i++) {
            push(i);
        }
        for (int i = 0; i < 30; i++) {
            System.out.print(pop() + " ");
        }
    }

    /**
     * 大家都知道斐波那契數列,現在要求輸入一個整數n,
     * 請你輸出斐波那契數列的第n項(從0開始,第0項為0)。
     * n<=39
     *
     * @param n
     * @return
     */
    public int fibonacci(int n) {

        if (n <= 0) {
            return 0;
        }

        if (0 < n && n <= 2) {
            return 1;
        }

        int v1 = 0;
        int v2 = 1;

        for (int i = 2; i < n; i++) {
            int temp = v1 + v2;
            v1 = v2;
            v2 = temp;
        }
        return v2 + v1;
    }

    @Test
    public void fidbonacciTest() {
        System.out.println(fibonacci(6));
    }

    /**
     * 一隻青蛙一次可以跳上1級臺階,也可以跳上2級。
     * 求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)
     *
     * @param n
     * @return
     */
    public int jumpFloor(int n) {
        if (n <= 0) {
            return 0;
        }

        if (n <= 1) {
            return 1;
        }

        if (n == 2) {
            return 2;
        }

        int v1 = 1;
        int v2 = 2;

        for (int i = 3; i < n; i++) {
            int temp = v1 + v2;
            v1 = v2;
            v2 = temp;
        }
        return v2 + v1;
    }

    /**
     * 一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
     * <p>
     * 連結:https://www.nowcoder.com/questionTerminal/22243d016f6b47f2a6928b4313c85387
     * 來源:牛客網
     * <p>
     * 因為n級臺階,第一步有n種跳法:跳1級、跳2級、到跳n級
     * 跳1級,剩下n-1級,則剩下跳法是f(n-1)
     * 跳2級,剩下n-2級,則剩下跳法是f(n-2)
     * 所以f(n)=f(n-1)+f(n-2)+...+f(1)
     * 因為f(n-1)=f(n-2)+f(n-3)+...+f(1)
     * 所以f(n)=2*f(n-1)
     *
     * @param target
     * @return
     */
    public int jumpFloorII(int target) {
        return (int) Math.pow(2, target - 1);
    }

    /**
     * 輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。
     *
     * @param n
     * @return
     */
    public int numberOf1(int n) {
        long start = System.currentTimeMillis();
        int temp = n;
        int mi = 0;
        int bijiao;
        while (temp >= (bijiao = (int) Math.pow(2, mi))) {
            if (temp == bijiao) {
                return 1;
            }
            mi++;
        }
        mi--;
        int number = 0;
        while (temp != 0) {
            // 如果相減大於0說明符合要求
            int pow = (int) Math.pow(2, mi);
            if (temp - pow < 0) {
                mi--;
                continue;
            }
            temp = temp - pow;
            mi--;
            number++;
        }
        if (n < 0) {
            return ++number;
        }
        start = System.currentTimeMillis() - start;
        System.out.println(start);
        return number;
    }

    @Test
    public void numberOf1Test() {
        System.out.println(numberOf1(1000000000));
    }

    /**
     * 給定一個double型別的浮點數base和int型別的整數exponent。求base的exponent次方。
     *
     * @param base
     * @param exponent
     * @return
     */
    public double Power(double base, int exponent) {
        if (exponent == 0) {
            return 1;
        }
        if (base == 0) {
            return 0;
        }
        double temp = base;
        if (exponent > 0) {
            while (exponent > 1) {
                temp *= base;
                exponent--;
            }
        } else {
            while (exponent < 1) {
                temp /= base;
                exponent++;
            }
        }
        return temp;
    }

    /**
     * 輸入一個連結串列,輸出該連結串列中倒數第k個結點。
     *
     * @param head
     * @param k
     * @return
     */
    public ListNode FindKthToTail(ListNode head, int k) {
        int size = 0;
        ListNode temp = head;
        while (temp != null) {
            temp = temp.next;
            size++;
        }
        System.out.println(size);
        size = size - k;
        System.out.println(size);
        if (size < 0) {
            return null;
        }
        while (size > 0) {
            head = head.next;
            size--;
        }
        return head;
    }

    @Test
    public void FindKthToTailTest() {
        ListNode node = new ListNode(1);
        node.next = new ListNode(1);
        node.next.next = new ListNode(3);
        node.next.next.next = new ListNode(4);
        node.next.next.next.next = new ListNode(5);
        node = deleteDuplication(node);
        while (node != null) {
            System.out.print(node.val + " ");
            node = node.next;
        }

    }

    /**
     * 輸入一個連結串列,反轉連結串列後,輸出新連結串列的表頭。
     *
     * @param head
     * @return
     */
    public ListNode ReverseList(ListNode head) {
        if (head == null) {
            return null;
        } else if (head.next == null) {
            return head;
        }
        ListNode node = ReverseList(head.next);
        head.next.next = head;
        head.next = null;
        return node;
    }

    public ListNode myReverseList(ListNode head) {
        ListNode pre = null;
        ListNode next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    /**
     * 輸入一棵二叉樹,求該樹的深度。
     * 從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,
     * 最長路徑的長度為樹的深度。
     */
    public int TreeDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = TreeDepth(root.left);
        int rigth = TreeDepth(root.right);
        return left > rigth ? left + 1 : rigth + 1;
    }

    /**
     * 在一個排序的連結串列中,存在重複的結點,請刪除該連結串列中重複的結點,重複的結點不保留,返回連結串列頭指標。
     * 例如,連結串列1->2->3->3->4->4->5 處理後為 1->2->5
     *
     * @param pHead
     * @return
     */
    public ListNode deleteDuplication(ListNode pHead) {
        if (pHead == null || pHead.next == null) {
            return pHead;
        }
        // 建立一個頭節點 p1記錄沒有重複的節點
        ListNode p1 = new ListNode();
        p1.next = null;
        ListNode head = p1;
        // p2用於跳過重複的節點
        ListNode p2 = pHead;
        while (p2 != null) {
            if (p2.next != null && p2.val == p2.next.val) {
                while (p2.next != null && p2.val == p2.next.val) {
                    p2 = p2.next;
                }
                // 跳過重複的最後個節點
                p2 = p2.next;
                //防止連結串列尾部出現重複值,p2==null跳出迴圈而p1沒有跳過尾部重複
                p1.next = p2;
            } else {
                // 如果沒有重複
                p1.next = p2;
                p1 = p2;
                p2 = p2.next;
            }
        }
        // 返回時去掉頭節點
        return head.next;
    }

    /**
     * HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。
     * 今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,
     * 當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,
     * 並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和為8(從第0個開始,到第3個為止)。
     * 給一個數組,返回它的最大連續子序列的和,你會不會被他忽悠住?(子向量的長度至少是1)
     *
     * @param array
     * @return
     */
    public int FindGreatestSumOfSubArray(int[] array) {
        if (array == null) {
            return 0;
        }
        int sum = array[0];
        int tempsum = array[0];
        int len = array.length;
        for (int i = 1; i < len; i++) {
            tempsum = tempsum < 0 ? array[i] : tempsum + array[i];
            sum = tempsum > sum ? tempsum : sum;
        }
        return sum;
    }

    /**
     * 寫一個函式,求兩個整數之和,要求在函式體內不得使用+、-、*、/四則運算子號。
     *
     * @param num1
     * @param num2
     * @return
     */
    public int Add(int num1, int num2) {
        if (num2 == 0) {
            return num1;
        }
        int tempNum2 = num2 > 0 ? num2 : -num2;
        for (int i = 0; i < tempNum2; i++) {
            if (num2 > 0) {
                num1++;
            } else {
                num1--;
            }
        }
        return num1;
    }

    /**
     * 從上往下打印出二叉樹的每個節點,同層節點從左至右列印。
     * 公式: 父節點 i 左節點 2*i+1 右節點 2*i+2
     *
     * @param root
     * @return
     */
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node != null) {
                list.add(node.val);
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
        }
        return list;
    }
}