左神笔记基础-题型整理

题目一:用数组结构实现大小固定的队列和栈

实现栈:栈是先进后出;准备一个index,想加进去一个数,index就是指要把这个数加到哪个位置上去,加进去一个就Index++;

若需要弹出一个数,弹出,就index--

package zuoshen;

public class Array_To_Stack_Queue {
    public static class ArrayStack{
        private Integer[]arr;
        private Integer index;

        public ArrayStack(int initSize){
            if(initSize<0){
                throw new IllegalArgumentException("The init size is less than 0");
            }
            arr=new Integer[initSize];
            index=0;
        }
        public Integer peek(){//栈顶元素
            if(index==0){
                return null;
            }
            return arr[index-1];//因为index指的是新来一个数要放的位置,而Peek()的位置在index下一个,所以index-1
        }
        public void push(int obj){
            if(index==arr.length){
                throw new ArrayIndexOutOfBoundsException("The stack is full");
            }
            arr[index++]=obj;
        }
        public Integer pull(){
            if(index==0){
                throw new ArrayIndexOutOfBoundsException("The stack is empty");
            }
            return arr[--index];
        }
    }
}

实现队列:队列是先进先出;start代表队列的头,end代表队列尾,size作为约束,数组循环使用;

每次加进去一个数,end向下移一位,end代表加进来的数放在哪里,end到最下边的时候,回到开头位置;

每次拿走一个数,拿走之后start向下移一位,准备下一次的时候申请拿数时候拿的位置,start到最下边的时候,回到开头位置;

因为两个数比较难互相约束,因为引进一个变量size:

当size不超过数组大小的时候,end正常使用;

当size不是0的时候,start正常使用;

public static class ArrayQueue{
        private Integer []arr;
        private Integer start;
        private Integer end;
        private Integer size;

        public ArrayQueue(int initSize){//因为是固定数组,最开始就固定下来的,所以要定义一个initSize
            if(initSize<0){
                throw new IllegalArgumentException("The init size is less than 0");
            }
            arr =new Integer[initSize];
            size=0;
            start=0;
            end=0;
        }
        public Integer peek(){
            if(size==0){
                return null;
            }
            return arr[start];
        }
        public void push(int obj){
            if(size==arr.length){
                throw new ArrayIndexOutOfBoundsException("The Queue is full");
            }
            size ++;
            arr[end]=obj;
            end=nextIndex(arr.length,end);
        }
        public Integer poll(){
            if(size==0){
                throw new ArrayIndexOutOfBoundsException("The Queue is empty");
            }
            size--;
            int tmp=arr[start];
            start=nextIndex(arr.length,start);
            return arr[tmp];
        }

        private Integer nextIndex(int size, Integer index) {
            return index==size-1? 0:index+1;//如果已经到了最后一个位置了,跳回到0,如果没有的话就往下+1
            //相当于:end=end==arr.length-1?0:end+1; start=start==arr.length-1?0:start+1;
        }
    }

 题目二:实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返 回栈中最小元素的操作。 

【要求】 1.pop、push、getMin操作的时间复杂度都是O(1)。 2.设计的栈类型可以使用现成的栈结构。

分析:用两个栈,一个栈存进来的数,一个栈保持最小数在栈顶

package zuoshen;

import java.util.Stack;

public class GetMinClass1 {
    public static class MyStack1{
        private Stack<Integer>stackData;
        private Stack<Integer>stackMin;

        public MyStack1(){
            this.stackData=new Stack<Integer>();
            this.stackMin=new Stack<Integer>();
        }
        public void push(int newNums){
            if(stackMin.isEmpty()){//栈为空,压入
                this.stackMin.push(newNums);
            }else if(newNums<this.getmin()){//栈不空,新进来的数比栈顶的小,压入
                this.stackMin.push(newNums);
            }else {//栈不空,新进来的数比栈顶的大,重复压入栈顶元素
                int newMin=this.stackMin.peek();
                this.stackMin.push(newMin);
            }
        }
        public Integer pop(){
            if(stackMin.isEmpty()){//栈空,报错
                throw new IllegalArgumentException("The stackMin is empty");
            }
            //这里没有什么逻辑操作,你弹我也弹????????????????????????????
            this.stackMin.pop();
            return this.stackData.pop();

        }
        private int getmin() {
            if(this.stackMin.isEmpty()){
                throw new IllegalArgumentException("The stackMin is empty");
            }
            return this.stackMin.peek();
        }
    }
}

