算法初级(二)—— 数组、栈、队列、链表相关题目

文章目录

      • 1、数组与栈和队列之间的转换
      • 2、栈与队列的转换
      • 3、猫狗队列
      • 4、打印旋转90°后的数组
      • 5、转圈打印
      • 6、单链表和双链表转置
      • 7、之字形打印
      • 8、在一个行列排好序的数组中找数
      • 9、打印两链表公共部分
      • 10、判断一个链表是否为回文结构

1、数组与栈和队列之间的转换

将数组转换成栈及其一些基本操作

public static class ArrayStack {
        private Integer[] arr;
        private Integer size;

        public ArrayStack(Integer initSize) {
            if (initSize < 0) {
                throw new IllegalArgumentException("The init size is less than 0");
            }
            arr = new Integer[initSize];
            size = 0;
        }

        //取栈顶元素
        public Integer peek() {
            if (size == 0) {
                return null;
            }
            return arr[size - 1];
        }

        //入栈
        public void push(int obj) {
            if (size == arr.length) {
                throw new ArrayIndexOutOfBoundsException("The stack is full");
            }
            arr[size++] = obj;
        }

        //出栈
        public Integer pop() {
            if (size == 0) {
                throw new ArrayIndexOutOfBoundsException("The stack is null");
            }
            return arr[--size];
        }
    }

数组转换成队列

public static class ArrayQueue {
        private Integer[] arr;
        private Integer size;
        private Integer first;
        private Integer last;

        private ArrayQueue(int initSize) {
            if (initSize < 0) {
                throw new IllegalArgumentException("The init size is less than 0");
            }
            arr = new Integer[initSize];
            size = 0;
            first = 0;
            last = 0;
        }

        public Integer peek() {
            if (size == 0) {
                return null;
            }
            return arr[first];
        }
        public void push(int obj) {
            if (size == arr.length) {
                throw new ArrayIndexOutOfBoundsException("The queue is full");
            }
            size ++;
            arr[last] = obj;
            //到达队列尾部的处理
            last = last == arr.length - 1 ? 0 : last + 1;
        }

        public Integer poll() {
            if (size == 0) {
                throw new ArrayIndexOutOfBoundsException("The queue is empty");
            }
            size --;
            int tmp = first;
            //到达队列头部的处理
            first = first == arr.length - 1 ? 0 : first + 1;
            return arr[tmp];
        }
    }

2、栈与队列的转换

两个栈转换成一个队列

public static class TwoStacksToQueue {
        private Stack<Integer> stackPush;
        private Stack<Integer> stackPop;

        public TwoStacksToQueue() {
            stackPush = new Stack<>();
            stackPop = new Stack<>();
        }

        public void push(int pushInt) {
            stackPush.push(pushInt);
        }

        public int poll() {
            if (stackPop.empty() && stackPush.empty()) {
                throw new RuntimeException("Queue is empty!");
            } else if (stackPop.empty()) {
                while (! stackPush.empty()) {
                    stackPop.push(stackPush.pop());
                }
            }
            return stackPop.pop();
        }

        public int peek() {
            if (stackPop.empty() && stackPush.empty()) {
                throw new RuntimeException("Queue is empty!");
            } else if (stackPop.empty()) {
                while (! stackPush.empty()) {
                    stackPop.push(stackPush.pop());
                }
            }
            return stackPop.peek();
        }
    }

两个队列转换成栈

public static class TwoQueuesToStack {
        private Queue<Integer> queue;
        private Queue<Integer> help;

        public TwoQueuesToStack() {
            queue = new LinkedList<>();
            help = new LinkedList<>();
        }

        public void push(int pustInt) {
            queue.add(pustInt);
        }

        public int peek() {
            if (queue.isEmpty()) {
                throw new RuntimeException("Stack is empty!");
            }
            //将队列中的除最后一个元素外,全部放入help中
            while (queue.size() != 1) {
                help.add(queue.poll());
            }
            //取出queue的最后一个元素
            int res = queue.poll();
            help.add(res);
            //将queue与help交换
            swap();
            return res;
        }

