《劍指offer》所有題目-含Java實現

陸續刷了很久,算是刷完了《劍指offer》,如下所有AC代碼,不必定性能最優,若有錯誤或更好解答,請留言區指出,你們共同交流,謝謝~java

1.二維數組中的查找

在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。node

public class Solution {
    public boolean Find(int target, int [][] array) {
        if(array == null||array.length==0) return false;
        int rowIdx = 0,colIdx = array[0].length-1;
        while(rowIdx<array.length&&colIdx>=0){
            if(array[rowIdx][colIdx] == target)
                return true;
            else if(target>array[rowIdx][colIdx])
                rowIdx++;
            else if(target<array[rowIdx][colIdx])
                colIdx--;
        }
        return false;
    }
}

2.替換空格

請實現一個函數,將一個字符串中的空格替換成「%20」。例如,當字符串爲We Are Happy.則通過替換以後的字符串爲We%20Are%20Happy。c++

public class Solution {
    public String replaceSpace(StringBuffer str) {
        StringBuilder sb = new StringBuilder();
        for(int i = 0;i<str.length();i++){
            if(str.charAt(i)==' '){
                sb.append("%20");
            }
            else
                sb.append(str.charAt(i));
        }
        return sb.toString();
    }
}

3.從尾到頭打印鏈表

輸入一個鏈表,從尾到頭打印鏈表每一個節點的值。正則表達式

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> result = new ArrayList<>();
        Stack<Integer> stack = new Stack<>();
        if(listNode == null) return result;
        while(listNode != null){
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.isEmpty())
            result.add(stack.pop());
        return result;
    }
}

==4.重建二叉樹==

使用遞歸數組

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

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        if (pre == null || in == null || pre.length != in.length||pre.length == 0) return null;
        return reConstructBinaryTreeCore(pre, 0, pre.length - 1, in, 0, in.length - 1);
    }

    public TreeNode reConstructBinaryTreeCore(int[] pre, int preStartIdx, int preEndIdx, int[] in, int inStartIdx, int inEndIdx)  throws Exception{
        TreeNode node = new TreeNode(pre[preStartIdx]);
        if (preStartIdx == preEndIdx)
            if (inStartIdx != inEndIdx || pre[preStartIdx] != in[inStartIdx])
                throw new Exception("Invalid input.");
        int i = 0;
        while (pre[preStartIdx] != in[inStartIdx + i])
            i++;
        if (i == 0)//證實沒有左子樹
            node.left = null;
        else
            node.left = reConstructBinaryTreeCore(pre, preStartIdx + 1, preStartIdx + i, in, inStartIdx, inStartIdx + i - 1);
        if (inStartIdx + i == inEndIdx)//證實沒有右子樹
            node.right = null;
        else
            node.right = reConstructBinaryTreeCore(pre, preStartIdx + i + 1, preEndIdx, in, inStartIdx + i + 1, inEndIdx);
        return node;

    }
}

5.用兩個棧實現隊列

用兩個棧來實現一個隊列,完成隊列的Push和Pop操做。 隊列中的元素爲int類型。app

import java.util.Stack;

public class Solution {
 Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

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

    public int pop() throws Exception {
        if(stack1.isEmpty()&&stack2.isEmpty())
            throw new Exception("Queue is empty.");
        if(!stack2.isEmpty())
            return stack2.pop();
        while(!stack1.isEmpty())
            stack2.push(stack1.pop());
        return stack2.pop();
    }
}

==6.旋轉數組的最小數字==

把一個數組最開始的若干個元素搬到數組的末尾,咱們稱之爲數組的旋轉。 輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。 例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。 NOTE:給出的全部元素都大於0,若數組大小爲0,請返回0。dom

public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array == null||array.length == 0)return 0;
        int idx1 = 0,idx2 = array.length-1;
        //若是不能進入while循環,則證實第一個元素小於最後一個元素,並且數組爲非遞減排序,最小值即爲首位。
        while(array[idx1]>=array[idx2]){
            //第一個指針指向前半段遞增序列的末尾,第二個指針指向後半段遞增序列的首位。
            if(idx2-idx1==1)return array[idx2];
            //二分法查找臨界點
            int mid = (idx1+idx2)/2;
            //考慮特例:{1,0,1,1,1}
            if(array[idx1] == array[idx2]&& array[mid] == array[idx1]){
                for(int i = idx1;i<=idx2;i++)
                    if(array[i]<array[mid])
                        return array[i];
            //特例:{1,1,1,1,1,1,1}
            return array[mid];
            }
            //更新指針,直至idx2-idx1==1;
            if(array[mid]>=array[idx1])
                idx1 = mid;
            else if(array[mid]<=array[idx2])
                idx2 = mid;
        }
        //此時數組爲遞增排列,第一個元素最小
        return array[0];
    }
}

7.斐波那契數列

你們都知道斐波那契數列,如今要求輸入一個整數n,請你輸出斐波那契數列的第n項。
n<=39ide

public class Solution {
    public int Fibonacci(int n) {
         if(n<1) return 0;
        int[] fibonacci = new int[2];
        fibonacci[0] = 1;
        fibonacci[1] = 1;
        n-=2;
        while(n>0){
            int temp = fibonacci[0]+fibonacci[1];
            fibonacci[0] = fibonacci[1];
            fibonacci[1] = temp;
            n--;
        }
        return fibonacci[1];
    }
}

8.跳臺階(動態規劃)

一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。函數

public class Solution {
    public int JumpFloor(int target) {
        if(target < 1) return 0;
        int[] DP = new int[3];
        DP[0] = 1;
        DP[1] = 2;
        DP[2] = DP[0]+DP[1];
        if(target<=3)
            return DP[target-1];
        for(int i =4;i<=target;i++){
            DP[0] = DP[1];
            DP[1] = DP[2];
            DP[2] = DP[0]+DP[1];
        }
        return DP[2];
    }
}

9.(變態版)跳臺階

一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級……它也能夠跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

public class Solution {
    public int JumpFloorII(int target) {
        if(target<=0) return -1;
        //if(target == 1) return 1;
        return (int)Math.pow(2,target - 1);
       // return 2*JumpFloorII(target-1); 
    }
}

10.矩形覆蓋

咱們能夠用2×1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2×1的小矩形無重疊地覆蓋一個2×n的大矩形,總共有多少種方法?

public class Solution {
    public int RectCover(int target) {
        if(target<1) return 0;
        int[] DP = new int[3];
        DP[0] = 1;
        DP[1] = 2;
        DP[2] = DP[1]+DP[0];
        if(target<4)
            return DP[target-1];
        for(int i = 4;i<=target;i++){
            int temp = DP[1]+DP[2];
            DP[0] = DP[1];
            DP[1] = DP[2];
            DP[2] = temp;
        }
        return DP[2];
    }
}

11.二進制中1的個數

輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。

public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while(n!=0){
            count+=n&1;
            n=n>>>1; // >>>運算符,使符號位也跟着右移
        }
        return count;
    }
}

12.數值的整數次方

給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。

public class Solution {
    public double Power(double base, int exponent) {
        if(base == 0 && exponent < 0)//輸入不合法
            return 0.0;
        if(exponent < 0)
            return 1/PowerWithPositive(base,-1*exponent);
        else
            return PowerWithPositive(base,exponent);
  }
    public double PowerWithPositive(double base,int exponent){
        if(exponent == 0)
            return 1;
        if(exponent == 1)
            return base;
        double result = PowerWithPositive(base,exponent >> 1);
        result *= result;
        if((exponent & 1) == 1)
            result *= base;
        return result;
    }
}

13.調整數組順序使奇數位於偶數前面

輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得全部的奇數位於數組的前半部分,全部的偶數位於位於數組的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。

import java.util.Stack;
public class Solution {
    public void reOrderArray(int [] array) {
        if(array == null||array.length == 0) return;
        Stack<Integer> odd = new Stack<>();
        Stack<Integer> even = new Stack<>();
        for(int i = 0;i<array.length;i++){
            if((array[i]&1) == 1)
                odd.push(array[i]);
            else
                even.push(array[i]);
        }
        int index = array.length-1;
        while(!even.isEmpty())
            array[index--] = even.pop();
        while(!odd.isEmpty())
            array[index--] = odd.pop();
    }
}

14.鏈表中倒數第K個結點

輸入一個鏈表,輸出該鏈表中倒數第k個結點。(能用指針儘可能不要使用輔助棧)

方法一:使用指針

