算法基礎(四)

隊列例子node

貓狗隊列數組

寵物、狗和貓的類以下:數據結構

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類的 實例放入隊列中;oop

用戶能夠調用pollAll方法,將隊列中全部的實例按照進隊列 的前後順序依次彈出;ui

用戶能夠調用pollDog方法,將隊列中dog類的實例按照 進隊列的前後順序依次彈出;this

用戶能夠調用pollCat方法,將隊列中cat類的實 例按照進隊列的前後順序依次彈出;spa

用戶能夠調用isEmpty方法,檢查隊列中是 否還有dog或cat的實例;指針

用戶能夠調用isDogEmpty方法,檢查隊列中是否有dog 類的實例;code

用戶能夠調用isCatEmpty方法,檢查隊列中是否有cat類的實例。

public class 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 AnimalQueue{
        private Queue<PetEnterQueue> dogQ;
        private Queue<PetEnterQueue> catQ;
        private long count;

        public AnimalQueue() {
            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();
        }
    }
}

轉圈打印矩陣

【題目】 給定一個整型矩陣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)

/*找最左上和最右下方兩個座標,調用函數遍歷打印
    * 而後座標不斷往中心移動,繼續調用函數遍歷打印
    * ,直到座標相遇,橫縱相遇都算,
    * */
    public static void findEdge(int[][] matrix){
        int lx=0;
        int ly=0;
        int rx=matrix.length-1;
        int ry=matrix[0].length-1;
        while(lx<=rx&&ly<=ry){
            printEdge(matrix,lx++,ly++,rx--,ry--);
        }
    }
    private static void printEdge(int[][] matrix, int lx, int ly, int rx, int ry) {
        //行相遇,從左到右打印
        if(lx==rx){
            for(int i=ly;i<=ry;i++){
                System.out.print(matrix[lx][i]+" ");
            }
        }
        //列相遇,從上到下打印
        else if(ly==ry){
            for(int i=lx;i<=rx;i++){
                System.out.print(matrix[i][ly]+" ");
            }
        }else{
            int curx=lx;
            int cury=ly;
            //左——>右
            while(cury!=ry){
                System.out.print(matrix[lx][cury++]+" ");
            }
            //上——>下
            while(curx!=rx){
                System.out.print(matrix[curx++][ry]+" ");
            }
            //右——>左
            while(cury!=ly){
                System.out.print(matrix[rx][cury--]+" ");
            }
            //下——>上
            while(curx!=lx){
                System.out.print(matrix[curx--][ly]+" ");
            }
        }
    }

 旋轉正方形矩陣

給定一個整型正方形矩陣matrix,請把該矩陣調整成 順時針旋轉90度的樣子。

【要求】 額外空間複雜度爲O(1)

public static void rotate(int[][] matrix){
        int lx=0;
        int ly=0;
        int rx=matrix.length-1;
        int ry=matrix[0].length-1;
        while(lx<rx){
            rotateEdge(matrix,lx++,ly++,rx--,ry--);
        }
    }
    private static void rotateEdge(int[][] matrix, int lx, int ly, int rx, int ry) {
        int temp=0;
        for(int i=0;i!=rx-lx;i++){
            temp=matrix[lx][ly+i];
            matrix[lx][ly+i]=matrix[rx-i][ly];
            matrix[rx-i][ly]=matrix[rx][ry-i];
            matrix[rx][ry-i]=matrix[lx+i][ry];
            matrix[lx+i][ry]=temp;
        }
    }

「之」字形打印矩陣 

給定一個矩陣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)。

  /*定義兩個座標啊a,b
     * a先向右移,移到最右後向下移,移到最下角中止
     * b先向下移,移到最下後向右移,移到最下角中止
     * 這樣兩個座標就能夠連城對角線,座標就是兩個邊界,遍歷線上的數便可
     * */
    public static void findEdge(int[][] matrix){
        int ax=0;
        int ay=0;
        int bx=0;
        int by=0;
        int endX=matrix.length-1;
        int endY=matrix[0].length-1;
        boolean flag=false;
        //當座標a移到最下角時中止
        while (ax!=endX+1){
            print(matrix,ax,ay,bx,by,flag);
            ax=ay==endY?ax+1:ax;
            ay=ay==endY?ay:ay+1;
            //這裏要先給by賦值,由於下面的操做會影響bx的值
            by=bx==endX?by+1:by;
            bx=bx==endX?bx:bx+1;
            flag=!flag;
        }
    }
    private static void print(int[][] matrix, int ax, int ay, int bx, int by, boolean flag) {
        if(flag){
            //右上——左下
            while(ax!=bx+1){
                System.out.print(matrix[ax++][ay--]+" ");
            }
        }else{
            //左下——右上
            while(bx!=ax-1){
                System.out.print(matrix[bx--][by++]+" ");
            }
        }
    }

 在行列都排好序的矩陣中找數 

