1. 程式人生 > >初級4-1 佇列棧題目

初級4-1 佇列棧題目

題目四:貓狗佇列

【題目】 寵物、狗和貓的類如下:
public class Pet { private String type;
public Pet(String type) { this.type = type; }
public String getPetType() { return this.type; }
}
public class Dog extends Pet { public Dog() { super("dog"); } }
public class Cat extends Pet { public Cat() { super("cat"); } }
實現一種狗貓佇列的結構,要求如下: 使用者可以呼叫add方法將cat類或dog類的
例項放入佇列中; 使用者可以呼叫pollAll方法,將佇列中所有的例項按照進佇列
的先後順序依次彈出; 使用者可以呼叫pollDog方法,將佇列中dog類的例項按照
進佇列的先後順序依次彈出; 使用者可以呼叫pollCat方法,將佇列中cat類的實
例按照進佇列的先後順序依次彈出; 使用者可以呼叫isEmpty方法,檢查佇列中是
否還有dog或cat的例項; 使用者可以呼叫isDogEmpty方法,檢查佇列中是否有dog
類的例項; 使用者可以呼叫isCatEmpty方法,檢查佇列中是否有cat類的例項。

 

package class_03;

import java.util.LinkedList;
import java.util.Queue;

public class Code_04_DogCatQueue {

    public static class Pet {
        private String type;

        public Pet(String type) {
            this.type = type;
        }

        public String getPetType() {
            
return this.type; } } public static class Dog extends Pet { public Dog() { super("dog"); } } public static class Cat extends Pet { public Cat() { super("cat"); } } public static class PetEnterQueue {
private Pet pet; private long count; public PetEnterQueue(Pet pet, long count) { this.pet = pet; this.count = count; } public Pet getPet() { return this.pet; } public long getCount() { return this.count; } public String getEnterPetType() { return this.pet.getPetType(); } } public static class DogCatQueue { private Queue<PetEnterQueue> dogQ; private Queue<PetEnterQueue> catQ; private long count; public DogCatQueue() { this.dogQ = new LinkedList<PetEnterQueue>(); this.catQ = new LinkedList<PetEnterQueue>(); this.count = 0; } public void add(Pet pet) { if (pet.getPetType().equals("dog")) { this.dogQ.add(new PetEnterQueue(pet, this.count++)); } else if (pet.getPetType().equals("cat")) { this.catQ.add(new PetEnterQueue(pet, this.count++)); } else { throw new RuntimeException("err, not dog or cat"); } } public Pet pollAll() { if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) { if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()) { return this.dogQ.poll().getPet(); } else { return this.catQ.poll().getPet(); } } else if (!this.dogQ.isEmpty()) { return this.dogQ.poll().getPet(); } else if (!this.catQ.isEmpty()) { return this.catQ.poll().getPet(); } else { throw new RuntimeException("err, queue is empty!"); } } public Dog pollDog() { if (!this.isDogQueueEmpty()) { return (Dog) this.dogQ.poll().getPet(); } else { throw new RuntimeException("Dog queue is empty!"); } } public Cat pollCat() { if (!this.isCatQueueEmpty()) { return (Cat) this.catQ.poll().getPet(); } else throw new RuntimeException("Cat queue is empty!"); } public boolean isEmpty() { return this.dogQ.isEmpty() && this.catQ.isEmpty(); } public boolean isDogQueueEmpty() { return this.dogQ.isEmpty(); } public boolean isCatQueueEmpty() { return this.catQ.isEmpty(); } } public static void main(String[] args) { DogCatQueue test = new DogCatQueue(); Pet dog1 = new Dog(); Pet cat1 = new Cat(); Pet dog2 = new Dog(); Pet cat2 = new Cat(); Pet dog3 = new Dog(); Pet cat3 = new Cat(); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); while (!test.isDogQueueEmpty()) { System.out.println(test.pollDog().getPetType()); } while (!test.isEmpty()) { System.out.println(test.pollAll().getPetType()); } } }

 

 題目五轉圈列印矩陣

【題目】 給定一個整型矩陣matrix,請按照轉圈的方式列印它。
例如: 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
【要求】 額外空間複雜度為O(1)。

 

package class_03;

public class Code_06_PrintMatrixSpiralOrder {

    public static void spiralOrderPrint(int[][] matrix) {
        int tR = 0;
        int tC = 0;
        int dR = matrix.length - 1;
        int dC = matrix[0].length - 1;
        while (tR <= dR && tC <= dC) {
            printEdge(matrix, tR++, tC++, dR--, dC--);
        }
    }