/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
import java.util.Stack;
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(head == null || k<=0)
            return null;
        ListNode node1 = head,node2 = head;
        for(int i=1;i<k;i++){
            if(node1==null)
                return null;
            node1 = node1.next;
        }
        if(node1 == null)
            return null;
        while(node1.next!=null){
            node1 = node1.next;
            node2 = node2.next;
        }
        return node2;
    }
         
}

方法二:使用輔助棧

/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
import java.util.Stack;
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        Stack<ListNode> stack = new Stack<>();
        ListNode node = head;
        while(node!=null){
            stack.push(node);
            node = node.next;
        }
        for(int i =0;i<k;i++){
            if(stack.empty())
                return null;
            node = stack.pop();
        }
        return node;
    }
}

15.反轉鏈表

輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head == null) return null;
        ListNode node1 = null,node2 = head,node3 = head.next;
        while(node3!=null){
            node2.next = node1;
            node1 = node2;
            node2 = node3;
            node3 = node3.next;
        }
        node2.next = node1;
        return node2;
    }
}

15.反轉鏈表

輸入一個鏈表,反轉鏈表後,輸出鏈表的全部元素。

解法一:(使用棧)
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
import java.util.Stack;
public class Solution {
    public ListNode ReverseList(ListNode head) {
        Stack<ListNode> stack = new Stack<>();
        if(head == null) return null;
        while(head != null){
            stack.push(head);
            head = head.next;
        }
        
        head = stack.pop();
        ListNode temp = head;
        while(!stack.empty()){
            temp.next = stack.pop();
            temp = temp.next;
        }
        temp.next = null;//必定要注意這裏的這行代碼
        //必定要將鏈表末位next置爲null
        return head;
    }
}
解法二:
public class Solution{
    public ListNode ReverseList(ListNode head){
        ListNode reversedListHead;
        ListNode pre = null;
        ListNode node = null;
        ListNode next = null;
        if(head == null) return null;
        node = head;
        while(true){
            next = node.next;
            node.next = pre;
            pre = node;
            if(next == null){
                reversedListHead = node;
                break;
            }   
            node = next;
        }
        return reversedListHead;
    }
}

16.合併兩個排序的鏈表

輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,固然咱們須要合成後的鏈表知足單調不減規則。

解法一:
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        //if(list1 == null && list2 == null) return null;
        //這行代碼能夠不要,由於當list1 == null  return list2也等於null
        if(list1 == null) return list2;
        if(list2 == null) return list1;
        ListNode head,node;
        if(list1.val <= list2.val){
            node = list1;
            head = node;
            list1 = list1.next;
        }else{
            node = list2;
            head = node;
            list2 = list2.next;
        }
        while(list1 != null&&list2 != null){
            if(list1.val<=list2.val){
                node.next = list1;
                list1 = list1.next;
                node = node.next;
            }else{
                node.next = list2;
                list2 = list2.next;
                node = node.next;
            }
        }
        while(list1 != null){
            node.next = list1;
            list1 = list1.next;
            node = node.next;
        }
        while(list2 != null){
            node.next = list2;
            list2 = list2.next;
            node = node.next;
        }
        return head;
    }
}
解法二:(使用遞歸)
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1 == null) return list2;
        if(list2 == null) return list1;
        ListNode MergedHead = null;
        if(list1.val <= list2.val){
            MergedHead = list1;
            MergedHead.next = Merge(list1.next,list2);
        }else{
            MergedHead = list2;
            MergedHead.next = Merge(list1,list2.next);
        }
        return MergedHead;
    }
}

17.樹的子結構

輸入兩棵二叉樹A,B,判斷B是否是A的子結構。(ps:咱們約定空樹不是任意一個樹的子結構)

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1==null||root2==null) return false;
        boolean result = false;
        if(root1.val == root2.val){
            result = isEqualTree(root1,root2);
        }
        if(!result)
            result = HasSubtree(root1.left,root2);
        if(!result)
            result = HasSubtree(root1.right,root2);
        return result;
    }
    public boolean isEqualTree(TreeNode tree1,TreeNode tree2){
        //注意此處,只需判斷tree2 == null便可返回true;
        //由於tree2爲子樹,此時tree1能夠不爲null,即tree1不爲葉節點
        if(tree2 == null) return true; 
        if(tree1 == null) return false;
        if(tree1.val == tree2.val){
            return isEqualTree(tree1.left,tree2.left) && isEqualTree(tree1.right,tree2.right);
        }
        return false;
    }
}

18.二叉樹的鏡像

操做給定的二叉樹,將其變換爲源二叉樹的鏡像。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    public void Mirror(TreeNode root) {
        if(root != null){
            TreeNode temp = root.left;
            root.left = root.right;
            root.right = temp;
            if(root.left!=null) Mirror(root.left);
            if(root.right!=null) Mirror(root.right);
        }
    }
}

==19.順時針打印矩陣(這道題有難度)==

==見書P161==

輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每個數字,例如,若是輸入以下矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

知識點:

關於值傳遞和引用傳遞能夠得出這樣的結論:

  1. 基本數據類型傳值,對形參的修改不會影響實參;
  2. 引用類型傳引用,形參和實參指向同一個內存地址(同一個對象),因此對參數的修改會影響到實際的對象;
  3. String, Integer, Double等immutable的類型特殊處理,能夠理解爲傳值,最後的操做不會修改實參對象。

解法一:

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        if(matrix == null) return null;
        ArrayList<Integer> result = new ArrayList<>();
        int start = 0;
        while(start*2<matrix.length&&start*2<matrix[0].length){
            printMatrixCircle(matrix,start,result);
            start++;
        }
       return result;
    }
    public void printMatrixCircle(int [][] matrix,int start,ArrayList<Integer> result){
        int endX = matrix[0].length - 1 - start;
        int endY = matrix.length - 1 - start;
        for(int i = start;i <= endX;i++){
            result.add(matrix[start][i]);
        }
        if(start < endY){
            for(int i = start +1;i <= endY;i++)
                result.add(matrix[i][endX]);
        }
        if(start<endX&&start<endY)
            for(int i = endX -1;i>=start;i--)
                result.add(matrix[endY][i]);
        if(start<endX&&start<endY-1)
            for(int i = endY -1;i>start;i--)
                result.add(matrix[i][start]);
    }
}

解法二:

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
       if(matrix == null) return null;
        ArrayList<Integer> result = new ArrayList<>();
        int h = matrix.length,w = matrix[0].length,round = 0;
        while(result.size()<h*w){
            int c=round,r=round;
            while(c<w-round)
                result.add(matrix[r][c++]);
            c--;
            r++;
            if(r == h-round) continue;
            while(r<h-round)
                result.add(matrix[r++][c]);
            r--;
            c--;
            if(c == round-1) continue;
            while(c>=round)
                result.add(matrix[r][c--]);
            c++;
            r--;
            while(r>round)
                result.add(matrix[r--][c]);
            round++;
        }
        return result;
    }
}

20 包含min函數的棧

定義棧的數據結構,請在該類型中實現一個可以獲得棧最小元素的min函數。

import java.util.Stack;

public class Solution {

    Stack<Integer> stack = new Stack<Integer>();
    Stack<Integer> minStack = new Stack<Integer>();
    int min;
    public void push(int node) {
        stack.push(node);
        if(minStack.empty())
            min = node;
        else
            min = Math.min(minStack.peek(),node);
        minStack.push(min);
    }
    
    public int pop() {
        minStack.pop();
        return stack.pop();
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int min() {
        return minStack.peek();
    }
}

21.棧的壓入、彈出序列

輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否爲該棧的彈出順序。假設壓入棧的全部數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不多是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)

【解題思路】:設計一個輔助棧,若是下一個彈出的數字是輔助棧的棧頂,則彈出,若是不是棧頂,則繼續將壓入序列壓入輔助棧,直到把下一個須要彈出的數字壓入棧頂爲止;若是全部數字都壓入輔助站,棧頂仍然不是欲彈出的數字,則該序列不多是一個彈出序列。

==注意:當stack爲空的時候,調用peek()方法會拋出異常==

import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        if(pushA == null||popA == null||pushA.length!=popA.length) return false;
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        for(int i = 0 ;i<popA.length;i++){
            //必定注意這裏須要先判斷一下棧是否爲空,
            //若是爲空,則調用peek()時會出現異常;
            if(stack.empty())
                stack.push(pushA[j++]);
            while(stack.peek()!=popA[i]&&j<pushA.length)
                stack.push(pushA[j++]);
            if(stack.peek()==popA[i])
                stack.pop();
            else
                return false;
        }
        return true;
    }
}