給定一個有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)。

 public static  boolean isContains(int[][] matrix,int num){
        /*起點定在右上角
        * 根據比較數的大小,來進行左移或者下移
        * 若是相等,直接返回true
        * 若是查的數比num大,左移,這個數下面的數排掉,由於確定比num大
        * 若是查的數比num小,下移,這個數左邊的數排掉,由於確定比num小
        *
        * */
        int row=0;
        int col=matrix[0].length-1;
        while(row<matrix.length&&col>-1){
            if(matrix[row][col]==num){
                return true;
            }else if(matrix[row][col]>num){
                col--;
            }else{
                row++;
            }
        }
        return false;
    }

 單向鏈表反轉

public class 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 void printLinkedList(Node head){
        while (head!=null){
            System.out.print(head.value+" ");
            head=head.next;
        }
        System.out.println();
    }

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

 判斷一個鏈表是否爲迴文結構

給定一個鏈表的頭節點head,請判斷該鏈表是否爲回 文結構。

例如:

1->2->1,返回true。

1->2->2->1,返回true。

15->6->15,返回true。

1->2->3,返回false。

public class isHuiWenList {
    public static class Node{
        public int value;
        public Node next;
        public Node(int data){
            this.value=data;
        }
    }
    //方法1,空間複雜度n
    //利用棧來存儲,再進行比較
    public static boolean isHuiWen1(Node head){
        Stack<Node> s=new Stack<Node>();
        Node cur=head;
        while(cur!=null){
            s.push(cur);
            cur=cur.next;
        }
        while (head!=null){
            if(head.value!=s.pop().value){
                return false;
            }
            head=head.next;
        }
        return true;
    }
    //方法2,空間複雜度n/2
    //定義兩個快慢指針,當cur走完時,right恰好走到中間,進行壓棧,出棧比較
    public static boolean isHuiWen2(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> s=new Stack<Node>();
        while(right!=null){
            s.push(right);
            right=right.next;
        }
        while(!s.isEmpty()){
            if(head.value!=s.pop().value){
                return false;
            }
            head=head.next;
        }
        return true;
    }
    //方法3,空間複雜度1
    //定義兩個快慢指針,
    public static boolean isHuiWen3(Node head){
        if(head==null||head.next==null)
            return true;
        Node n1=head;//慢指針
        Node n2=head;//快指針
        while(n2.next!=null&&n2.next.next!=null){
            n1=n1.next;//中止時在中間
            n2=n2.next.next;//中止時在末尾
        }
        n2=n1.next;//右半部分第一個結點
        n1.next=null;//mid.next->null
        Node n3=null;
        while(n2!=null){//右半部分反轉
            n3=n2.next;//保留下一個結點
            n2.next=n1;//當前結點指向前面結點
            n1=n2;//前面結點設置爲當前結點
            n2=n3;//當前結點設置爲下一個結點
        }
        n3=n1;//保留最後的結點
        n2=head;//保留第一個結點
        boolean res=true;
        while (n1!=null&&n2!=null){
            if(n1.value!=n2.value){
                res=false;
                break;
            }
            n1=n1.next;
            n2=n2.next;
        }
        n1=n3.next;
        n3.next=null;
        while(n1!=null){//後半部分反轉回來
            n2=n1.next;//保留下一個結點
            n1.next=n3;//下個結點指向當前結點
            n3=n1;//下個結點設置爲當前結點
            n1=n2;//當前結點設置爲下個結點
        }
        return res;
    }
    public static void main(String[] args) {
        Node n=new Node(1);
        n.next=new Node(2);
        n.next.next=new Node(3);
        System.out.println(isHuiWen3(n));
    }
}

 將單向鏈表按某值劃分紅左邊小、中間相等、右邊大的形式 

給定一個單向鏈表的頭節點head,節點的值類型是整型,再給定一個 整 數pivot。實現一個調整鏈表的函數,將鏈表調整爲左部分都是值小於 pivot 的節點,中間部分都是值等於pivot的節點,右部分都是值大於 pivot的節點。在左、中、右三個部分的內部也作順序要求,要求每部分裏的節點從左 到右的 順序與原鏈表中節點的前後次序一致。

例如:鏈表9->0->4->5->1,pivot=3。 調整後的鏈表是0->1->9->4->5。 在知足原問題要求的同時,左部分節點從左到 右爲0、1。在原鏈表中也 是先出現0,後出現1;中間部分在本例中爲空,再也不 討論;右部分節點 從左到右爲九、四、5。在原鏈表中也是先出現9,而後出現4, 最後出現5。