        public int pop() {
            if (queue.isEmpty()) {
                throw new RuntimeException("Stack is empty!");
            }
            while (queue.size() > 1) {
                help.add(queue.poll());
            }
            int res = queue.poll();
            swap();
            return res;
        }

        private void swap() {
            Queue<Integer> tmp = help;
            help = queue;
            queue = tmp;
        }
    }

3、猫狗队列

1.定义Pet类,Dog Cat继承Pet类

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");
        }
    }

2.pet入的队列

    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;
        }

		//获取pet类型
        public String getEnterPetType() {
            return this.pet.getPetType();
        }
    }

//dog cat队列

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;
        }

		//当有pet入时,判断类型,对号入座
        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!");
            }
        }

		//将Dog中的所有实例按照顺序出
        public Dog pollDog() {
            if (!this.isDogQueueEmpty()) {
                return (Dog) this.dogQ.poll().getPet();
            } else {
                throw new RuntimeException("Dog queue is empty!");
            }
        }

		////将Cat中的所有实例按照顺序出
        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();
        }

    }

4、打印旋转90°后的数组

方法一:抠边界
算法初级(二)—— 数组、栈、队列、链表相关题目_第1张图片

//数组旋转90度
    public static void rotate(int[][] matrix) {
        //数组左上角坐标(a,b)右下角坐标(c,d)
        int a = 0;
        int b = 0;
        int c = matrix.length - 1;
        int d = matrix[0].length - 1;
        //分圈打印
        while (a < c) {
            rotateEdge(matrix, a++, b++, c--, d--);
        }
    }

    public static void rotateEdge(int[][] matrix, int a, int b, int c, int d) {
        int times = d - b;
        int tmp = 0;
        //坐标对应关系
        for (int i = 0; i != times; i ++) {
            tmp = matrix[a][b+i];
            matrix[a][b+i] = matrix[c-i][b];
            matrix[c-i][b] = matrix[c][d-i];
            matrix[c][d-i] = matrix[a+i][d];
            matrix[a+i][d] = tmp;
        }
    }

方法二:找坐标对应关系

//(正方形)矩阵顺时针旋转90度
    //原纵坐标=新横坐标
    //原横坐标+新纵坐标=列数(行数)-1
    public static int[][] rotate(int [][]matrix) {
        int[][] temp = new int[matrix[0].length][matrix.length];
        int row = matrix.length - 1;
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                temp[j][row - i] = matrix[i][j];
            }
        }
        return temp;
    }

    public static void main(String[]args){
        int [][]matrix={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
        int [][]temp=rotate(matrix);
        for(int i=0;i<temp.length;i++){
            for(int j=0;j<temp[0].length;j++){
                System.out.print(temp[i][j]+"\t");
            }
            System.out.println();
        }
    }

5、转圈打印

算法初级(二)—— 数组、栈、队列、链表相关题目_第2张图片

public static void spiralOrderPrint(int[][] matrix) {
        int a = 0;
        int b = 0;
        int c = matrix.length - 1;
        int d = matrix[0].length - 1;
        while (a <= c && b <= d) {
            printEdge(matrix, a++, b++, c--, d--);
        }    }

    public static void printEdge(int[][] m, int a, int b, int c, int d) {
        //只有一列
        if (a == c) {
            for (int i = 0; i < d; i ++) {
                System.out.print(m[a][i] + " ");
            }
        } else if (b == d) {//只有一行
            for (int i = 0; i < c; i ++) {
                System.out.print(m[i][b] + " ");
            }
        } else {
            //矩形数组
            int curRow = a;
            int curCol = b;
            //此处参考上图
            while (curCol != d) {
                System.out.print(m[a][curCol++] + " ");
            }
            while (curRow != c) {
                System.out.print(m[curRow++][d] + " ");
            }
            while (curCol != b) {
                System.out.print(m[c][curCol--] + " ");
            }
            while (curRow != a) {
                System.out.print(m[curRow--][b] + " ");
            }
        }
    }
    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);//1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 
    }