    public static void printEdge(int[][] m, int tR, int tC, int dR, int dC) {
        if (tR == dR) {
            for (int i = tC; i <= dC; i++) {
                System.out.print(m[tR][i] + " ");
            }
        } else if (tC == dC) {
            for (int i = tR; i <= dR; i++) {
                System.out.print(m[i][tC] + " ");
            }
        } else {
            int curC = tC;
            int curR = tR;
            while (curC != dC) {
                System.out.print(m[tR][curC] + " ");
                curC++;
            }
            while (curR != dR) {
                System.out.print(m[curR][dC] + " ");
                curR++;
            }
            while (curC != tC) {
                System.out.print(m[dR][curC] + " ");
                curC--;
            }
            while (curR != tR) {
                System.out.print(m[curR][tC] + " ");
                curR--;
            }
        }
    }

    public static void main(String[] args) {
        int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
                { 13, 14, 15, 16 } };
        spiralOrderPrint(matrix);

    }

}

 

 

題目六:旋轉正方形矩陣

【題目】 給定一個整型正方形矩陣matrix,請把該矩陣調整成
順時針旋轉90度的樣子。
【要求】 額外空間複雜度為O(1)。

 

先轉外圈

1、 1,4,13,16

2、2,8,15,9

3、5,12,14,5

package class_03;

public class Code_05_RotateMatrix {

    public static void rotate(int[][] matrix) {
        int tR = 0;
        int tC = 0;
        int dR = matrix.length - 1;
        int dC = matrix[0].length - 1;
        while (tR < dR) {
            rotateEdge(matrix, tR++, tC++, dR--, dC--);
        }
    }

    public static void rotateEdge(int[][] m, int tR, int tC, int dR, int dC) {
        int times = dC - tC; 
        int tmp = 0;
        for (int i = 0; i != times; i++) {
            tmp = m[tR][tC + i];
            m[tR][tC + i] = m[dR - i][tC];
            m[dR - i][tC] = m[dR][dC - i];
            m[dR][dC - i] = m[tR + i][dC];
            m[tR + i][dC] = tmp;
        }
    }

    public static void printMatrix(int[][] matrix) {
        for (int i = 0; i != matrix.length; i++) {
            for (int j = 0; j != matrix[0].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
                { 13, 14, 15, 16 } };
        printMatrix(matrix);
        rotate(matrix);
        System.out.println("=========");
        printMatrix(matrix);

    }

}

 

 

題目七:轉單向和雙向連結串列


【題目】 分別實現反轉單向連結串列和反轉雙向連結串列的函式。
【要求】 如果連結串列長度為N,時間複雜度要求為O(N),額外空間
複雜度要求為O(1)

package class_03;

public class Code_07_ReverseList {

    public static class Node {
        public int value;
        public Node next;

        public Node(int data) {
            this.value = data;
        }
    }

    public static Node reverseList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    public static class DoubleNode {
        public int value;
        public DoubleNode last;
        public DoubleNode next;

        public DoubleNode(int data) {
            this.value = data;
        }
    }

    public static DoubleNode reverseList(DoubleNode head) {
        DoubleNode pre = null;
        DoubleNode next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            head.last = next;
            pre = head;
            head = next;
        }
        return pre;
    }

    public static void printLinkedList(Node head) {
        System.out.print("Linked List: ");
        while (head != null) {
            System.out.print(head.value + " ");
            head = head.next;
        }
        System.out.println();
    }

    public static void printDoubleLinkedList(DoubleNode head) {
        System.out.print("Double Linked List: ");
        DoubleNode end = null;
        while (head != null) {
            System.out.print(head.value + " ");
            end = head;
            head = head.next;
        }
        System.out.print("| ");
        while (end != null) {
            System.out.print(end.value + " ");
            end = end.last;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Node head1 = new Node(1);
        head1.next = new Node(2);
        head1.next.next = new Node(3);
        printLinkedList(head1);
        head1 = reverseList(head1);
        printLinkedList(head1);

        DoubleNode head2 = new DoubleNode(1);
        head2.next = new DoubleNode(2);
        head2.next.last = head2;
        head2.next.next = new DoubleNode(3);
        head2.next.next.last = head2.next;
        head2.next.next.next = new DoubleNode(4);
        head2.next.next.next.last = head2.next.next;
        printDoubleLinkedList(head2);
        printDoubleLinkedList(reverseList(head2));

    }

}

 

 題目八:“之”字形列印矩陣

【題目】 給定一個矩陣matrix,按照“之”字形的方式列印這
個矩陣,例如: 1 2 3 4 5 6 7 8 9 10 11 12
“之”字形列印的結果為:1,2,5,9,6,3,4,7,10,11,
8,12
【要求】 額外空間複雜度為O(1)。

 

coding:對資料加工的一種技巧

設計巨集觀結構

 

bool型別

A--> 往左,到邊界向下

B--> 往下,到邊界往右

每次列印對角線,AB分開移動

package class_03;

public class Code_08_ZigZagPrintMatrix {

