劍指Offer(一)

二維數(shù)組中的查找

題目

在二維數(shù)組中醇份,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序,判斷二維數(shù)組中是否有該整數(shù)丢氢。

思路

查找整數(shù)時(shí)會(huì)出現(xiàn)重復(fù)查找問題,列從最右開始往左邊檢索先改,行從上往下邊開始檢索疚察,當(dāng)列中的值比目標(biāo)整數(shù)大,則該列中就不存在比目標(biāo)整數(shù)相等的值仇奶,列往左移動(dòng)貌嫡,當(dāng)行中的值比目標(biāo)整數(shù)小,行往下移動(dòng)

java中判斷數(shù)組為空该溯,要檢查三個(gè)部分:

一是數(shù)組首地址是否為空

二是是否為{}岛抄,也就是array.length==0的情況

三是{{}},這時(shí)array.length == 1狈茉,但是array[0].length == 0夫椭。滿足任意一個(gè)條件就可以返回false了。

if(array == null || array.length == 0 || (array.length <= 1 && array[0].length == 0)) return false;

//時(shí)間復(fù)雜度 O(n^2)
public static boolean find(int[][] arr, int target) {
        if (arr == null || arr.length < 1 && arr[0].length < 1) {
            return false;
        }
        int row = 0;
        int col = arr.length - 1;
        while (row >= 0 && row < arr.length - 1 && col >= 0) {
            if (arr[row][col] == target) {
                return true;
            } else if (arr[row][col] > target) {//如果當(dāng)前的數(shù)字比target大氯庆,則表示不在該列蹭秋,則表示在該列的左邊
                col--;//列數(shù)遞減,表示往左移
            } else {//如果當(dāng)前的數(shù)字比target小堤撵,則表示不在該行仁讨,則表示在該行的下邊
                row++;//行數(shù)遞增,表示往下移
            }
        }
        return false;
}
//二分 時(shí)間復(fù)雜度 O(nlogn)
public static boolean find2(int[][] arr, int target) {
        if (arr == null || arr.length < 1 && arr[0].length < 1) {
            return false;
        }
        int i = 0;
        while (i < arr.length) {
            if (arr[i][arr[i].length - 1] < target) {
                i++;
            } else {
                int b = 0;
                int t = arr[i].length - 1;
                while (b <= t) {
                    int mid = (b + t) / 2;
                    if (arr[i][mid] < target) {
                        b = mid + 1;
                    } else if (arr[i][mid] > target) {
                        t = mid - 1;
                    } else {
                        return true;
                    }
                }
                i++;
            }
        }
        return false;
}

public static void main(String[] args) {
        int[][] matrix = { { 1, 2, 8, 9 }, 
                           { 2, 4, 9, 12 }, 
                           { 4, 7, 10, 13 }, 
                           { 6, 8, 11, 15 } };
        System.out.println(find(matrix, 7)); // 要查找的數(shù)在數(shù)組中
        System.out.println(find(matrix, 5)); // 要查找的數(shù)不在數(shù)組中
        System.out.println(find(matrix, 1)); // 要查找的數(shù)是數(shù)組中最小的數(shù)字
        System.out.println(find(matrix, 15)); // 要查找的數(shù)是數(shù)組中最大的數(shù)字
        System.out.println(find(matrix, 0)); // 要查找的數(shù)比數(shù)組中最小的數(shù)字還小
        System.out.println(find(matrix, 16)); // 要查找的數(shù)比數(shù)組中最大的數(shù)字還大
        System.out.println(find(null, 16)); // 健壯性測試实昨,輸入空指針
    }

替換空格

題目

請實(shí)現(xiàn)一個(gè)函數(shù)陪竿,把字符串中的空格替換成"%20",輸入”we are happy.“,輸出”we%20are%20happy.“

思路

遍歷一次字符串族跛,計(jì)算出其空格的個(gè)數(shù)闰挡,可以計(jì)算出替換之后的字符串總長度,每替換一個(gè)空格礁哄,長度就增加2长酗,因此替換后的長度等于原來的長度加上字符串空格的個(gè)數(shù)乘以2。替換的時(shí)候從后往前開始復(fù)制和替換桐绒,準(zhǔn)備兩個(gè)指針夺脾,p1和p2,p1指向原始字符串的末尾茉继,p2指向替換后的字符串末尾咧叭。接下來移動(dòng)p1,逐個(gè)把字符復(fù)制到p2烁竭,直到碰到第一個(gè)空為止菲茬,此時(shí)p1往前移動(dòng)一格,p2往前插入 "%20"派撕,由于 %20長度是3婉弹,因此p2也要往前移動(dòng)3格。重復(fù)以上步驟就可以把空格完全替換终吼。