22.從上往下打印二叉樹

從上往下打印出二叉樹的每一個節點,同層節點從左至右打印。

Java知識點:

  1. 返回長度:
    1. String.length();String字符串用length()方法會返回其長度。
    2. Array.length;數組有length屬性,直接數組名點length就能夠取到。
    3. ArrayList.size()方法的會返回其長度。
  2. ArrayList 操做:
    get(),add(),remove()
    You need to use the get() method to get the element at a particular index from an ArrayList. You can't use [] to get the element at a particular index, in an arraylist. Its possible only for arrays and your files is not an array, but an ArrayList.

==必定要注意,Java中Queue爲接口,若是使用隊列須要使用LinkedList(雙向隊列)、PriorityQueue(優先隊列)==

解法一:

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * public class TreeNode {
 *  int val = 0;
 *  TreeNode left = null;
 *  TreeNode right = null;
 *
 *  public TreeNode(int val) {
 *      this.val = val;
 *  }
 * }
 */
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom( TreeNode root )
    {
        ArrayList<Integer> result = new ArrayList<>();
        if ( root == null )
            return(result);
        LinkedList<TreeNode> queue = new LinkedList<>();
        result.add( root.val );
        if ( root.left != null )
            queue.offer( root.left );
        if ( root.right != null )
            queue.offer( root.right );
        while ( !queue.isEmpty() )
        {
            TreeNode node = queue.poll();
            result.add( node.val );
            if ( node.left != null )
                queue.offer( node.left );
            if ( node.right != null )
                queue.offer( node.right );
        }
        return(result);
    }
}

解法二:

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}
*/
import java.util.ArrayList;
/**
用arraylist模擬一個隊列來存儲相應的TreeNode
*/
public class Solution {
    ArrayList<Integer> result = new ArrayList<>();
    ArrayList<TreeNode> temp = new ArrayList<>();
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        if(root == null) return result;
        temp.add(root);
        while(temp.size() != 0){
            TreeNode node = temp.remove(0);
            result.add(node.val);
            if(node.left!=null)
                temp.add(node.left);
            if(node.right!=null)
                temp.add(node.right);
        }
        return result;
    }
}

23.二叉搜索樹的後序遍歷序列

輸入一個整數數組,判斷該數組是否是某二叉搜索樹的後序遍歷的結果。若是是則輸出True,不然輸出False。假設輸入的數組的任意兩個數字都互不相同。

public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence == null || sequence.length == 0) return false;
        int start = 0,end = sequence.length-1;
        return isSearchTree(sequence,start,end);
    }
    public boolean isSearchTree(int [] sequence,int start,int end){
        if(end==start) return true;
        int root = sequence[end];
        int index = end;
        for(int i = start;i<end;i++){
            if(sequence[i] > root){
                index = i;
                break;
            }
        }
        for(int i = index;i<end;i++)
            if(sequence[i]< root)
                return false;
        if(index == end||index == start)// index = end 時沒有右子樹;index = start時沒有左子樹; 
            return isSearchTree(sequence,start,end-1);
        else
            return isSearchTree(sequence,start,index-1)&&isSearchTree(sequence,index,end-1);
    }
}

24.二叉樹中和爲某一值的路徑

輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和爲輸入整數的全部路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所通過的結點造成一條路徑。
【解題思路】:由於根結點和葉子結點必定在路徑中,並且路徑開始必定是跟結點,使用前序遍歷遍歷二叉樹,每通過一個結點減少target的值,直至找到使target=0的葉子結點,即爲路徑,每次回退,須要刪除路徑中最後一個結點。

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    private ArrayList<ArrayList<Integer>> allPath = new ArrayList<>();
    private ArrayList<Integer> path = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        if(root == null) return allPath;
        target -= root.val;
        path.add(root.val);
        if(target == 0&& root.left == null&&root.right == null)
            allPath.add(new ArrayList<Integer>(path));
        else{
            FindPath(root.left,target);
            FindPath(root.right,target);
        }
        path.remove(path.size()-1);
        return allPath;
        
    }
}

25.複雜鏈表的複製

輸入一個複雜鏈表(每一個節點中有節點值,以及兩個指針,一個指向下一個節點,另外一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。(注意,輸出結果中請不要返回參數中的節點引用,不然判題程序會直接返回空)

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        //必定注意考慮輸入爲空鏈表的狀況
        if(pHead == null) return null;
        //第一步:克隆每一個結點的值和next,而且將新節點放置在對應舊結點以後
        RandomListNode node = pHead;
        while(node != null){
            RandomListNode cloneNode = new RandomListNode(node.label);
            //cloneNode.label = node.label;
            cloneNode.next = node.next;
            node.next = cloneNode;
            node = cloneNode.next;
        }
        //第二步:克隆每一個隨機指針
        node = pHead;
        while(node != null){
            RandomListNode cloneNode = node.next;
            if(node.random != null)
                cloneNode.random = node.random.next;
            node = cloneNode.next;
        }
        //第三步:拆分拼接的鏈表
        node = pHead;
        RandomListNode cloneHead = pHead.next;
        while(node != null){
            RandomListNode cloneNode = node.next;
            node.next = cloneNode.next;
            node = node.next;
            if(node != null)
                cloneNode.next = node.next;
            else
                cloneNode.next = null;
        }
        return cloneHead;
    } 
}

26.二叉搜索樹與雙向鏈表

輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能建立任何新的結點,只能調整樹中結點指針的指向。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null) return null;
        if(pRootOfTree.left == null && pRootOfTree.right == null) return pRootOfTree;
        TreeNode left = Convert(pRootOfTree.left);
        TreeNode node = left;
        
        if(node == null)
            pRootOfTree.left = null;
        else{
            while(node.right != null)
                node = node.right;
            pRootOfTree.left = node;
            node.right = pRootOfTree;
        }
        TreeNode right = Convert(pRootOfTree.right);
        pRootOfTree.right = right;
        if(right != null)
            right.left = pRootOfTree;
        return left != null ? left : pRootOfTree; 
    }
}

27.==字符串的排列==

題目描述
輸入一個字符串,按字典序打印出該字符串中字符的全部排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的全部字符串abc,acb,bac,bca,cab和cba。

輸入描述:
輸入一個字符串,長度不超過9(可能有字符重複),字符只包括大小寫字母。

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collections;
public class Solution {
    ArrayList<String> result = new ArrayList<String>();
    public ArrayList<String> Permutation(String str) {
        if(str == null) return null;
        char[] charArray = str.toCharArray();
        permutation(charArray,0);
        Collections.sort(result);
        return result;
    }
    public void permutation(char[] charArray,int beginIdx){
        if(beginIdx >= charArray.length) return;
        if(beginIdx == charArray.length-1){
            result.add(String.valueOf(charArray));
        }
        HashSet<Character> charSet = new HashSet<>();
        for(int i = beginIdx;i<charArray.length;i++){
            if(i == beginIdx){
                charSet.add(charArray[i]);
                permutation(charArray,beginIdx+1);
            }else if(i != beginIdx && !charSet.contains(charArray[i])){
                charSet.add(charArray[i]);
                char temp = charArray[beginIdx];
                charArray[beginIdx] = charArray[i];
                charArray[i] = temp;
                permutation(charArray,beginIdx+1);
                temp = charArray[beginIdx];
                charArray[beginIdx] = charArray[i];
                charArray[i] = temp;
            }
        }
    }
}

28.數組中出現次數超過一半的數字

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。因爲數字2在數組中出現了5次,超過數組長度的一半,所以輸出2。若是不存在則輸出0。

解法一:利用HashMap

import java.util.HashMap;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        HashMap<Integer,Integer> map = new HashMap<>();
        int length = array.length;
        if(length == 1) return array[0]; //此處用於當數組只有一個元素的時候,下面的代碼對該狀況無效
        for(int i : array){
           if(map.containsKey(i)){
               if(map.get(i) == length/2)
                   return i;
               map.put(i,map.get(i) + 1);
               
           }else{
               map.put(i,1);
           }
        }
        return 0;
    }
}

解法二:利用數組特色,重複次數超過一半的數字必定大於其它數字出現次數之和

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array == null || array.length == 0) return 0;
        int length = array.length;
        int result = array[0];
        int times = 1;
        for(int i =1;i<length;i++){
            if(result == array[i])
                times++;
            else if(times == 0){
                result = array[i];
                times =1;
            }else
                times--; 
        }
        if(times == 0) return 0;
        times = 0;
        for(int i =0;i<length;i++){
            if(array[i] == result)
                times++;
        }
        if(times <= length/2)
            result = 0;
        return result;
    }
}