题目三:如何仅用队列结构实现栈结构? 如何仅用栈结构实现队列结构?

分析:

1.队列--栈:

图的深度优先遍历必须使用栈,那么怎么用队列来实现优先遍历呢,就需要用队列实现栈结构,可以用两个队列来实现栈,再去实现优先遍历,栈结构先进后出:让1234进到另外一个队列中,留着最后一个,把最后一个返回给用户;进的时候都进data栈,出的时候就除了最后一个都进到help栈中,然后换一下data和help的引用

 

package zuoshen;

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

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

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

        // 使用两个队列来回倒,每次倒的时候留队列尾部最后一个元素,然后pop()这个元素
        public void push(int pushInt){//新的数放到queue中
            queue.add(pushInt);
        }
        public int peek(){//queue 队列的元素进入 help 队列,只留一个
            if (queue.isEmpty()) {
                throw new RuntimeException("Stack is empty!");
            }
            while(queue.size() !=1){
                help.add(queue.poll());
            }
            int res=queue.poll();
            help.add(res);
            swap();
            return res;
        }
        public int pop(){ // queue 队列的元素进入 help 队列,只留一个
            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() {//help和queue交换一下
            Queue<Integer> tmp = help;
            help = queue;
            queue = tmp;
        }
    }
}

2.栈--队列:

两个栈实现一个队列 ,用户要数的时候都是从pop栈里拿,压入都是压入push栈,

导的行为有两个限制:

1)如果push栈要往pop栈里边倒,一次必须倒完,

2)如果pop栈里边有东西,那push栈不要倒

 这时候不能倒:pop中有数据的时候,不能倒,

public static class TwoStackQueue{
        private Stack<Integer> push;
        private Stack<Integer> pop;
        public TwoStackQueue() {
            push = new Stack<Integer>();
            pop = new Stack<Integer>();
        }
        public void push(int pushInt){
            push.push(pushInt);
        }
        public int poll() {
            if (pop.empty() && push.empty()) {
                throw new RuntimeException("Queue is empty!");
            } else if (pop.empty()) {
                while (!push.empty()) {
                    pop.push(push.pop());
                }
            }
            return pop.pop();
        }
        public int peek() {
            if (pop.empty() && push.empty()) {
                throw new RuntimeException("Queue is empty!");
            } else if (pop.empty()) {
                while (!push.empty()) {
                    pop.push(push.pop());
                }
            }
            return pop.peek();
        }
    }

 题目四:猫狗队列

猫狗队列  【题目】 宠物、狗和猫的类如下:

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

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

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

        public DogCatQueue1() {
            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) {
        DogCatQueue1 test = new DogCatQueue1();

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

public class PrintMatrixSpiralOrder {
    public static void spiralOrderPrint(int[][]matrix){
        //左上角
        int tr=0,tc=0;
        //右下角
        int dr=matrix.length-1,dc=matrix[0].length-1;
        while(tr<=dr&&tc<=dc){
            printEdge(matrix,tr++,tc++,dr--,dc--);
        }
    }

    private 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 curr=tr;//行
            int curc=tc;//列
            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][tr]+" ");
                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)

package zuoshen;

public class RotateMatrix {//这是一个正方形的矩阵
    public static void rotate(int[][]matrix){
        int lx=0, ly=0;
        int rx=matrix.length-1,ry=matrix[0].length-1;
        while(lx<=rx&&ly<=ry){
            printMatrixEdge(matrix,lx++,ly++,rx--,ry--);
        }
    }