時(shí)間復(fù)雜度 O(n)

public static int replaceBlank(char[] chars, int usedLength) {
        if (chars == null || chars.length < usedLength) {
            return -1;
        }
        int blankCount = 0;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == ' ') {
                blankCount++;
            }
        }
        if (blankCount == 0) {
            return usedLength;
        }
        int targetLength = blankCount * 2 + usedLength;//計(jì)算出替換后的長度
        //如果轉(zhuǎn)換后的長度大于數(shù)組最大長度镀赌,返回-1
        if (targetLength > chars.length) {
            return -1;
        }
        int temp = targetLength;
        usedLength--;//從后往前,第一個(gè)開始處理的字符
        targetLength--;//替換后的字符放置的位置
        //字符中有空白字符际跪,一直處理到所有空白字符處理完
        while (targetLength >= 0 && usedLength < targetLength) {
            if (chars[usedLength] == ' ') {
                chars[targetLength--] = '0';
                chars[targetLength--] = '2';
                chars[targetLength--] = '%';
            } else {
                chars[targetLength--] = chars[usedLength];
            }
            usedLength--;
        }
        return temp;
    }

public static void main(String[] args) {
        char[] string = new char[20];
        string[0] = 'w';
        string[1] = 'e';
        string[2] = ' ';
        string[3] = 'a';
        string[4] = 'r';
        string[5] = 'e';
        string[6] = ' ';
        string[7] = 'h';
        string[8] = 'a';
        string[9] = 'p';
        string[10] = 'p';
        string[11] = 'y';
        string[12] = '.';
        int length = replaceBlank(string, 13);//傳遞的長度是已經(jīng)使用的長度商佛,而數(shù)組的長度要比已使用的長度長,并且超過替換后的長度
        System.out.println(new String(string, 0, length));
    }

單鏈表

插入:將要插入的節(jié)點(diǎn)指向頭節(jié)點(diǎn)姆打,并將指針往后移動(dòng)良姆,直到后續(xù)節(jié)點(diǎn)為null,將新節(jié)點(diǎn)插入

刪除:只需要將節(jié)點(diǎn)往后移即可

public static void main(String[] args) {
        ListNode node = new ListNode(2);
        addNode(node,4);
        addNode(node,5);
        addNode(node,6);
        removeNode(node, 2);
        removeNode(node, 5);
        printNode2(node);
    }
    
    public static Stack<Integer> stack = new Stack<>();
    public static LinkedList<Integer> list = new LinkedList<>();
    //從頭到尾打印鏈表
    public static void printNode2(ListNode head) {
        ListNode cur = head;
        while (cur != null) {
            list.add(cur.val);
            cur = cur.node_next;
        }
        while (!list.isEmpty()) {
            System.out.print(list.pop()+"-->");
        }
    }
    //打印鏈表(利用棧從尾到頭打印鏈表)
    public static void printNode(ListNode head) {
        ListNode cur = head;
        while (cur != null) {
            stack.push(cur.val);
            cur = cur.node_next;
        }
        while (!stack.isEmpty()) {
            System.out.print(stack.pop()+"-->");
        }
    }
    //刪除節(jié)點(diǎn)
    public static void removeNode(ListNode head,int val) {
        if (head==null) {
            return;
        }
        if (head.val == val) {
            head = head.node_next;
        }else {
            ListNode curNode = head;
            while (curNode.node_next!=null && curNode.node_next.val != val) {
                curNode = curNode.node_next;
            }
            if (curNode.node_next !=null && curNode.node_next.val==val) {
                curNode.node_next = curNode.node_next.node_next;
            }
        }
    }
    //插入節(jié)點(diǎn)
    public static void addNode(ListNode head,int val) {
        ListNode newNode = new ListNode(val);
        if (head==null) {
            head = newNode;
        }else {
            ListNode CurNode = head;
            while (CurNode.node_next != null) {
                CurNode = CurNode.node_next;
            }
            CurNode.node_next = newNode;
        }
    }
    //結(jié)構(gòu)體
    static class ListNode{
        int val;
        ListNode node_next;
        public ListNode(int val) {
            super();
            this.val = val;
        }
    }