29.最小的K個數

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。

解法一

Partition思想

容許改變原始數組的狀況,時間複雜度O(n),不適合海量數據

import java.util.ArrayList;
public class Solution {
    /*解法一:容許改變原始數組的狀況,時間複雜度O(n),不適合海量數據*/
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> result = new ArrayList<>();
        //注意若是輸入不合法,這裏返回的是一個空集合,不是Null,與return null不一樣
        if(input == null || k<0 || k>input.length) return result;
        
        int start = 0;
        int end = input.length-1;
        int smallNums = partition(input,start,end);
        while(smallNums != k-1){
            if(smallNums > k-1)
                smallNums = partition(input,start,smallNums-1);
            else if(smallNums < k-1)
                smallNums = partition(input,smallNums+1,end);
        }
        for(int i =0;i<k;i++){
            result.add(input[i]);
        }
        return result;
    }
    //快排方法功能函數,在指定範圍內隨機選取一個數字,將數組中大與等於的放置其又,小於的放置其左;
    //返回值是在變換位置後,該元素的索引值
    public static int partition(int[] array,int start,int end){
        //邊界檢測
        if(array == null || array.length == 0 || start < 0 || end >= array.length || start > end) return -1;
        //在[start,end]範圍內,隨機選取一個數做爲index
        int randomIdx = (int)(start + Math.random()*(end-start));
        //int length = array.length;
        int smallNums = start-1;
        swap(array,randomIdx,end);
        for(int i=start;i<end;i++){
            if(array[i] < array[end]){
                smallNums++;
                if(smallNums < i){
                    swap(array,smallNums,i);
                }
            }
        }
        
        smallNums++;
        swap(array,smallNums,end);
        return smallNums;
    }
    //交換元素
    public static void swap(int[] array,int i,int j){
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

解法二:

使用最大堆思想,經過優先隊列的Conparator定製排序,實現指定大小的最大堆。這樣作的目的是使空間複雜度最低O(k),時間複雜度最低O(nlogk)

import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Solution {
    //解法二:不改變原始數組,使用優先隊列,時間複雜度O(nlogk),適合海量數據
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> result = new ArrayList<>();
        if(input == null || k > input.length || k<=0) return result;
        PriorityQueue<Integer> maxQueue = new PriorityQueue(k,new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return o2.compareTo(o1);//將先前Integer中的天然排序(從小到大)反過來,實現從大到小;
            }
        });
        for(int i =0;i<input.length;i++){
            if(maxQueue.size() != k ){
                maxQueue.offer(input[i]);
            }else if(maxQueue.peek() > input[i]){
                Integer temp = maxQueue.poll();//必須先去除隊列頭部的數據,以保證隊列長度
                temp = null;
                maxQueue.offer(input[i]);
            }
        }
        for(Integer i : maxQueue){
            result.add(i);
        }
        return result;
    }
}

30.連續子數組的最大和

HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同窗。今天測試組開完會後,他又發話了:在古老的一維模式識別中,經常須要計算連續子向量的最大和,當向量全爲正數的時候,問題很好解決。可是,若是向量中包含負數,是否應該包含某個負數,並指望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和爲8(從第0個開始,到第3個爲止)。你會不會被他忽悠住?(子向量的長度至少是1)

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        if (array == null || array.length == 0) return 0;
        int[] DP = new int[2];
        DP[0] = array[0];
        int max = DP[0];
        for (int i = 1; i < array.length; i++) {
            DP[i & 1] = Math.max(array[i], array[i] + DP[(i - 1) & 1]);
            max = Math.max(max, DP[i & 1]);
        }
        return max;
    }
}

==31.1~n整數中1出現的次數==

輸入一個整數n,求1~ n個整數的十進制表示中1出現的次數,例如:輸入13,1~13中包含1的數字有一、十、十一、十二、13所以共出現6次。

解題思路:

思路:
n中每一位數字對總體「1」數量的影響包括一下兩個方面:

  1. 若第i位大於1,則該位1的個數位,高於i的位組成的數字+1倍的10^i;
  2. 若第i位等於1,則該位1的個數位,高於i的位組成的數字倍的10^i加上後面各位組成的數字加1;
  3. 若第i位小於1,則該位1的個數位,高於i的位組成的數字倍的10^i;
import java.util.ArrayList;
public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        if(n<=0) return 0;
        //用於將int的每一位數字保存在int[]數組中
        ArrayList<Integer> number = new ArrayList<>();
        int totalNums = 0;
        //已分析過的高位數字組成的乘子
        int mult = 0;
        int temp = n;
        while(temp!=0){
            number.add(temp%10);
            temp = temp/10;
        }
        for(int i = number.size()-1;i>=0;i--){
            int nums = (int)(Math.pow(10,i));
            if(number.get(i) == 1){
                totalNums += (int)(n % Math.pow(10,i) + 1);
            }else if(number.get(i) > 1){
                totalNums += (int)(Math.pow(10,i));
            }else if(number.get(i) == 0){
            }
            totalNums += mult * nums;
            mult = mult * 10 + number.get(i);
        }
        return totalNums;
    }
}

解法二:找數字規律

import java.util.ArrayList;

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        if (n <= 0) return 0;
        int num = 0, k = 0, count = 0, i = 1;
        while (n != 0) {
            int x = n % 10;
            if (x == 1) {
                count += num + 1;
                count += x * k;
            } else if (x > 1) {
                count += x * k;
                count += (int) Math.pow(10, i - 1);
            }
            num += x * Math.pow(10, i - 1);
            k = 10 * k + (int) Math.pow(10, i - 1);
            n /= 10;
            i++;
        }

        return count;
    }

32.把數組排成最小的數

輸入一個正整數數組,把數組裏全部數字拼接起來排成一個數,打印能拼接出的全部數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字爲321323。

解題思路:

  1. 實際是將數組元素進行排序的操做
  2. 排序規則爲,若MN組成的數字大於NM,則N在前M在後
  3. 使用Comparatpr定製排序規則
  4. 考慮到數字鏈接起來可能使int溢出,因此轉換爲使用String來操做。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Solution {
    public String PrintMinNumber(int[] numbers) {
        String result = "";
        if (numbers == null || numbers.length == 0) return result;
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < numbers.length; i++) {
            list.add(numbers[i] + "");
        }
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String sNum1, String sNum2) {
                String num1 = sNum1 + sNum2;
                String num2 = sNum2 + sNum1;
                return num1.compareTo(num2);
            }
        });
        for (String str : list) {
            result += str;
        }
        return result;
    }
}

33.醜數

把只包含因子二、3和5的數稱做醜數(Ugly Number)。例如六、8都是醜數,但14不是,由於它包含因子7。 習慣上咱們把1當作是第一個醜數。求按從小到大的順序的第N個醜數。

public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index <= 0 ) return 0;
        int mult2_Idx = 0,mult3_Idx = 0,mult5_Idx = 0;
        int[] uglyNumber = new int[index];
        uglyNumber[0] = 1;
        for(int i = 1;i<index;i++){
            int min = Math.min(Math.min(uglyNumber[mult2_Idx]*2,
                                        uglyNumber[mult3_Idx]*3),
                                        uglyNumber[mult5_Idx]*5);
            uglyNumber[i] = min;    
            if(uglyNumber[mult2_Idx]*2 == uglyNumber[i])
                mult2_Idx++;
            if(uglyNumber[mult3_Idx]*3 == uglyNumber[i])
                mult3_Idx++;
            if(uglyNumber[mult5_Idx]*5 == uglyNumber[i])
                mult5_Idx++;
        }
        return uglyNumber[index-1];
    }
}

34.第一個只出現一次的字符

在一個字符串(1<=字符串長度<=10000,所有由字母組成)中找到第一個只出現一次的字符,並返回它的位置

import java.util.HashMap;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        int result = Integer.MAX_VALUE;
        if(str.length() == 0) return -1;
        HashMap<Character,Integer> charIdx = new HashMap<>();
        for(int i = 0 ;i < str.length(); i++){
            Character c = str.charAt(i);
            if(charIdx.containsKey(c)){
                charIdx.put(c,-1);
            }else{
                charIdx.put(c,i);
            }
        }
        for(int index : charIdx.values()){
            if(index != -1){
                result = Math.min(result,index);
            }
        }
        return result;
    }
}

35.==數組中的逆序對==

在數組中的兩個數字,若是前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007

