1. 程式人生 > >【劍指offer】21-30題

【劍指offer】21-30題

21.定義棧的資料結構,請在該型別中實現一個能夠得到棧最小元素的min函式。

思路:定義兩個棧,一個存放入的值。另一個存最小值。

程式碼實現:

public void push(int node) {
    stack1.push(node);
    if (stack2.isEmpty()) {
        stack2.push(node);
    }else {
        if (stack2.peek() > node) {
            stack2.push(node);
        }
    }
}

public void pop() {
    if (stack1.pop() == stack2.peek()) {
        stack2.pop();
    }
}

public int top() {
    return stack1.peek();
}

public int min() {
    return stack2.peek();
}

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

思路:用棧來壓入彈出元素,相等則出棧。

程式碼實現:

public boolean IsPopOrder(int [] pushA,int [] popA) {
    if (pushA == null || popA == null) {
        return false;
    }
    Stack<Integer> stack = new Stack<>();
    int index = 0;

    for (int i = 0; i < pushA.length; i++) {
        stack.push(pushA[i]);
        while (!stack.isEmpty() && stack.peek() == popA[index]) {
            stack.pop();
            index++;
        }
    }
    return stack.isEmpty();
}

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

思路:利用佇列(連結串列)輔助實現。

程式碼實現:

public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
    ArrayList<Integer> list = new ArrayList<>();
    if (root == null) {
        return list;
    }
    LinkedList<TreeNode> queue = new LinkedList<>();
    queue.add(root);

    while (!queue.isEmpty()) {
        TreeNode node = queue.poll();
        list.add(node.val);
        if (node.left != null) {
            queue.addLast(node.left);
        }
        if (node.right != null) {
            queue.addLast(node.right);
        }
    }
    return list;
}

24.輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的陣列的任意兩個數字都互不相同。

思路:先找到右子樹的開始位置,然後分別進行左右子樹遞迴處理。

程式碼實現:  

public boolean VerifySquenceOfBST(int[] sequence) {
    if (sequence == null || sequence.length == 0)
        return false;
    int rstart = 0;
    int length = sequence.length;

    for (int i = 0; i < length - 1; i++) {
        if (sequence[i] < sequence[length - 1])
            rstart++;
    }

    if (rstart == 0) {
        VerifySquenceOfBST(Arrays.copyOfRange(sequence,0,length-1));
    }else {
        for (int i = rstart; i < length - 1; i++) {
            if (sequence[i] <= sequence[length - 1]) {
                return false;
            }
        }
        VerifySquenceOfBST(Arrays.copyOfRange(sequence,0,rstart));
        VerifySquenceOfBST(Arrays.copyOfRange(sequence,rstart,length - 1));
    }
    return true;
}

25.輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。

思路:先儲存根節點,然後分別遞迴在左右子樹中找目標值,若找到即到達葉子節點,列印路徑中的值

程式碼實現:

public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
    if(root == null)
        return resultList;
    list.add(root.val);
    target -= root.val;

    if(target == 0 && root.left == null && root.right == null){
        resultList.add(new ArrayList<>(list));
    }else {
        FindPath(root.left,target);
        FindPath(root.right,target);
    }
    //每返回上一層一次就要回退一個節點
    list.remove(list.size()-1);
    return resultList;
}

26.輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標指向任意一個節點),返回結果為複製後複雜連結串列的head。(注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空)

思路:先複製連結串列的next節點,將複製後的節點接在原節點後,然後複製其它的節點,最後取偶數位置的節點(複製後的節點)。

程式碼實現:

public RandomListNode Clone2(RandomListNode pHead) {
    if(pHead == null)
        return null;
    RandomListNode head = new RandomListNode(pHead.label) ;
    RandomListNode temp = head ;

    while(pHead.next != null) {
        temp.next = new RandomListNode(pHead.next.label) ;
        if(pHead.random != null) {
            temp.random = new RandomListNode(pHead.random.label) ;
        }
        pHead = pHead.next ;
        temp = temp.next ;
    }
    return head ;
}

27.輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。