二叉樹的構(gòu)造

利用中序和后序構(gòu)造二叉樹

public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(postorder.length == 0 || inorder.length == 0) return null;
        Index index = new Index();
        index.index = postorder.length - 1;
        return helper(0,inorder.length - 1,inorder,postorder,index);
    }
    class Index 
    {
        int index;
    }
    public TreeNode helper(int inStart,int inEnd,int[] inorder, int[] postorder,Index index){
        if(inStart > inEnd) {
            return null;
        }else{
            TreeNode root = new TreeNode(postorder[index.index]);
            index.index--;
            int mid = 0;
            for(int i=inStart;i<=inEnd;i++){
                if(inorder[i] == root.val){
                    mid = i;
                }
            }
            root.right = helper(mid+1,inEnd,inorder, postorder,index);
            root.left = helper(inStart,mid-1,inorder, postorder,index);
            return root;
        }
    }

前序和中序構(gòu)造二叉樹

public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder.length == 0 || inorder.length == 0) return null;
        return helper(0,inorder.length - 1,preorder,inorder);
    }
    int preStart = 0;
    public TreeNode helper(int inStart,int inEnd,int[] preorder, int[] inorder){
        if(preStart>preorder.length || inStart>inEnd){
            return null;
        }else{
            TreeNode root = new TreeNode(preorder[preStart]);
            int mid = 0;
            for(int i=inStart;i<=inEnd;i++){
                if(inorder[i] == preorder[preStart]){
                    mid = i;
                }
            }
            preStart++;
            root.left = helper(inStart,mid-1,preorder,inorder);
            root.right = helper(mid+1,inEnd,preorder,inorder);
            return root;
        }
}

兩個(gè)棧實(shí)現(xiàn)隊(duì)列

public class StackToQueue {

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

    public void addLast(int x) {
        stack1.push(x);
    }
    
    public int removeFirst() {
        if (size()!=0) {//彈出條件:當(dāng)隊(duì)列不為空的時(shí)候
            if (stack2.isEmpty()) {//當(dāng)s2為空的時(shí)候穴肘,將s1中的數(shù)字壓入s2
                while (!stack1.isEmpty()) {
                    stack2.push(stack1.pop());
                }
            }
            return stack2.pop();//只要s2不為空歇盼,就彈出
        }else {
            System.out.println("隊(duì)列已空");
            return -1;
        }
    }

    public int size() {
        return stack1.size() + stack2.size();
    }

    public static void main(String[] args) {
        StackToQueue queue = new StackToQueue();
         queue.addLast(1);
         queue.addLast(2);
         queue.addLast(3);
         queue.addLast(4);
         System.out.println(queue.removeFirst());
         System.out.println(queue.removeFirst());
         System.out.println(queue.removeFirst());
         queue.addLast(5);
         queue.addLast(6);
         System.out.println(queue.removeFirst());
         System.out.println(queue.removeFirst());
         System.out.println(queue.removeFirst());
    }
}

兩個(gè)隊(duì)列實(shí)現(xiàn)棧

public class QueueToStack {

    LinkedList<Integer> queue1 = new LinkedList<>();
    LinkedList<Integer> queue2 = new LinkedList<>();

    public void push(int x) {
        queue1.addLast(x);
    }

    public int pop() {
        if (size() != 0) {
            if (queue1.size() > 1) {
                putN_1ToAnthor();
                return queue1.removeFirst();
            } else {
                putN_1ToAnthor();
                return queue2.removeFirst();
            }
        } else {
            System.out.println("棧已空");
            return -1;
        }
    }

    // 移動(dòng)n-1個(gè)到另一個(gè)隊(duì)列
    public void putN_1ToAnthor() {
        if (!queue1.isEmpty()) {
            while (queue1.size() > 1) {
                queue2.addLast(queue1.removeFirst());
            }
        } else if (!queue2.isEmpty()) {
            while (queue2.size() > 1) {
                queue1.addLast(queue2.removeFirst());
            }
        }
    }

    public int size() {
        return queue1.size() + queue2.size();
    }