若是鏈表長度爲N,時間複雜度請達到O(N),額外空間複雜度請達到O(1)。

 

public class HeLanGQ {
    public static class Node {
        public int value;
        public Node next;
        public Node(int data) {
            this.value = data;
        }
    }
    //方法1
    //遍歷鏈表,把鏈表的結點存進數組,對數組操做,而後再拼成鏈表返回
    public static Node listPartition1(Node head, int pivot) {
        if (head == null) {
            return head;
        }
        Node cur = head;
        int i = 0;
        while (cur != null) {
            i++;
            cur = cur.next;
        }
        Node[] nodeArr = new Node[i];
        i = 0;
        cur = head;
        for (i = 0; i != nodeArr.length; i++) {
            nodeArr[i] = cur;
            cur = cur.next;
        }
        arrPartition(nodeArr, pivot);
        for (i = 1; i != nodeArr.length; i++) {
            nodeArr[i - 1].next = nodeArr[i];
        }
        nodeArr[i - 1].next = null;
        return nodeArr[0];
    }

    public static void arrPartition(Node[] nodeArr, int pivot) {
        int small = -1;
        int big = nodeArr.length;
        int index = 0;
        while (index != big) {
            if (nodeArr[index].value < pivot) {
                swap(nodeArr, ++small, index++);
            } else if (nodeArr[index].value == pivot) {
                index++;
            } else {
                swap(nodeArr, --big, index);
            }
        }
    }

    public static void swap(Node[] nodeArr, int a, int b) {
        Node tmp = nodeArr[a];
        nodeArr[a] = nodeArr[b];
        nodeArr[b] = tmp;
    }
    //方法2
    //把鏈表分紅三個小鏈表,小的放第一個,相等放第二個,大的放最後,每一個鏈表記錄頭和尾,後面進行拼接。
    public static Node listPartition2(Node head, int pivot) {
        Node sH = null; // small head
        Node sT = null; // small tail
        Node eH = null; // equal head
        Node eT = null; // equal tail
        Node bH = null; // big head
        Node bT = null; // big tail
        Node next = null; // save next node
        // every node distributed to three lists
        while (head != null) {
            next = head.next;
            head.next = null;
            if (head.value < pivot) {
                if (sH == null) {
                    sH = head;
                    sT = head;
                } else {
                    sT.next = head;
                    sT = head;
                }
            } else if (head.value == pivot) {
                if (eH == null) {
                    eH = head;
                    eT = head;
                } else {
                    eT.next = head;
                    eT = head;
                }
            } else {
                if (bH == null) {
                    bH = head;
                    bT = head;
                } else {
                    bT.next = head;
                    bT = head;
                }
            }
            head = next;
        }
        // small and equal reconnect
        if (sT != null) {
            sT.next = eH;//小鏈表尾指向中鏈表頭
            eT = eT == null ? bH : eT;//判斷中鏈表是否爲空
        }
        // all reconnect
        if (eT != null) {
            eT.next = bH;//中鏈表尾指向大鏈表頭
        }
        return sH != null ? sH : eH != null ? eH : bH;
    }

    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 head1 = new Node(7);
        head1.next = new Node(3);
        head1.next.next = new Node(1);
        head1.next.next.next = new Node(8);
        head1.next.next.next.next = new Node(5);
        head1.next.next.next.next.next = new Node(5);
        head1.next.next.next.next.next.next = new Node(9);
        printLinkedList(head1);
        //head1 = listPartition1(head1, 5);
        head1 = listPartition2(head1, 5);
        printLinkedList(head1);

    }
}

 複製含有隨機指針節點的鏈表 

一種特殊的鏈表節點類描述以下:

public class Node {

public int value;

public Node next;

public Node rand;

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

}

Node類中的value是節點值,next指針和正常單鏈表中next指針的意義 一 樣,都指向下一個節點,rand指針是Node類中新增的指針,這個指 針可 能指向鏈表中的任意一個節點,也可能指向null。 給定一個由 Node節點類型組成的無環單鏈表的頭節點head,請實現一個 函數完成 這個鏈表中全部結構的複製,並返回複製的新鏈表的頭節點。 進階: 不使用額外的數據結構,只用有限幾個變量,且在時間複雜度爲 O(N) 內完成原問題要實現的函數。