    public static void printMatrixZigZag(int[][] matrix) {
        int tR = 0;
        int tC = 0;
        int dR = 0;
        int dC = 0;
        int endR = matrix.length - 1;
        int endC = matrix[0].length - 1;
        boolean fromUp = false;
        while (tR != endR + 1) {
            printLevel(matrix, tR, tC, dR, dC, fromUp);
            tR = tC == endC ? tR + 1 : tR;
            tC = tC == endC ? tC : tC + 1;
            dC = dR == endR ? dC + 1 : dC;
            dR = dR == endR ? dR : dR + 1;
            fromUp = !fromUp;
        }
        System.out.println();
    }

    public static void printLevel(int[][] m, int tR, int tC, int dR, int dC,
            boolean f) {
        if (f) {
            while (tR != dR + 1) {
                System.out.print(m[tR++][tC--] + " ");
            }
        } else {
            while (dR != tR - 1) {
                System.out.print(m[dR--][dC++] + " ");
            }
        }
    }

    public static void main(String[] args) {
        int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
        printMatrixZigZag(matrix);

    }

}

 

 

“巨集觀”解決列印問題

 

 題目九:在行列都排好序的矩陣中找數

【題目】 給定一個有N*M的整型矩陣matrix和一個整數K,
matrix的每一行和每一 列都是排好序的。實現一個函式,判斷K
是否在matrix中。 例如: 0 1 2 5 2 3 4 7 4
4 4 8 5 7 7 9 如果K為7,返回true;如果K為6,返
回false。
【要求】 時間複雜度為O(N+M),額外空間複雜度為O(1)。

 

 

package class_03;

public class Code_09_FindNumInSortedMatrix {

    public static boolean isContains(int[][] matrix, int K) {
        int row = 0;
        int col = matrix[0].length - 1;
        while (row < matrix.length && col > -1) {
            if (matrix[row][col] == K) {
                return true;
            } else if (matrix[row][col] > K) {
                col--;
            } else {
                row++;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int[][] matrix = new int[][] { { 0, 1, 2, 3, 4, 5, 6 },// 0
                { 10, 12, 13, 15, 16, 17, 18 },// 1
                { 23, 24, 25, 26, 27, 28, 29 },// 2
                { 44, 45, 46, 47, 48, 49, 50 },// 3
                { 65, 66, 67, 68, 69, 70, 71 },// 4
                { 96, 97, 98, 99, 100, 111, 122 },// 5
                { 166, 176, 186, 187, 190, 195, 200 },// 6
                { 233, 243, 321, 341, 356, 370, 380 } // 7
        };
        int K = 233;
        System.out.println(isContains(matrix, K));
    }

}

 

兩大思路

 一個題的最優解來自這個題目的 資料狀況

 一個題的最優解來自這個題目的 本身問法

 

 

題目十:列印兩個有序連結串列的公共部分


【題目】 給定兩個有序連結串列的頭指標head1和head2,列印兩個
連結串列的公共部分。

 

類似快排中的merge

 

package class_03;

public class Code_10_PrintCommonPart {

    public static class Node {
        public int value;
        public Node next;
        public Node(int data) {
            this.value = data;
        }
    }

    public static void printCommonPart(Node head1, Node head2) {
        System.out.print("Common Part: ");
        while (head1 != null && head2 != null) {
            if (head1.value < head2.value) {
                head1 = head1.next;
            } else if (head1.value > head2.value) {
                head2 = head2.next;
            } else {
                System.out.print(head1.value + " ");
                head1 = head1.next;
                head2 = head2.next;
            }
        }
        System.out.println();
    }

    public static void printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.value + " ");
            node = node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Node node1 = new Node(2);
        node1.next = new Node(3);
        node1.next.next = new Node(5);
        node1.next.next.next = new Node(6);

        Node node2 = new Node(1);
        node2.next = new Node(2);
        node2.next.next = new Node(5);
        node2.next.next.next = new Node(7);
        node2.next.next.next.next = new Node(8);

        printLinkedList(node1);
        printLinkedList(node2);
        printCommonPart(node1, node2);

    }

}

 

連結串列問題

空間複雜度O(1)    面試中重點是O(1)

時間複雜度O(n)

 

如果用輔助空間,下面的題目都很easy

 

題目十一:判斷一個連結串列是否為迴文結構

【題目】 給定一個連結串列的頭節點head,請判斷該連結串列是否為回
文結構。 例如: 1->2->1,返回true。 1->2->2->1,返回true。
15->6->15,返回true。 1->2->3,返回false。


進階: 如果連結串列長度為N,時間複雜度達到O(N),額外空間複雜
度達到O(1)。

1、放入棧    O(N)

 

2、快慢指標  O(N/2)

 