    public static void main(String[] args) {
        QueueToStack stack = new QueueToStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        stack.push(5);
        stack.push(6);
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }
}

旋轉(zhuǎn)數(shù)組中最小數(shù)

public static int min(int[] nums) {
        int p1 = 0;
        int p2 = nums.length - 1;
        int mid = p1;
        while (nums[p1] >= nums[p2]) {
            if (p2 - p1 == 1) {
                mid = p2;
                break;
            }
            mid = (p1 + p2) / 2;
            if (nums[p1] == nums[p2] && nums[p1] == nums[mid]) {
                int temp = nums[p1];
                for (int i = 0; i < nums.length; i++) {
                    if (temp > nums[i]) {
                        temp = nums[i];
                    }
                }
                return temp;
            }
            if (nums[mid] >= nums[p1]) {
                p1 = mid;
            } else if (nums[mid] <= nums[p2]) {
                p2 = mid;
            }
        }
        return nums[mid];
    }

二進(jìn)制中1的個(gè)數(shù)

public static int numberOf2(int n) {
        int count = 0;
        while (n>0) {
            count += n&1;
            n = n>>1;
        }
        return count;
}
    
public static int numberOf1(int n) {
        int count = 0;
        while (n>0) {
            ++count;
            n = (n-1)&n;
        }
        return count;
}

數(shù)值的整數(shù)次方

  1. 當(dāng)exponent為負(fù)數(shù)時(shí),轉(zhuǎn)成正數(shù)求解后评抚,求解其倒數(shù)
  2. 當(dāng)exponent為0時(shí)豹缀,直接返回0,當(dāng)exponent為1時(shí)慨代,返回base本身
  3. 當(dāng)base小數(shù)為0時(shí)邢笙,不能直接和0比較,需要重寫equals方法侍匙,并且base為0考慮其為非法輸入氮惯。
  4. 使用exponent>>1 代替除法叮雳,使用位與運(yùn)算代替 %,位運(yùn)算效率比乘除法高妇汗。
public static double power(double base, int exponent) {
        // 判斷底數(shù)為0并且指數(shù)小于0
        if (equals(base, 0.0) && exponent < 0) {
            invalideInput = true;
            return 0.0;
        }
        int absExponent = exponent;
        if (exponent > 0) {
            absExponent = exponent;
        }
        if (exponent < 0) {
            absExponent = -exponent;
        }
        double result = powerWithUnsignExponent(base, absExponent);
        if (exponent < 0) {
            result = 1.0 / result;
        }
        return result;
    }

    public static double powerWithUnsignExponent(double base, int exponent) {
        if (exponent == 0) {
            return 1;
        }
        if (exponent == 1) {
            return base;
        }
        double result = powerWithUnsignExponent(base, exponent >> 1);
        result *= result;
        //a^n = a^(n/2) * a^(n/2) (n為偶數(shù))
        //a^n = a^(n/2) * a^(n/2) * a (n為奇數(shù))
        //這個(gè)公式可以將時(shí)間復(fù)雜度提高到O(logn)帘不,否則直接求指數(shù)到時(shí)間復(fù)雜度為O(n)
        if ((exponent & 0x1) == 1) {//判斷exponent是奇數(shù)還是偶數(shù)
            result *= base;
        }
        return result;
    }

    public static boolean equals(double m, double n) {
        if ((m - n > -0.000001) && (m-n) < 0.000001) {
            return true;
        } else {
            return false;
        }
    }

打印1到最大的n位數(shù)

public static boolean isCrement(int[] number) {
        boolean isOverFlow = false;
        int takeOver = 0;
        for (int i = number.length-1; i >=0; i--) {
            int sum = number[i] + takeOver;
            if (i == number.length-1) {
                sum++;
            }
            if (sum>=10) {
                if (i==0) {
                    isOverFlow = true; 
                }else {
                    takeOver = 1;
                    sum -= 10;
                    number[i] = sum;
                }
            }else {
                number[i] = sum;
                break;
            }
        }
        return isOverFlow;
    }
    
    public static void printNumber(int[] number) {
        boolean isBeginning = true;
        for (int i = 0; i < number.length; i++) {
            if (isBeginning && number[i] != 0) {
                isBeginning = false;
            }
            if (!isBeginning) {
                System.out.print(number[i]);
            }
        }
        System.out.println();
    }
    
    public static void printMaxOfNDigits(int n) {
        if (n<0) {
            System.out.println("輸入出錯(cuò)");
        }
        int[] number = new int[n];
        while (!isCrement(number)) {
            printNumber(number);
        }
    }