方法1:藉助輔助空間

    public static Node copyListWithRand1(Node head){
        HashMap<Node,Node> map=new HashMap<Node,Node>();
        Node cur=head;
        while (cur!=null){
            map.put(cur,new Node(cur.value));
            cur=cur.next;
        }
        cur=head;
        while(cur!=null){
            map.get(cur.value).next=map.get(cur.next);
            map.get(cur.value).rand=map.get(cur.rand);
            cur=cur.next;
        }
        return map.get(head);
    }

方法2:不借助輔助空間

    public static Node copyListWithRand2(Node head) {
        if (head == null) {
            return null;
        }
        Node cur = head;
        Node next = null;
        // copy node and link to every node
        while (cur != null) {
            next = cur.next;
            cur.next = new Node(cur.value);
            cur.next.next = next;
            cur = next;
        }
        cur = head;
        Node curCopy = null;
        // set copy node rand
        while (cur != null) {
            next = cur.next.next;
            curCopy = cur.next;
            curCopy.rand = cur.rand != null ? cur.rand.next : null;
            cur = next;
        }
        Node res = head.next;
        cur = head;
        // split
        while (cur != null) {
            next = cur.next.next;
            curCopy = cur.next;
            cur.next = next;
            curCopy.next = next != null ? next.next : null;
            cur = next;
        }
        return res;
    }

 兩個單鏈表相交的一系列問題

在本題中,單鏈表可能有環,也可能無環。給定兩個 單鏈表的頭節點 head1和head2,這兩個鏈表可能相交,也可能 不相交。請實現一個函數, 若是兩個鏈表相交,請返回相交的 第一個節點;若是不相交,返回null 便可。

要求:若是鏈表1 的長度爲N,鏈表2的長度爲M,時間複雜度請達到 O(N+M),額外 空間複雜度請達到O(1)。

    //主要方法
    public static Node getIntersectNode(Node head1, Node head2) {
        if (head1 == null || head2 == null) {
            return null;
        }
        Node loop1 = getLoopNode(head1);//判斷鏈表是否有環
        Node loop2 = getLoopNode(head2);//判斷鏈表是否有環
        if (loop1 == null && loop2 == null) {//兩個鏈表都無環
            return noLoop(head1, head2);
        }
        if (loop1 != null && loop2 != null) {//兩個鏈表都有環
            return bothLoop(head1, loop1, head2, loop2);
        }
        return null;
    }
    //定義快慢指針,當兩個指針相遇時,快指針回到原點,快指針變爲慢指針,再次相遇時,即爲第一次相遇點
    public static Node getLoopNode(Node head) {
        if (head == null || head.next == null || head.next.next == null) {
            return null;
        }
        Node n1 = head.next; // n1 -> slow
        Node n2 = head.next.next; // n2 -> fast
        while (n1 != n2) {
            if (n2.next == null || n2.next.next == null) {
                return null;
            }
            n2 = n2.next.next;
            n1 = n1.next;
        }
        n2 = head; // n2 -> walk again from head
        while (n1 != n2) {
            n1 = n1.next;
            n2 = n2.next;
        }
        return n1;
    }
    public static Node noLoop(Node head1, Node head2) {
        if (head1 == null || head2 == null) {
            return null;
        }
        Node cur1 = head1;
        Node cur2 = head2;
        int n = 0;//記錄兩個鏈表的長度差值
        while (cur1.next != null) {
            n++;
            cur1 = cur1.next;
        }
        while (cur2.next != null) {
            n--;
            cur2 = cur2.next;
        }
        //最後一個結點不相等,不可能相交
        if (cur1 != cur2) {
            return null;
        }
        cur1 = n > 0 ? head1 : head2;
        cur2 = cur1 == head1 ? head2 : head1;
        n = Math.abs(n);
        while (n != 0) {
            n--;
            cur1 = cur1.next;
        }
        while (cur1 != cur2) {
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }
    //兩種狀況
    public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
        Node cur1 = null;
        Node cur2 = null;
        if (loop1 == loop2) {
            cur1 = head1;
            cur2 = head2;
            int n = 0;
            while (cur1 != loop1) {
                n++;
                cur1 = cur1.next;
            }
            while (cur2 != loop2) {
                n--;
                cur2 = cur2.next;
            }
            cur1 = n > 0 ? head1 : head2;
            cur2 = cur1 == head1 ? head2 : head1;
            n = Math.abs(n);
            while (n != 0) {
                n--;
                cur1 = cur1.next;
            }
            while (cur1 != cur2) {
                cur1 = cur1.next;
                cur2 = cur2.next;
            }
            return cur1;
        } else {
            cur1 = loop1.next;
            while (cur1 != loop1) {
                if (cur1 == loop2) {
                    return loop1;
                }
                cur1 = cur1.next;
            }
            return null;
        }
    }
相關文章
相關標籤/搜索