    private static void printMatrixEdge(int[][] m, int lx, int ly, int rx, int ry) {
        int time=rx-lx;
        int tmp=0;
        //这里的重点是,一定要考虑好i的值
        //第一次:i=0:1->4>16->13>1
        //第二次:i=2:2 8 15 9
        //第三次:i=3:结束
        for (int i = 0; i!=time ; i++) {
            tmp=m[lx][ly+i];//1
            m[lx][ly+i]=m[rx-i][ly];//13->1
            m[rx-i][ly]=m[rx][ry-i];//16->13
            m[rx][ry-i]=m[lx+i][ry];//4->16
            m[lx+i][ry]=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)

 笔记:(来自百度百科的解释)

单向链表单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;

链表是由结点构成,head指针指向第一个成为表头结点,而终止于最后一个指向NULL的指针。

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

package zuoshen;

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 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)。

分析:不能局限在局部结构怎么变,要考虑宏观结构。

设置一个AB点,A:每次往右走一步,到头了就往下;B:每次往右走一步,到头了就往右;AB总是形成一条对角线,打印这个对角线,用一个boolean类型的值来决定从上往下打印还是从下往上打印。

package zuoshen;

public class ZigZagPrintMatrix {
    public static void printMatrixZigZag(int[][]matrix){
        //A开始点
        int AR=0;
        int AC=0;
        //B开始点
        int BR=0;
        int BC=0;
        //终止条件
        int endR=matrix.length-1;
        int endC=matrix[0].length-1;
        boolean fromA=false;

        while(AR!=endR+1){//循环的终止条件,表示A来到了最后一行,说明A已经到了最右,又跑到最下了。这和B来到最下又跑到最后是一样的道理,写哪个都行
            printlevel(matrix,AR,AC,BR,BC,fromA);
            AR=AC==endC?AR+1:AR;//A到最右了吗?到了的话,A就开始往下,行+1
            AC=AC==endC?AC:AC+1;//A到最下了吗?到了的话,A就不再往下了,没到的话,A就继续往下,列+1
            BC=BR==endR?BC+1:BC;//B到最下了吗?到了的话,A就开始往右,列+1
            BR=BR==endR?BR:BR+1;//B到最右了吗?到了的话,B就不再往右了,没到的话,B就继续往右,行+1
            fromA=!fromA;
        }
        System.out.println();
    }

    private static void printlevel(int[][] matrix, int ar, int ac, int br, int bc, boolean fromA) {
        if(fromA){//从上往下fromA=true
            while(ar !=br+1){
                System.out.print(matrix[ar++][ac--]+" ");
            }
        }else {//从下往上fromA=false
            while (bc !=ac+1){
                System.out.print(matrix[br--][bc++]+" ");
            }
        }
    }
    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 zuoshen;

public class FindNumInSortedMatrix {
    public static boolean FindNumInSortedMatrix(int[][] matrix, int k){
        int i=0;
        int j=matrix[0].length-1;
        while(i<matrix.length && j>-1){
            if(matrix[i][j]==k){
                return true;
            }else if(matrix[i][j]>k){
                j--;
            }else {
                i++;
            }
        }
        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(FindNumInSortedMatrix(matrix, K));
    }
    }

题目十:打印两个有序链表的公共部分

【题目】 给定两个有序链表的头指针head1和head2,打印两个链表的公共部分。

package zuoshen;

public class 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);

    }
}

题目十一:判断一个链表是否为回文结构

【题目】 给定一个链表的头节点head,请判断该链表是否为回文结构。

例如: 1->2->1,返回true。 1->2->2->1,返回true。 15->6->15,返回true。 1->2->3,返回false。
进阶: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。

package zuoshen;

import java.util.Stack;

public class 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) {//当快指针走到头了,刚好慢指针走到中间,while结束,跳出循环
            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("=========================");

    }

}

题目十二:将单向链表按某值划分成左边小、中间相等、右边大的形式

【题目】 给定一个单向链表的头节点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的节点即可。对某部分内部的节点顺序不做 要求。
进阶: 在原问题的要求之上再增加如下两个要求。 在左、中、右三个部分的内部也做顺序要求,要求每部分里的节点从左 到右的 顺序与原链表中节点的先后次序一致。 例如:链表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)。

分析:荷兰国旗问题做不到稳定性,可以选择链表,准备三个链表less,equal,large,然后把三个连在一起。