輸入描述:

題目保證輸入的數組中沒有的相同的數字

數據範圍:

對於%50的數據,size<=10^4
對於%75的數據,size<=10^5
對於%100的數據,size<=2*10^5

示例1

輸入1,2,3,4,5,6,7,0 輸出7

public class Solution {
    public int InversePairs(int [] array) {
        if(array == null||array.length == 0) return 0;
        int length = array.length;
        int[] copy = new int[length];
        for(int i = 0;i < length ;i++){
            copy[i] = array[i];
        }
        int count = InversePairsCore(array,copy,0,array.length-1);
        return count;
    }
    
    public int InversePairsCore(int[] array,int[] copy,int start,int end){
        if(start == end){
            return 0;
        }
        int count = 0;
        int length = (end-start)/2;
        //注意:這裏是故意將copy和array調換位置的,由於每次執行InversePairCore以後copy在[start,end]部分都是排好序的
        //隨意使用data做爲array輸入,省去了來回複製的資源消耗。
        int left = InversePairsCore(copy,array,start,start+length);
        int right = InversePairsCore(copy,array,start+length+1,end);
        int p1 = start+length;
        int p2 = end;
        int copyIdx = end;
        while(p1 >= start && p2 >= start+length+1){
            if(array[p1]>array[p2]){
                count += p2-start-length;
                //此處先判斷一下,以避免超出運算範圍。
                if(count > 1000000007)
                    count = count%1000000007;
                copy[copyIdx--] = array[p1--];
            }else{
                copy[copyIdx--] = array[p2--];
            }
        }
        while(p1 >= start){
            copy[copyIdx--] = array[p1--];
        }
        while(p2 >= start+length+1){
            copy[copyIdx--] = array[p2--];
        }
        return (count+left+right)%1000000007;
    } 
}

36.兩個鏈表的第一個公共結點

輸入兩個鏈表,找出它們的第一個公共結點。技巧:不使用輔助Stack

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if(pHead1 == null || pHead2 == null) return null;
        int L1 = getListLength(pHead1);
        int L2 = getListLength(pHead2);
        if(L1>L2)
            for(int i = 0 ;i<(L1-L2);i++)
                pHead1 = pHead1.next;
        else if(L2>L1)
            for(int i = 0 ;i<(L2-L1);i++)
                pHead2 = pHead2.next;
        
        while(pHead1!=null){
            if(pHead1 == pHead2)
                return pHead1;
            pHead1 = pHead1.next;
            pHead2 = pHead2.next;
        }
        return null;
    }
    public int getListLength(ListNode head){
        ListNode temp = head;
        int count = 1;
        while(temp.next != null){
            temp = temp.next;
            count++;
        }
        return count;
    }
}

37.數字在排序數組中出現的次數

統計一個數字在排序數組中出現的次數。
採用二分查找法

/*
方法一:時間複雜度O(n),不可選
*/

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
        if(array.length == 0) return 0;
        int count = 0;
        for(int i = 0 ; i < array.length ; i++){
            if(array[i] == k){
                count++;
            }else{
                if(count != 0)
                    break;
            }
        }
        return count;
    }
}

/*
方法二:首選!先採用二分查找法,在數組中查找到第一個K和第二個K,總時間複雜度O(logn)
*/
public class Solution {
    public int GetNumberOfK(int[] array,int k){
        if(array.length == 0) return 0;
        int first = getFirstK(array,k,0,array.length-1);
        int last = getLastK(array,k,0,array.length-1);
        if(first > -1 && last > -1)
            return last - first + 1;
        return 0;
    }
    public int getFirstK(int[] array,int k,int start,int end){
        if(start > end) return -1;
        int midIdx = (end + start)/2;
        if(array[midIdx] == k){
            if((midIdx > 0 && array[midIdx-1] != k) || midIdx == 0)
                return midIdx;
            else{
                end = midIdx - 1;
                return getFirstK(array,k,start,end);
            }
        }else if(array[midIdx] > k){
            end = midIdx - 1;
        }else if(array[midIdx] < k){
            start = midIdx +1;
        }
        return getFirstK(array,k,start,end);
    }
    public int getLastK(int[] array,int k ,int start,int end){
        if(start > end) return -1;
        int midIdx = (start + end)/2;
        if(array[midIdx] == k){
            if((midIdx < array.length-1 && array[midIdx+1] != k) || midIdx == array.length-1)
                return midIdx;
            else
                start = midIdx + 1;
        }else if(array[midIdx] > k){
            end = midIdx - 1;
        }else if(array[midIdx] < k){
            start = midIdx + 1;
        }
        return getLastK(array,k,start,end);
    }
}

38.二叉樹的深度

輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次通過的結點(含根、葉結點)造成樹的一條路徑,最長路徑的長度爲樹的深度。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null) return 0;
        int left = TreeDepth(root.left);
        int right = TreeDepth(root.right);
        if(left>right) return left+1;
        else return right+1;
    }
}

39.平衡二叉樹

輸入一棵二叉樹,判斷該二叉樹是不是平衡二叉樹。若是某二叉樹中任意節點的左、右子樹的深度相差不超過1,那麼他就是一棵平衡二叉樹。
解法一:不夠簡便

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null) return true;
        int left = TreeDepth(root.left);
        int right = TreeDepth(root.right);
        if((left-right)>1||(left-right)<-1)
            return false;
        else
            return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }
    public int TreeDepth(TreeNode root){
        if(root == null) return 0;
        int left = TreeDepth(root.left);
        int right = TreeDepth(root.right);
        return left > right ? left+1 : right+1;
    }
}

解法二:推薦!後序遍歷二叉樹,只需遍歷一遍便可。

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        return getDepth(root) != -1;
    }
    public int getDepth(TreeNode root){
        if(root == null) return 0;
        int left = getDepth(root.left);
        if(left == -1)
            return -1;
        int right = getDepth(root.right);
        if(right == -1)
            return -1;
        return Math.abs(left-right) > 1 ? -1 : Math.max(left,right) + 1;
    }
}

40.數組中只出現一次的數字

一個整型數組裏除了兩個數字以外,其餘的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。
第一種:利用Set,空間複雜度爲O(N)

//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結果
import java.util.HashSet;
import java.util.Iterator;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashSet<Integer> set = new HashSet<Integer>();
        for(int i = 0;i<array.length;i++){
            if(set.contains(array[i])){
                set.remove(array[i]);
            }else{
                set.add(array[i]);
            }
        }
        boolean isFirst = true;
        Iterator iter = set.iterator();
        while(iter.hasNext()){
            if(isFirst){
                num1[0] = (int)iter.next();
                isFirst = false;
            }else
                num2[0] = (int)iter.next();
        }
    }
}

第二種:按位運算:異或、位移

//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int OR = 0;
        for(int i = 0;i<array.length;i++)
            OR ^= array[i];
        int idx = 0;//OR從後數第幾位是1,從1開始
        while(OR != 0){
            OR = OR >> 1;
            idx++;
        }
        num1[0] = 0;
        num2[0] = 0;
        for(int i = 0;i<array.length;i++){
            if((array[i]&(1<<(idx-1))) == 0)
                num1[0] ^= array[i];
            else
                num2[0] ^= array[i];
        }
    }
}

41.和爲S的連續正數序列

小明很喜歡數學,有一天他在作數學做業時,要求計算出9~16的和,他立刻就寫出了正確答案是100。可是他並不知足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就獲得另外一組連續正數和爲100的序列:18,19,20,21,22。如今把問題交給你,你能不能也很快的找出全部和爲S的連續正數序列? Good Luck!
輸出描述:
輸出全部和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序

import java.util.ArrayList;

public class Solution {
    public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        int small = 1, big = 2, s = 3, mid = sum / 2;
        while (small <= mid) {
            if (s == sum) {
                ArrayList<Integer> list = new ArrayList<>();
                for (int i = small; i <= big; i++)
                    list.add(i);
                result.add(list);
                s -= small;
                small++;
            } else if (s < sum) {
                big++;
                s += big;
            } else if (s > sum) {
                s -= small;
                small++;
            }
        }
        return result;
    }
}

42.和爲S的兩個數

輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,是的他們的和正好是S,若是有多對數字的和等於S,輸出兩個數的乘積最小的。
解析:
其實找的就是數組最兩側知足和爲S的數字,由於:

z=xy

x+y=s