在O(1)時(shí)間內(nèi)刪除節(jié)點(diǎn)

時(shí)間復(fù)雜度

((n-1)*O(1) + O(n))/n = O(1)

只有在尾節(jié)點(diǎn)時(shí)需要從頭節(jié)點(diǎn)遍歷,時(shí)間復(fù)雜度為O(n)杨箭,其他時(shí)候復(fù)雜度為O(1)寞焙,綜合起來時(shí)間復(fù)雜度還是O(1)

  1. 當(dāng)只有一個(gè)節(jié)點(diǎn)的時(shí)候(頭節(jié)點(diǎn)也是尾街店),直接刪除即可
  2. 當(dāng)有多個(gè)節(jié)點(diǎn)并是中間節(jié)點(diǎn)時(shí)互婿,將要?jiǎng)h除的節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)的值復(fù)制到要?jiǎng)h除的節(jié)點(diǎn)并覆蓋它的值捣郊,然后把它后面的節(jié)點(diǎn)刪掉
  3. 當(dāng)是尾節(jié)點(diǎn)的時(shí)候,需要從頭節(jié)點(diǎn)開始遍歷慈参,并刪除該節(jié)點(diǎn)
public static ListNode deleteNode(ListNode head, ListNode toDeleteNode) {
        if (head == null || toDeleteNode == null) {
            return head;
        }
        if (head == toDeleteNode) {
            return head.node_next;
        }
        // 要?jiǎng)h除的不是尾節(jié)點(diǎn)
        //將要?jiǎng)h除的下一個(gè)節(jié)點(diǎn)的值復(fù)制到要?jiǎng)h除的節(jié)點(diǎn)上呛牲,然后刪除它的下一個(gè)節(jié)點(diǎn)
        if (toDeleteNode.node_next != null) {
            toDeleteNode.val = toDeleteNode.node_next.val;
            toDeleteNode.node_next = toDeleteNode.node_next.node_next;
        } else if (toDeleteNode.node_next == head) {// 鏈表中只有一個(gè)節(jié)點(diǎn),刪除頭節(jié)點(diǎn)(也是尾節(jié)點(diǎn))
            toDeleteNode = null;
            head = null;
        } else {// 鏈表中有多個(gè)節(jié)點(diǎn)驮配,刪除尾節(jié)點(diǎn)
            ListNode curNode = head;
            while (curNode.node_next != null) {
                curNode = curNode.node_next;
            }
            curNode = null;
            toDeleteNode = null;
        }
        return head;
    }

調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)前面

二分讓時(shí)間復(fù)雜度降低娘扩,提高擴(kuò)展性,使用一個(gè)函數(shù)來規(guī)定函數(shù)條件成立的標(biāo)準(zhǔn)

public static void order(int[] nums) {
        if (nums == null || nums.length == 0) {
            return;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            while (left < right && !isEven(nums[left])) {
                left++;
            }
            while (left<right && isEven(nums[right])) {
                right--;
            }
            if(isEven(nums[left]) && !isEven(nums[right])) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
            }
        }
    }
    //判斷一個(gè)數(shù)是否是偶數(shù)
    public static boolean isEven(int n) {
        return (n & 1) == 0;
    }

鏈表中倒數(shù)第k個(gè)節(jié)點(diǎn)

public static ListNode kthNodeFromEnd(ListNode head,int k) {
        //當(dāng)頭指針為空或者k=0時(shí)僧凤,不在考慮范圍內(nèi)
        if (head==null || k==0) {
            return null;
        }
        ListNode pNode = head;
        ListNode pBehind = null;
        for (int i = 0; i < k-1; i++) {
            if (pNode.node_next!=null) {
                pNode = pNode.node_next;//先走到k-1到位置上
            }else {
                return null;//當(dāng)鏈表長度小于k當(dāng)時(shí)候畜侦,會(huì)拋空指針
            }
        }
        pBehind = head;
        while (pNode.node_next!=null) {
            pNode = pNode.node_next;//繼續(xù)走直到走到鏈表尾部
            pBehind = pBehind.node_next;//后一個(gè)指針從頭節(jié)點(diǎn)開始元扔,當(dāng)前面一個(gè)指針走到尾部躯保,循環(huán)結(jié)束,該指針剛好走到第k個(gè)位置上
        }
        return pBehind;
    }