6、单链表和双链表转置

算法初级(二)—— 数组、栈、队列、链表相关题目_第3张图片

//单链表
public static class Node {
        int value;
        Node next;

        public Node(int value) {
            this.value = value;
        }
    }
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 {
        int value;
        DoubleNode last;
        DoubleNode next;

        public DoubleNode(int value) {
            this.value = value;
        }
    }
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;
    }

7、之字形打印

算法初级(二)—— 数组、栈、队列、链表相关题目_第4张图片

    public static void printZigZagMatrix(int[][] matrix) {
        //标记初始打印点的位置。
        int aR = 0;
        int aC = 0;
        int bR = 0;
        int bC = 0;
        int endR = matrix.length - 1;
        int endC = matrix[0].length - 1;
        boolean flag = false;//判断斜向上打印还是斜向下打印
        while (aR != endR + 1) {
            printNum(matrix, aR, aC, bR, bC, flag);
            //先判断列再判断行,否则会出现打印错误
            aR = aC == endC ? aR + 1 : aR;//判断a是否到达最后一列,如果到达,则a向下,aR+1
            aC = aC == endC ? aC : aC + 1;//如果没有到达,则a向右,aC+1
            bC = bR == endR ? bC + 1 : bC;
            bR = bR == endR ? bR : bR + 1;
            flag = !flag;
        }
        System.out.println();

    }

    public static void printNum(int[][] m, int aR, int aC, int bR,
                                int bC, boolean flag) {
        if (flag) { //从右上到左下
            while (aR != bR + 1) {
                System.out.print(m[aR++][aC--] + " ");
            }
        } else {
            while (bR != aR - 1) {
                System.out.print(m[bR--][bC++] + " ");
            }
        }
    }
    public static void main(String[] args) {
        int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, {13, 14, 15, 16} };
        printMatrixZigZag(matrix);//1 2 5 9 6 3 4 7 10 13 14 11 8 12 15 16 
    }

8、在一个行列排好序的数组中找数

算法初级(二)—— 数组、栈、队列、链表相关题目_第5张图片

public static boolean isContains(int[][] matrix, int K) {
        int row = matrix.length - 1;//行号
        int col = matrix[0].length - 1;//列号
        while (row >= 0 && col >= 0) {
            if (matrix[row][col] == K) {
                return true;
            } else if (matrix[row][col] > K) {
                col--;//当前数大于K,向左移动
            } else {
                row--;//当前数小于K,向下移动
            }
        }
        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 = 101;
        System.out.println(isContains(matrix, K));
    }

9、打印两链表公共部分

public static class Node {
        int value;
        Node next;

        public Node(int value) {
            this.value = value;
        }
    }
    public static void printCommonPart(Node head1, Node head2) {
        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;
            }
        }
    }

10、判断一个链表是否为回文结构

  1. 辅助空间,复杂度O(n)
  2. 辅助空间,复杂度O(n/2)
  3. 不用辅助空间
    算法初级(二)—— 数组、栈、队列、链表相关题目_第6张图片
    public static class Node {
        int value;
        Node next;

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

    //1 额外空间O(n),利用栈
    public static boolean isPalindrome1(Node head) {
        Stack<Node> stack = new Stack<>();
        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;
    }

    //额外空间复杂度O(n/2)
    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<>();
        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;
    }

    //不用辅助空间
    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) {
            n1 = n1.next;//n1遍历到一半
            n2 = n2.next.next;//n2遍历完成
        }
        //以n2所指节点为头节点,反转链表
        n2 = n1.next;
        n1.next = null;
        Node n3 = null;
        while (n2 != null) {
            n3 = n2.next;
            n2.next = n1;
            n1 = n2;
            n2 = n3;
        }
        //两个指针分别指向链表两端,开始向中间遍历,并比较值是否相等
        n2 = head;//first
        n3 = n1;//last
        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 printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.value + " ");
            node = node.next;
        }
        System.out.println();
    }

你可能感兴趣的:(数据结构与算法)