 3、面試中,快慢指標   O(1)

完美解法

快指標 2步,走完

慢指標1步,重點

右半部分逆序

 

一一比對,相同的話,True,False

資料要恢復回來

 

 

package class_03;

import java.util.Stack;

public class Code_11_IsPalindromeList {

    public static class Node {
        public int value;
        public Node next;

        public Node(int data) {
            this.value = data;
        }
    }

    // need n extra space
    public static boolean isPalindrome1(Node head) {
        Stack<Node> stack = new Stack<Node>();
        Node cur = head;
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        while (head != null) {
            if (head.value != stack.pop().value) {
                return false;
            }
            head = head.next;
        }
        return true;
    }

    // need n/2 extra space
    public static boolean isPalindrome2(Node head) {
        if (head == null || head.next == null) {
            return true;
        }
        Node right = head.next;
        Node cur = head;
        while (cur.next != null && cur.next.next != null) {
            right = right.next;
            cur = cur.next.next;
        }
        Stack<Node> stack = new Stack<Node>();
        while (right != null) {
            stack.push(right);
            right = right.next;
        }
        while (!stack.isEmpty()) {
            if (head.value != stack.pop().value) {
                return false;
            }
            head = head.next;
        }
        return true;
    }

    // need O(1) extra space
    public static boolean isPalindrome3(Node head) {
        if (head == null || head.next == null) {
            return true;
        }
        Node n1 = head;
        Node n2 = head;
        while (n2.next != null && n2.next.next != null) { // find mid node
            n1 = n1.next; // n1 -> mid
            n2 = n2.next.next; // n2 -> end
        }
        n2 = n1.next; // n2 -> right part first node
        n1.next = null; // mid.next -> null
        Node n3 = null;
        while (n2 != null) { // right part convert
            n3 = n2.next; // n3 -> save next node
            n2.next = n1; // next of right node convert
            n1 = n2; // n1 move
            n2 = n3; // n2 move
        }
        n3 = n1; // n3 -> save last node
        n2 = head;// n2 -> left first node
        boolean res = true;
        while (n1 != null && n2 != null) { // check palindrome
            if (n1.value != n2.value) {
                res = false;
                break;
            }
            n1 = n1.next; // left to mid
            n2 = n2.next; // right to mid
        }
        n1 = n3.next;
        n3.next = null;
        while (n1 != null) { // recover list
            n2 = n1.next;
            n1.next = n3;
            n3 = n1;
            n1 = n2;
        }
        return res;
    }

    public static void printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.value + " ");
            node = node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {

        Node head = null;
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        head.next.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(2);
        head.next.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        head.next.next.next = new Node(2);
        head.next.next.next.next = new Node(1);
        printLinkedList(head);
        System.out.print(isPalindrome1(head) + " | ");
        System.out.print(isPalindrome2(head) + " | ");
        System.out.println(isPalindrome3(head) + " | ");
        printLinkedList(head);
        System.out.println("=========================");

    }

}

 

 

左神:推薦用C++程式碼

不要求有語言特性

比如 range(len(array))

 

題目十二:將單向連結串列按某值劃分成左邊小、中間相等、右邊大的形式

 

 荷蘭國旗問題

【題目】 給定一個單向連結串列的頭節點head,節點的值型別是整型,再給定一個
整 數pivot。實現一個調整連結串列的函式,將連結串列調整為左部分都是值小於 pivot
的節點,中間部分都是值等於pivot的節點,右部分都是值大於 pivot的節點。
除這個要求外,對調整後的節點順序沒有更多的要求。 例如:連結串列9->0->4->5-
>1,pivot=3。 調整後連結串列可以是1->0->4->9->5,也可以是0->1->9->5->4。總
之,滿 足左部分都是小於3的節點,中間部分都是等於3的節點(本例中這個部
分為空),右部分都是大於3的節點即可。對某部分內部的節點順序不做 要求。

 

與面試官聊天

1、什麼是穩定性

2、荷蘭國旗不具有穩定性

3、連結串列問題可以省略空間完成

4、你coding達標

 

進階: 在原問題的要求之上再增加如下兩個要求。
在左、中、右三個部分的內部也做順序要求,要求每部分裡的節點從左 到右的
順序與原連結串列中節點的先後次序一致。 例如:連結串列9->0->4->5->1,pivot=3。
調整後的連結串列是0->1->9->4->5。 在滿足原問題要求的同時,左部分節點從左到
右為0、1。在原連結串列中也 是先出現0,後出現1;中間部分在本例中為空,不再
討論;右部分節點 從左到右為9、4、5。在原連結串列中也是先出現9,然後出現4,
最後出現5。
如果連結串列長度為N,時間複雜度請達到O(N),額外空間複雜度請達到O(1)。