package zuoshen;

public class Code_12_SmallerEqualBigger {
    public static class Node{
        public int value;
        public Node next;
        public Node(int data){
            this.value=data;
        }
    }
    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;
    }
    //优化:时间复杂度o(N),额外空间o(1)
    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 ? sT : 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(9);
        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(2);
        head1.next.next.next.next.next.next = new Node(5);
        printLinkedList(head1);
        // head1 = listPartition1(head1, 4);
        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) 内完成原问题要实现的函数。

package zuoshen;

import java.util.HashMap;
import java.util.Map;

public class Code_13_CopyListWithRandom {
    public static class Node{
        public int value;
        public Node next;
        public Node rand;
        public Node(int data){
            this.value=data;
        }
    }
    //用哈希表来存
    public static Node copyListWithRand1(Node head){
        Map<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).next=map.get(cur.next);
            map.get(cur).rand=map.get(cur.rand);
            cur=cur.next;
        }
        return map.get(head);
    }
    public static Node copyListWithRand2(Node head){
        if(head==null){
            return null;
        }
        Node cur=head;//当前节点
        Node next=null;//下一个

        // copy node and link to every node:1->2->3
        while (cur !=null){//若当前节点不空
            next=cur.next;//下一个->当前的下一个2
            cur.next=new Node(cur.value);//当前的下一个->当前的值1->1'
            cur.next.next=next;//当前的下一个的下一个->当前的下一个1'->2
            cur=next;//当前->2
            //1->1'->2->2'->3->3'
        }
        cur=head;//当前回到头
        Node curCopy=null;//copy的数组当前值
        // set copy node rand
        while(cur!=null){
            next=cur.next.next;//2'
            curCopy=cur.next;//copy当前值->1'
            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;
    }
    public static void printRandLinkedList(Node head){//打印用的
        Node cur=head;
        System.out.print("order: ");
        while (cur !=null){
            System.out.print(cur.value+" ");
            cur=cur.next;
        }
        System.out.println();
        cur=head;
        System.out.print("Rand: ");
        while (cur!=null){
            System.out.print(cur.rand == null ? "- " : cur.rand.value + " ");
            cur=cur.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Node head=null;
        Node res1=null;
        Node res2=null;
        printRandLinkedList(head);
        res1=copyListWithRand1(head);
        printRandLinkedList(res1);
        res2=copyListWithRand2(head);
        printRandLinkedList(res2);
        printRandLinkedList(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(4);
        head.next.next.next.next = new Node(5);
        head.next.next.next.next.next = new Node(6);

        head.rand = head.next.next.next.next.next; // 1 -> 6
        head.next.rand = head.next.next.next.next.next; // 2 -> 6
        head.next.next.rand = head.next.next.next.next; // 3 -> 5
        head.next.next.next.rand = head.next.next; // 4 -> 3
        head.next.next.next.next.rand = null; // 5 -> null
        head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4

        printRandLinkedList(head);
        res1 = copyListWithRand1(head);
        printRandLinkedList(res1);
        res2 = copyListWithRand2(head);
        printRandLinkedList(res2);
        printRandLinkedList(head);
        System.out.println("=========================");
    }
}

题目十四:两个单链表相交的一系列问题

【题目】 在本题中,单链表可能有环,也可能无环。给定两个 单链表的头节点 head1和head2,这两个链表可能相交,也可能 不相交。请实现一个函数, 如果两个链表相交,请返回相交的 第一个节点;如果不相交,返回null 即可。 要求:如果链表1 的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外 空间复杂度请达到O(1)。

分析:相交指的是内存地址,不是值,和值没有关系

1.怎么判断一个单链表有环还是无环:用hash表,从Head开始遍历,next开始入map,每次进的时候查一下存不存在,若不存在,放进去,存在----》有环;

2.不用hash表的话:准备两个指针,一个快指针(两步),一个慢指针(一步),若相遇,有环,指向Null,无环

相遇时候,快指针回到开头,然后快指针由一次走两步变成一次走一步,这样快慢指针一定会在第一个入环出相遇

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值