反轉(zhuǎn)鏈表

三個(gè)指針分別記錄當(dāng)前節(jié)點(diǎn)澎语,當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)和上一個(gè)節(jié)點(diǎn)途事,記錄上一個(gè)和下一個(gè)節(jié)點(diǎn)未來防止反轉(zhuǎn)之后鏈表斷裂,反轉(zhuǎn)之后的頭節(jié)點(diǎn)就是為節(jié)點(diǎn)擅羞。

public static ListNode reverseNode(ListNode head) {
        if (head==null) {
            return null;
        }
        ListNode pReverseHead = null;//轉(zhuǎn)換后的頭節(jié)點(diǎn)
        ListNode pNode = head;//當(dāng)前節(jié)點(diǎn)
        ListNode pPrev = null;//當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)
        while (pNode!=null) {
            ListNode pNext = pNode.node_next;
            if (pNext==null) {
                pReverseHead = pNode;
            }
            pNode.node_next = pPrev;
            pPrev = pNode;
            pNode = pNext;
        }
        return pReverseHead;
    }

合并兩個(gè)排序的鏈表

public static ListNode mergeNode(ListNode head1,ListNode head2) {
        if (head1==null) {
            return head2;
        }else if (head2==null) {
            return head1;
        }
        ListNode pMergedHead = null;
        if (head1.val < head2.val) {
            pMergedHead = head1;
            pMergedHead.node_next = mergeNode(head1.node_next, head2);
        }else {
            pMergedHead = head2;
            pMergedHead.node_next = mergeNode(head1, head2.node_next);
        }
        return pMergedHead;
    }

樹的子結(jié)構(gòu)

public static boolean sameSubTree(TreeNode node1,TreeNode node2) {
        if (node1==null && node2 == null) {
            return false;
        }
        boolean result = false;
        if (node1.val == node2.val) {
            result = doesTree1HasTree2(node1, node2);
        }
        if (!result) {
            result = doesTree1HasTree2(node1.left, node2);
        }
        
        if (!result) {
            result = doesTree1HasTree2(node1.right, node2);
        }
        return result;
    }
    
    public static boolean doesTree1HasTree2(TreeNode node1,TreeNode node2) {
        if (node2==null) {
            return true;
        }
        if (node1 == null) {
            return false;
        }
        if (node1.val != node2.val) {
            return false;
        }
        return doesTree1HasTree2(node1.left, node2.left) && doesTree1HasTree2(node1.right, node2.right);
    }

樹的鏡像

public static void mirrorTreeNode(TreeNode node) {
        if (node == null) {
            return;
        }
        if (node.left== null && node.right == null) {
            return;
        }
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
        if (node.left!=null) {
            mirrorTreeNode(node.left);
        }
        if (node.right!=null) {
            mirrorTreeNode(node.right);
        }
    }

順時(shí)針打印矩陣

public static void printMatrixInCircle(int[][] nums) {
        if (nums == null || nums.length == 0 || nums[0].length == 0) {
            return;
        }
        int start = 0;
        while (nums.length > start * 2 && nums[0].length > start * 2) {
            printMatrixInCircle(nums, nums.length, nums[0].length, start);
            start++;
        }
    }

    private static void printMatrixInCircle(int[][] nums, int rows, int cols, int start) {
        int endX = cols - 1 - start;
        int endY = rows - 1 - start;
        // 從左往右打印一行
        for (int i = start; i <= endX; ++i) {
            printNumber(nums[start][i]);
        }
        System.out.println();
        // 從上到下打印一列
        for (int i = start+1; i <= endY; i++) {
            printNumber(nums[i][endX]);
        }
        System.out.println();
        // 從右到左打印一行
        if (start < endX && start < endY) {
            for (int i = endX - 1; i >= start; --i) {
                printNumber(nums[endY][i]);
            }
            System.out.println();
        }
        // 從下到上打印一列
        if (start < endX && start < endY - 1) {
            for (int i = endY - 1; i >= start + 1; --i) {
                printNumber(nums[i][start]);
            }
            System.out.println();
        }
    }

    private static void printNumber(int number) {
        System.out.print(number + " ");
    }