z=x(s-x)=sx-x^2 函數圖像爲向下開口的拋物線,兩段數值小中間大。因此取兩邊的值。

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> result = new ArrayList<>();
        int p1 = 0,p2 = array.length-1;
        while(p1<p2){
            if(array[p1]+array[p2] == sum){
                result.add(array[p1]);
                result.add(array[p2]);
                return result;
            }else if(array[p1]+array[p2]>sum)
                p2--;
            else
                p1++;
        }
        return result;
    }
}

43.坐旋轉字符串

彙編語言中有一種移位指令叫作循環左移(ROL),如今有個簡單的任務,就是用字符串模擬這個指令的運算結果。對於一個給定的字符序列S,請你把其循環左移K位後的序列輸出。例如,字符序列S=」abcXYZdef」,要求輸出循環左移3位後的結果,即「XYZdefabc」。是否是很簡單?OK,搞定它!
==該題有好多種作法==
方法一:雖然AC,可是不是最優解

public class Solution {
    public String LeftRotateString(String str,int n) {
        if(n<0 || str==null || str.length() == 0) return "";
        n %= str.length();
        StringBuilder sb = new StringBuilder();
        for(int i = n;i<str.length();i++){
            sb.append(str.charAt(i));
        }
        for(int i = 0;i<n;i++){
            sb.append(str.charAt(i));
        }
        return sb.toString();
    }
}

方法二:

public class Solution {
    public String LeftRotateString(String str, int n) {
        if (str.length() == 0 || n < 0) return "";
        int length = str.length();
        n %= length;
        str += str;
        return str.substring(n, n + length);
    }
}

44.翻轉字符串

牛客最近來了一個新員工Fish,天天早晨老是會拿着一本英文雜誌,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,「student. a am I」。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句子應該是「I am a student.」。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他麼?

public class Solution {
    public String ReverseSentence(String str) {
        if (str.length() == 0) return "";
        char[] charArray = str.toCharArray();
        Reverse(charArray, 0, str.length() - 1);
        int start = 0, end = 0;
        for (int i = 0; i < charArray.length; i++) {
            if (charArray[i] == ' ') {
                end = i - 1;
                Reverse(charArray, start, end);
                start = i + 1;
            }
        }
        //這句話是用於旋轉最後一個單詞的。
        Reverse(charArray, start, charArray.length - 1);
        return String.valueOf(charArray);
    }

    public char[] Reverse(char[] charArray, int start, int end) {
        while (start < end) {
            char temp = charArray[start];
            charArray[start] = charArray[end];
            charArray[end] = temp;
            start++;
            end--;
        }
        return charArray;
    }
}

45.撲克牌順子

LL今天心情特別好,由於他去買了一副撲克牌,發現裏面竟然有2個大王,2個小王(一副牌本來是54張^_^)...他隨機從中抽出了5張牌,想測測本身的手氣,看看能不能抽到順子,若是抽到的話,他決定去買體育彩票,嘿嘿!!「紅心A,黑桃3,小王,大王,方片5」,「Oh My God!」不是順子.....LL不高興了,他想了想,決定大\小 王能夠當作任何數字,而且A看做1,J爲11,Q爲12,K爲13。上面的5張牌就能夠變成「1,2,3,4,5」(大小王分別看做2和4),「So Lucky!」。LL決定去買體育彩票啦。 如今,要求你使用這幅牌模擬上面的過程,而後告訴咱們LL的運氣如何。爲了方便起見,你能夠認爲大小王是0。

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers.length < 5) return false;
        Arrays.sort(numbers);
        int zerosNum = 0;
        int needZeros = 0;
        for(int i = 0 ;i < 5;i++){
            if(numbers[i] == 0){
                zerosNum++;
            }else if(i+1<5){
                //如存在兩數字相同,則必定不是順子
                if(numbers[i+1] == numbers[i]) return false; 
                needZeros += numbers[i+1] - numbers[i] -1;
            }
        }
        //此時大王個數超過四個,不符合題目要求
        if(zerosNum > 4) return false; 
        if(zerosNum >= needZeros) return true;
        else return false;
    }
}

46.孩子們的遊戲

n我的(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人 繼續從0開始報數。求勝利者的編號。(約瑟夫環問題)
解法一:使用數組模擬環

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n<0||m<1) return -1;
        int[] array = new int[n];
        int count=n,step=0,idx=-1;
        while(count>0){
            idx++;
            if(idx == n) idx=0;
            if(array[idx] == -1) continue;//若是是被標記過的則跳過
            step++;
            if(step == m){
                array[idx] = -1;
                count--; 
                step=0;
            } 
        }
        return idx;
    }
}

解法二:使用ArrayList模擬環

import java.util.ArrayList;
public class Solution {
    public int LastRemaining_Solution(int n, int m){
        if(n<0||m<1) return -1;
        ArrayList<Integer> list = new ArrayList<>();
        for(int i = 0;i<n;i++)
            list.add(i);
        int idx = (m-1)%n;
        while(list.size()>1){
            list.remove(idx);
            idx = (idx+m-1)%list.size();
        }
        return list.get(0);
    }
}

47.求1+2+3+...+n

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。

解題思路:(短路求值)

  1. 需利用邏輯與短路特性實現遞歸終止。
  2. 當n==0時,(n>0)&&((sum+=Sum_Solution(n-1))>0)只執行前面的判斷,爲false,而後直接返回0;
  3. 當n>0時,執行sum+=Sum_Solution(n-1),實現遞歸計算Sum_Solution(n)。
public class Solution {
    public int Sum_Solution(int n) {
        int sum = n;
        boolean isEnd = (sum != 0)&&((sum += Sum_Solution(n-1))>0);
        return sum;
    }
}

48.不用加減乘除作加法

寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。

解析:按位運算

  • step1:按位與是查看兩個數哪些二進制位都爲1,這些都是進位位,結果需左移一位,表示進位後的結果
  • step2:異或是查看兩個數哪些二進制位只有一個爲1,這些是非進位位,能夠直接加、減,結果表示非進位位進行加操做後的結果
  • step3:n1&n2是查看有沒有進位位了,若是有,須要重複step一、step2;若是沒有,保留n一、n2上二進制爲1的部分,用或將之合爲一個數,即爲最後結果
public class Solution {
    public int Add(int num1,int num2) {
        int n1,n2;
        n1 = num1 & num2;
        n1 = n1<<1;
        n2 = num1 ^ num2;
        if((n1 & n2) != 0) return Add(n1,n2);
        return n1 | n2;
    }
}

49.把字符串轉換成整數

將一個字符串轉換成一個整數,要求不能使用字符串轉換整數的庫函數。 數值爲0或者字符串不是一個合法的數值則返回0

public class Solution {
    public int StrToInt(String str) {
        if(str.length() < 1) return 0;
        char[] nums = str.toCharArray();
        int result = 0;
        int flag = 1;
        for(int i = 0 ; i<nums.length ; i++){
            if(nums[i]-'0'>9 || nums[i]-'0'<0){
                if( i==0 && (nums[i] == '+' || nums[i] == '-'))
                    flag = nums[i] == '+' ? 1 : -1;
                else
                    return 0;
            }else{
                result*=10;
                result+=(nums[i]-'0');
            }  
        }
        return result*flag;
    }
}

不適用str.toCharArray()方法

public class Solution {
    public int StrToInt(String str) {
        if(str.length() < 1) return 0;
        int result = 0;
        int flag = 1;
        for(int i = 0 ; i<str.length(); i++){
            if(str.charAt(i)-'0'>9 || str.charAt(i)-'0'<0){
                if( i==0 && (str.charAt(i) == '+' || str.charAt(i) == '-'))
                    flag = str.charAt(i) == '+' ? 1 : -1;
                else
                    return 0;
            }else{
                result*=10;
                result+=(str.charAt(i)-'0');
            }  
        }
        return result*flag;
    }
}

50.數組中重複的數字

在一個長度爲n的數組裏的全部數字都在0到n-1的範圍內。 數組中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每一個數字重複幾回。請找出數組中任意一個重複的數字。 例如,若是輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。

public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    這裏要特別注意~返回任意重複的一個,賦值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length<0) return false;
        boolean[] result = new boolean[length];
        for(int i = 0;i<length;i++){
            if(numbers[i]>length-1||numbers[i]<0) return false;
            if(result[numbers[i]]){
                duplication[0] = numbers[i];
                return true;
            }
            result[numbers[i]] = true;
        }
        return false;
    }
}

51.構建乘積數組

