zoukankan      html  css  js  c++  java
  • 算法基础(四)

    队列例子

    猫狗队列

    宠物、狗和猫的类如下:

    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类的实例。

    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;中间部分在本例中为空,不再 讨论;右部分节点 从左到右为9、4、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;
            }
        }
  • 相关阅读:
    mysql设置定时任务
    Spark On Yarn:提交Spark应用程序到Yarn
    Spark On Yarn:提交Spark应用程序到Yarn
    在Yarn上运行spark-shell和spark-sql命令行
    在Yarn上运行spark-shell和spark-sql命令行
    SparkSQL On Yarn with Hive,操作和访问Hive表
    SparkSQL On Yarn with Hive,操作和访问Hive表
    使用hive访问elasticsearch的数据
    使用hive访问elasticsearch的数据
    redis数据类型之list
  • 原文地址:https://www.cnblogs.com/huozhonghun/p/10740200.html
Copyright © 2011-2022 走看看