思路:定義一個連結串列的尾節點,遞迴處理左右子樹,最後返回連結串列的頭節點

程式碼實現:

public TreeNode Convert(TreeNode pRootOfTree) {
    TreeNode lastlist = covertNode(pRootOfTree,null);
    TreeNode pHead = lastlist;
    while (pHead != null && pHead.left != null) {
        pHead = pHead.left;
    }
    return pHead;
}

public TreeNode covertNode(TreeNode root, TreeNode lastlist) {
    if (root == null)
        return null;
    TreeNode cur = root;
    if (cur.left != null) {
        lastlist = covertNode(cur.left,lastlist);
    }
    cur.left = lastlist;
    if (lastlist != null) {
        lastlist.right = cur;
    }
    lastlist = cur;
    if (cur.right != null) {
        lastlist = covertNode(cur.right,lastlist);
    }
    return lastlist;
}

28.輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。

思路:將當前位置的字元和前一個字元位置交換,遞迴。

程式碼實現:

public ArrayList<String> Permutation(String str) {
    ArrayList<String> result = new ArrayList<String>() ;
    if(str == null || str.length() == 0)
        return result;
    char[] chars = str.toCharArray() ;
    TreeSet<String> temp = new TreeSet<>() ;
    Permutation(chars, 0, temp);
    result.addAll(temp) ;
    return result ;
}

public void Permutation(char[] chars, int index, TreeSet<String> result) {
    if(chars == null || chars.length == 0 )
        return ;
    if (index < 0 || index > chars.length - 1)
        return;
    if(index == chars.length-1) {
        result.add(String.valueOf(chars)) ;
    }else {
        for(int i=index ; i<=chars.length-1 ; i++) {
            swap(chars, index, i) ;
            Permutation(chars, index+1, result);
            // 回退
            swap(chars, index, i) ;
        }
    }
}

public void swap(char[] c, int a,int b) {
    char temp = c[a];
    c[a] = c[b];
    c[b] = temp;
}

29.陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字

思路:將首次出現的數count+1,與之後的數進行比較,相等則+1,否則—1,最後進行校驗是否超過長度的一半。

程式碼實現:

public int MoreThanHalfNum_Solution(int [] array) {
    int maxCount = array[0];
    int number = array[0];
    int count = 1;

    for (int i = 1; i < array.length; i++) {
        if (number != array[i]) {
            if (count == 0) {
                number = array[i];
                count = 1;
            }else {
                count--;
            }
        }else {
            count++;
        }

        if (count == 1) {
            maxCount = number;
        }
    }
    // 驗證
    int num = 0;
    for (int j = 0; j < array.length; j++) {
        if (array[j] == maxCount) {
            num++;
        }
    }

    if (num * 2 > array.length) {
        return maxCount;
    }
    return 0;
}

30.輸入n個整數,找出其中最小的K個數。

思路:先將前K個數放入陣列,進行堆排序,若之後的數比它還小,則進行調整

程式碼實現:

public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
    ArrayList<Integer> list = new ArrayList<>();
    if (input == null || k <= 0 || k > input.length) {
        return list;
    }
    int[] kArray = Arrays.copyOfRange(input,0,k);
    // 建立大根堆
    buildHeap(kArray);

    for(int i = k; i < input.length; i++) {
        if(input[i] < kArray[0]) {
            kArray[0] = input[i];
            maxHeap(kArray, 0);
        }
    }

    for (int i = kArray.length - 1; i >= 0; i--) {
        list.add(kArray[i]);
    }

    return list;
}

public void buildHeap(int[] input) {
    for (int i = input.length/2 - 1; i >= 0; i--) {
        maxHeap(input,i);
    }
}

private void maxHeap(int[] array,int i) {
    int left=2*i+1;
    int right=left+1;
    int largest=0;

    if(left < array.length && array[left] > array[i])
        largest=left;
    else
        largest=i;

    if(right < array.length && array[right] > array[largest])
        largest = right;

    if(largest != i) {
        int temp = array[i];
        array[i] = array[largest];
        array[largest] = temp;
        maxHeap(array, largest);
    }
}

未完待續。。。。。。