給定一個數組A[0,1,...,n-1],請構建一個數組B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1]。不能使用除法。

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        int[] B = new int[A.length];
        if(A.length == 0) return B;
        B[0] = 1;
        for(int i = 1;i<A.length;i++){
            B[i] = B[i-1] * A[i-1];
        }
        int temp = 1;
        for(int i = A.length-1;i>=0;i--){
            B[i] *= temp;
            temp *= A[i];
        }
        return B;
    }
}

==52.正則表達式匹配==

請實現一個函數用來匹配包括「.」和「 * 」的正則表達式。模式中的字符'.'表示任意一個字符,而' * '表示它前面的字符能夠出現任意次(包含0次)。 在本題中,匹配是指字符串的全部字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab * ac * a"匹配,可是與"aa.a"和"ab * a"均不匹配

解題思路

  1. 當patternIndex後一位爲‘ * ’時:
    此時若strIndex == str.length時,直接將patternIndex+2,跳過兩個;
    若是strIndex!=str.length時,分爲如下三種狀況:
    1. strIndex,patternIndex+2;(str != pattern時)
    2. strIndex+1,patternIndex+2;(str = pattern 時 或者 此時pattern == ‘.’)
    3. strIndex+1,patternIndex;(str == pattern 並且 str+1 也 == pattern)
  2. 當patternIndex後一位不爲‘*’
    此時若是strIndex = str.length return false;
    若是 str = pattern 則 str+1,pattern+1
    反之 return false;
public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        //1.邊緣檢測
        if(str==null||pattern==null) return false;
        int strIndex=0,patternIndex=0;
        return matchCore(str,pattern,strIndex,patternIndex);
    } 
    public boolean matchCore(char[] str,char[] pattern,int strIndex,int patternIndex){
        if(strIndex == str.length && patternIndex == pattern.length) return true;
        if(strIndex != str.length && patternIndex == pattern.length) return false;
        //當模式中第二個字符是‘*’
        if(patternIndex+1 < pattern.length && pattern[patternIndex +1] == '*'){
            //必定注意這裏strIndex有多是str.length 須要把str[strIndex]放在後面,以避免溢出
            if(strIndex != str.length && (pattern[patternIndex] == '.' || str[strIndex] == pattern[patternIndex])){
                return matchCore(str,pattern,strIndex+1,patternIndex) || matchCore(str,pattern,strIndex+1,patternIndex+2) || matchCore(str,pattern,strIndex,patternIndex+2);
            }else{
                return matchCore(str,pattern,strIndex,patternIndex+2);
            }     
        }else{//模式中第二個字符不是’*‘
            if(strIndex != str.length && (str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.'))
                return matchCore(str,pattern,strIndex+1,patternIndex+1);
            else
                return false;
        }
    }
}

==53.表示數值的字符串==

請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示數值。 可是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

題目分析:數值能夠表示爲"A+'.'+B+'E/e'+C"

  • 其中A爲帶符號整數,能夠爲空
  • B爲不帶符號整數,能夠爲空
  • A和B不能同時爲空
  • C爲帶符號整數,不能爲空
public class Solution {
    //聲明一個全局變量,記錄小數點前是否有數字
    boolean hasInt = false;
    public boolean isNumeric(char[] str) {
        if(str == null || str.length == 0) return false;
        return scanA(str,0);
    }
    //第一部分:爲帶符號整數,後續字符串可包括'./e/E'
    public boolean scanA(char[] str,int index){
        //1.若是有符號則跳過。
        if(str[index] == '-' || str[index] == '+') index++;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            hasInt = true;
            index++;
        }
        if(index == str.length) return hasInt;
        if(str[index] == '.')
            return scanB(str,index+1);
        else if(str[index] == 'e'||str[index]=='E')
            return scanC(str,index+1);
        else
            return false;
    }
    //第二部分:爲不帶符號整數,後續字符可帶'e/E'
    public boolean scanB(char[] str,int index){
        boolean hasNum = false;
        //用於判斷是不是「12.」這種數字
        if(index == str.length) return hasInt || hasNum;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            index++;
            hasNum = true;
        }
        if(index == str.length) return hasInt || hasNum;
        if(str[index] == 'e' || str[index] == 'E')
            return (hasInt || hasNum) && scanC(str,index+1);
        else
            return false;
    }
    //第三部分:爲帶符號整數
    public boolean scanC(char[] str,int index){
        //用於判斷是否爲「12e」這樣的數字,這種是不正確的,第三部分不能爲空
        if(index == str.length) return false;
        boolean hasNum = false;
        //若是有符號,則跳過
        if(str[index]=='+'||str[index]=='-') index++;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            hasNum=true;
            index++;
        }  
        if(index == str.length) return hasNum;
        else return false;
    }
}

54.字符流中第一個不重複的字符

請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符「google"時,第一個只出現一次的字符是"l"。

輸出描述:

若是當前字符流沒有存在出現一次的字符,返回#字符。

import java.util.ArrayList;
import java.util.HashSet;
public class Solution {
    ArrayList<Character> list = new ArrayList<>();
    HashSet<Character> set = new HashSet<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if(!set.contains(ch))
            if(list.contains(ch)){
                //注意這裏之因此將char轉換爲Character對象,是由於,若是直接帶入char
                //函數會將char轉變成ASCII碼int值做爲索引,會致使溢出。
                list.remove((Character)ch);
                set.add(ch);
            }else{
                list.add(ch);
            }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        if(list.size() > 0)
            return list.get(0);
        else
            return '#';
    }
}

55.鏈表中的入口結點

一個鏈表中包含環,請找出該鏈表的環的入口結點。
方法一:使用輔助Set集合

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
import java.util.HashSet;
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null) return null;
        HashSet<ListNode> set = new HashSet<>();
        while(!set.contains(pHead)){
            if(pHead.next == null) return null;
            set.add(pHead);
            pHead = pHead.next;
        }
        return pHead;
            
    }
}

方法二:單純指針操做

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null) return null;
        ListNode p1=pHead,p2=pHead.next;
        //第一步:若是有環,則算出環的長度;
        while(p1 != p2 && p2 != null){
            p1 = p1.next;
            p2 = p2.next;
            if(p2 == null) return null;
            p2 = p2.next;
        }
        if(p2 == null) return null;
        int count = 1;
        while(p1.next != p2){
            p1 = p1.next;
            count++;
        }
        //第二步:找到環的入口
        p1 = pHead;
        p2 = pHead;
        while(count-- > 0)
            p2 = p2.next;
        while(p1!=p2){
            p1 = p1.next;
            p2 = p2.next;
        }
        return p1;     
    }
}

56.刪除鏈表中重複的結點這道題糾結了好久!!!很簡單的遞歸就能實現,有點相似於動態規劃

在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null || pHead.next == null)
            return pHead;
        if(pHead.val == pHead.next.val){
          while(pHead.next != null && pHead.val == pHead.next.val)
              pHead = pHead.next;
          return deleteDuplication(pHead.next);
        }
        pHead.next = deleteDuplication(pHead.next);
        return pHead;
    }
}

57.二叉樹的下一個結點

給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點而且返回。注意,樹中的結點不只包含左右子結點,同時包含指向父結點的指針。

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode == null) return null;
        if(pNode.right != null){
            TreeLinkNode node = pNode.right;
            while(node.left != null)
                node = node.left;
            return node;
        }
        while(pNode.next != null){
            if(pNode.next.right != pNode)
                return pNode.next;
            pNode = pNode.next;
        }
        return null;
    }
}

58.對稱的二叉樹

請實現一個函數,用來判斷一顆二叉樹是否是對稱的。注意,若是一個二叉樹同此二叉樹的鏡像是一樣的,定義其爲對稱的。

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        return isSymmetrical(pRoot,pRoot);
    }
    public boolean isSymmetrical(TreeNode n1,TreeNode n2){
        if(n1 == null && n2 == null) return true;
        if(n1 == null || n2 == null) return false;
        if(n1.val != n2.val) return false;
        return isSymmetrical(n1.left,n2.right) && isSymmetrical(n1.right,n2.left);
    }
}

59.==之字形打印二叉樹==

請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其餘行以此類推。
解題思路:參見《劍指offer》p176,使用兩個輔助棧進行操做