包含min函數(shù)的棧

public class MinStack {

    Stack<Integer> date = new Stack<>();
    Stack<Integer> min = new Stack<>();

    public static void main(String[] args) {
        MinStack minStack = new MinStack();
        minStack.push(3);
        minStack.push(4);
        minStack.push(2);
        minStack.push(1);
        minStack.push(0);
        System.out.println(minStack.pop());
        System.out.println(minStack.min());
        System.out.println(minStack.min());
    }

    public void push(int x) {
        date.push(x);
        if (min.size() == 0 || x < min.peek()) {
            min.push(x);
        }else {
            min.push(min.peek());
        }
    }
    
    public int pop() {
        if (date.size()>0 && min.size()>0) {
            min.pop();
            return date.pop();
        }
        return -1;
    }
    
    public int min() {
        if (date.size()>0 && min.size()>0) {
            return min.peek();
        }
        return -1;
    }
}

棧的壓入尸变、彈出序列

public static boolean isPopOrder(int[] pushList,int[] popList) {
        if (pushList==null || popList==null || pushList.length==0 || popList.length == 0) {
            return false;
        }
        Stack<Integer> pushStack = new Stack<>();
        int pushIndex = 0;
        int popIndex = 0;
        while (popIndex < popList.length) {
            //入棧元素還未全部入棧的條件下,如果棧為空减俏,或者棧頂元素不與當(dāng)前處理的相等召烂,則一直進(jìn)行入棧操作,直到入棧元素全部入椡蕹校或者找到出棧元素相等的元素
            while (pushIndex<pushList.length && (pushStack.isEmpty() || pushStack.peek() != popList[popIndex])) {
                //入棧數(shù)組中的元素入棧
                pushStack.push(pushList[pushIndex]);
                //指向下一個(gè)要處理的入棧元素
                pushIndex++;
            }
            //如果在上一步的入棧操作中找到了與出棧元素相等的元素
            if (pushStack.peek() == popList[popIndex]) {
                pushStack.pop();//將元素出棧
                popIndex++;//指向下一個(gè)要處理的元素
            }else {
                return false;//如果沒有找到與出棧元素相等的元素奏夫,說明出棧順序不合法
            }
        }
        return true;
    }

二叉樹的后序遍歷序列

private static boolean verifySequenceOfBST(List<Integer> sequence, int start, int end) {
        if (start >= end) {
            return true;
        }
        int index = start;
        //從左往右找到第一個(gè)不大于根節(jié)點(diǎn)都元素的位置
        while (index<end-1 && sequence.get(index) < sequence.get(end)) {
            index++;
        }
        //到此,[start,index-1]的值都比根節(jié)點(diǎn)小历筝,[start,index-1]可以看作是根節(jié)點(diǎn)都左子樹
        //right記錄第一個(gè)不小于根節(jié)點(diǎn)都位置
        int right = index;
        //找到[index,end-1]都所有元素都大于根節(jié)點(diǎn)酗昼,[index,end-1]為根節(jié)點(diǎn)都右子樹
        while (index<end-1 && sequence.get(index) > sequence.get(end)) {
            index++;
        }
        //當(dāng)index=end-1,說明目前是合法的
        if (index!=end-1) {
            return false;
        }
        index = right;//right記錄的第一個(gè)不大于根節(jié)點(diǎn)的位置梳猪,遞歸判斷左子樹和右子樹是否合法
        return verifySequenceOfBST(sequence, start, index - 1) && verifySequenceOfBST(sequence, index, end - 1);
    }

二叉樹中和胃某一值的路徑

    public static void findPath(TreeNode node, int expectSum) {
        List<Integer> path = new ArrayList<>();
        if (node != null) {
            findPath(node, path, expectSum, 0);
        }
    }

    public static void findPath(TreeNode node, List<Integer> path, int expectSum, int curSum) {
        if (node == null) {
            return;
        }
        path.add(node.val);
        curSum += node.val;

        if (curSum < expectSum) {
            if (node.left != null) {
                findPath(node.left, path, expectSum, curSum);
            }
            if (node.right != null) {
                findPath(node.right, path, expectSum, curSum);
            }
        } else if (curSum == expectSum) {
            if (node.left == null && node.right == null) {
                for (Integer val : path) {
                    System.out.print(val + " ");
                }
            }
        }
        path.remove(path.size() - 1);
        curSum -= node.val;
    }

復(fù)雜鏈表的復(fù)制

public static void cloneNode(ListNode head) {
        if (head == null) {
            return;
        }
        ListNode pNode = head;
        ListNode cloneNode = new ListNode();
        cloneNode.val = pNode.val;
        cloneNode.node_next = pNode.node_next;
        pNode.node_next = cloneNode;
        pNode = cloneNode.node_next;
        cloneNode.node_sibling = null;
    }

    public static void connectSiblingNode(ListNode head) {
        if (head == null) {
            return;
        }
        ListNode pNode = head;
        if (pNode != null) {
            ListNode cloneNode = pNode.node_next;
            while (pNode.node_sibling != null) {
                cloneNode.node_sibling = pNode.node_sibling.node_next;
                pNode = cloneNode.node_next;
            }
        }
    }

    public static ListNode reConnectNode(ListNode head) {
        ListNode cloneHead = null;
        ListNode cloneNode = null;
        ListNode pNode = head;
        if (pNode != null) {
            cloneHead = cloneNode = pNode.node_next;
            pNode.node_next = cloneNode.node_next;
            pNode = cloneNode.node_next;
            cloneNode.node_next = pNode.node_next;
            cloneNode = cloneNode.node_next;
        }
        return cloneHead;
    }

    public static ListNode clone(ListNode head) {
        cloneNode(head);
        connectSiblingNode(head);
        return reConnectNode(head);
    }

    static class ListNode {
        int val;
        ListNode node_next;
        ListNode node_sibling;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麻削,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呛哟,老刑警劉巖叠荠,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異扫责,居然都是意外死亡蝙叛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門公给,熙熙樓的掌柜王于貴愁眉苦臉地迎上來借帘,“玉大人,你說我怎么就攤上這事淌铐》稳唬” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵腿准,是天一觀的道長际起。 經(jīng)常有香客問我,道長吐葱,這世上最難降的妖魔是什么街望? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮弟跑,結(jié)果婚禮上灾前,老公的妹妹穿的比我還像新娘。我一直安慰自己孟辑,他們只是感情好哎甲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饲嗽,像睡著了一般炭玫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上貌虾,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天吞加,我揣著相機(jī)與錄音,去河邊找鬼尽狠。 笑死衔憨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晚唇。 我是一名探鬼主播巫财,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哩陕!你這毒婦竟也來了平项?” 一聲冷哼從身側(cè)響起赫舒,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闽瓢,沒想到半個(gè)月后接癌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扣讼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年缺猛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椭符。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荔燎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出销钝,到底是詐尸還是另有隱情有咨,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布蒸健,位于F島的核電站座享,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏似忧。R本人自食惡果不足惜渣叛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盯捌。 院中可真熱鬧淳衙,春花似錦、人聲如沸挽唉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓶籽。三九已至,卻和暖如春埂材,著一層夾襖步出監(jiān)牢的瞬間塑顺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工俏险, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留严拒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓竖独,卻偏偏與公主長得像裤唠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子莹痢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1.題目描述:在一個(gè)二維數(shù)組中种蘸,每一行都按照從左到右遞增的順序排序墓赴,每一列都按照從上到下遞增的順序排序。請完成一個(gè)...
    秋風(fēng)落葉黃閱讀 389評論 0 0
  • 1.在一個(gè)二維數(shù)組中(每個(gè)一維數(shù)組的長度相同)航瞭,每一行都按照從左到右遞增的順序排序诫硕,每一列都按照從上到下遞增的順序...
    甜柚小仙女閱讀 425評論 0 1
  • 1.二維數(shù)組中的查找 在一個(gè)二維數(shù)組中(每個(gè)一維數(shù)組的長度相同),每一行都按照從左到右遞增的順序排序刊侯,每一列都按照...
    禿頭哥編程閱讀 222評論 0 1
  • 本文按照耪掳欤客網(wǎng)的順序,疟醭梗客網(wǎng)劍指offer刷題網(wǎng)址:https://www.nowcoder.com/ta/cod...
    文哥的學(xué)習(xí)日記閱讀 2,245評論 0 5
  • 題目一:二維數(shù)組中的查找 題目描述:在一個(gè)二維數(shù)組中藕届,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增...
    管弦_閱讀 317評論 0 0