import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        if(pRoot == null) return result;
        int layer = 1;
        Stack<TreeNode> odd = new Stack<>();
        Stack<TreeNode> even = new Stack<>();
        odd.push(pRoot);
        while(!odd.empty()||!even.empty()){
            ArrayList<Integer> list = new ArrayList<>();
            if((layer & 1) == 1){//位運算,判斷是否爲奇數;等價於layer%2
                while(!odd.empty()){
                    TreeNode node = odd.pop();
                    list.add(node.val);
                    if(node.left != null) even.push(node.left);
                    if(node.right != null) even.push(node.right);
                }
            }else{
                while(!even.empty()){
                    TreeNode node = even.pop();
                    list.add(node.val);
                    if(node.right != null) odd.push(node.right);
                    if(node.left != null) odd.push(node.left);
                }
            }
            result.add(list);
            layer++;   
        }
        return result;
    } 
}

60.把二叉樹打印成多行

從上到下按層打印二叉樹,同一層結點從左至右輸出。每一層輸出一行。
注意要使用isEmpty()

import java.util.ArrayList;
import java.util.LinkedList;
public class Solution {
    ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        if(pRoot == null) return result;
        LinkedList<TreeNode> queue = new LinkedList<>();
        ArrayList<Integer> list = new ArrayList<>();
        queue.offer(pRoot);//將根節點加入隊列
        int elementsCount = 1;//用於記錄每一層的元素個數
        while(!queue.isEmpty()){//注意LinkedList 是沒有 enpty()方法的。
            TreeNode node = queue.poll();
            elementsCount--;
            list.add(node.val);
            if(node.left != null) queue.offer(node.left);
            if(node.right != null) queue.offer(node.right);
            if(elementsCount == 0){
                result.add(list);
                list = new ArrayList<>();
                elementsCount = queue.size();
            }
        }
        return result;
    }
}

61.序列化二叉樹

請實現兩個函數,分別用來序列化和反序列化二叉樹

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    String Serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        if(root == null)
            sb.append("$,");
        else{
            sb.append(root.val+",");
            sb.append(Serialize(root.left));
            sb.append(Serialize(root.right));
        }
        return sb.toString();
  }
    int index = -1;
    TreeNode Deserialize(String str) {
        if(str == null || str == "") return null;
        String[] strArray = str.split(",");
        if(strArray.length == 0) return null;
        return DeserializeCore(strArray);
   }
    TreeNode DeserializeCore(String[] strArray){     
        TreeNode node = null;
        index++;
        if(!strArray[index].equals("$")){
            node = new TreeNode(Integer.parseInt(strArray[index]));
            node.left = DeserializeCore(strArray);
            node.right = DeserializeCore(strArray);
        }
        return node;
    }
}

62.二叉搜索樹的第K個結點

給定一顆二叉搜索樹,請找出其中的第k大的結點。例如, 5 /  3 7 / / 2 4 6 8 中,按結點數值大小順序第三個結點的值爲4。(換句話說,從小到大排列,第k個數字)

import java.util.ArrayList;
public class Solution {
    ArrayList<TreeNode> list = new ArrayList<>();
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(k < 1 || pRoot == null) return null;
        LDR(pRoot);
        if(list.size() < k) return null;
        return list.get(k-1);
    }
    
    void LDR(TreeNode pRoot){
        if(pRoot.left != null)
            LDR(pRoot.left);
        list.add(pRoot);
        if(pRoot.right!=null)
            LDR(pRoot.right);
    }
}

63.數據流中的中位數

如何獲得一個數據流中的中位數?若是從數據流中讀出奇數個數值,那麼中位數就是全部數值排序以後位於中間的數值。若是從數據流中讀出偶數個數值,那麼中位數就是全部數值排序以後中間兩個數的平均值。

題目解析:若是直接使用ArrayList每次進行排序再選取中位數的話,時間複雜度爲O(n^2logn),每一次排序O(nlogn),共進行N次排序;而使用最大堆、最小堆操做,每次插入數據,取出數據均佔用O(logn)的時間,因此總共佔用時間複雜度爲O(NlogN)

import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>(){
        @Override
        public int compare(Integer i1,Integer i2){
            return i2-i1;
        }
    });
    public void Insert(Integer num) {
        minHeap.offer(num);
        if(minHeap.size()>maxHeap.size()){
            maxHeap.offer(minHeap.poll());
        }else{
            maxHeap.offer(minHeap.poll());
            minHeap.offer(maxHeap.poll());
        }
    }
    public Double GetMedian() {
        if(minHeap.size()==0&&maxHeap.size()==0)
            return null;
        if(minHeap.size() == maxHeap.size())
            return (double)(minHeap.peek()+maxHeap.peek())/2.0;
        return (double)maxHeap.peek();
    }
}

64.滑動窗口的最大值

給定一個數組和滑動窗口的大小,找出全部滑動窗口裏數值的最大值。例如,若是輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一共存在6個滑動窗口,他們的最大值分別爲{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有如下6個: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

import java.util.LinkedList; 
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> result = new ArrayList<>();
        if(num.length<1||size<1||size>num.length)
            return result;
        LinkedList<Integer> deque = new LinkedList<>();
        for(int i = 0;i<num.length;i++){
            while(!deque.isEmpty() && num[deque.peekLast()] <= num[i])
                deque.pollLast();
            deque.offerLast(i);
            if(i>=size-1){
                while(i-deque.peekFirst()>size-1)
                    deque.pollFirst();
                result.add(num[deque.peekFirst()]);
            }
        }
        return result;
    }
}

65.矩陣中的路徑

請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串全部字符的路徑。路徑能夠從矩陣中的任意一個格子開始,每一步能夠在矩陣中向左,向右,向上,向下移動一個格子。若是一條路徑通過了矩陣中的某一個格子,則該路徑不能再進入該格子。 例如 a b c e s f c s a d e e 矩陣中包含一條字符串"bcced"的路徑,可是矩陣中不包含"abcb"路徑,由於字符串的第一個字符b佔據了矩陣中的第一行第二個格子以後,路徑不能再次進入該格子。

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {    
        if(matrix == null || rows<1 || cols<1 || str == null) return false;
        boolean[][] visited = new boolean[rows][cols];
        int pathLength = 0;
        for(int row = 0;row<rows;row++)
            for(int col = 0 ;col<cols;col++){
                if(hasPathCore(matrix,rows,cols,row,col,str,visited,pathLength))
                    return true;
            }
        return false;
    }
    public boolean hasPathCore(char[] matrix,int rows,int cols,int row,int col,char[] str,boolean[][] visited,int pathLength){
        if(pathLength == str.length) return true;
        boolean hasPath = false;
        if(row>=0 && col>=0 && row<rows && col<cols && visited[row][col]==false && matrix[row*cols+col] == str[pathLength]){
            pathLength++;
            visited[row][col] = true;
            hasPath = hasPathCore(matrix,rows,cols,row+1,col,str,visited,pathLength)
                ||hasPathCore(matrix,rows,cols,row-1,col,str,visited,pathLength)
                ||hasPathCore(matrix,rows,cols,row,col+1,str,visited,pathLength)
                ||hasPathCore(matrix,rows,cols,row,col-1,str,visited,pathLength);
            if(!hasPath){
                pathLength--;
                visited[row][col] = false;
            }     
        }
        return hasPath;
    }
}

66.機器人的運動範圍

地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,可是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人可以進入方格(35,37),由於3+5+3+7 = 18。可是,它不能進入方格(35,38),由於3+5+3+8 = 19。請問該機器人可以達到多少個格子?

public class Solution {
    public int movingCount(int threshold, int rows, int cols) {
        if (threshold < 1 || rows < 1 || cols < 1) return 0;
        boolean[][] visited = new boolean[rows][cols];
        return movingCountCore(threshold, 0, 0, rows, cols, visited);

    }

    public int movingCountCore(int threshold, int row, int col, int rows, int cols, boolean[][] visited) {
        int count = 0;
        if (check(threshold, row, col, rows, cols, visited)) {
            visited[row][col] = true;
            count = 1 + movingCountCore(threshold, row + 1, col, rows, cols, visited)
                    + movingCountCore(threshold, row - 1, col, rows, cols, visited)
                    + movingCountCore(threshold, row, col + 1, rows, cols, visited)
                    + movingCountCore(threshold, row, col - 1, rows, cols, visited);
        }
        return count;

    }

    public boolean check(int threshold, int row, int col, int rows, int cols, boolean[][] visited) {
        if (row < 0 || col < 0 || row >= rows || col >= cols || visited[row][col])
            return false;
        int num = 0;
        while (col != 0 || row != 0) {
            num += col % 10;
            num += row % 10;
            col /= 10;
            row /= 10;
        }
        if (num > threshold)
            return false;
        return true;
    }

}

個人博客即將搬運同步至騰訊雲+社區,邀請你們一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=2jb8bijgh4mc8

相關文章
相關標籤/搜索