牛客网修炼之路6(反转单链表,反转双链表,判断链表是不是回文链表)

1、反转单链表。

单链表结构如下图:

 牛客网修炼之路6(反转单链表,反转双链表,判断链表是不是回文链表)_第1张图片

反转的话,那么第一个将会变成最后一个节点。那么用一个front来记录反转子链的引用。一开始没有反转,所以,front=null

然后通过p = head.next,可以找到第一个节点。很明显,然后p.next = front,很明显这一步会把p的下一步信息给覆盖掉,因为还有p后面的数据,所以这里先用一个临时节点存起来。after= p.next;所以是先temp = p.next ,然后在p.next = front。做完这一步,很明显要把字链的第一个节点给存起来备用。所以front = p;同时p指向下一个节点。即p = after;然后重复上述的操作,知道p==null停。

package com.lizhi.java8;

public class TestNode {
   public static void main(String[] args) {
	   Node head = new Node();
	   
	   Node n1 = new Node();
	   n1.setData(1);
	   head.setNext(n1);
	   
	   Node n2 = new Node();
	   n2.setData(2);
	   n1.setNext(n2);
	   
	   Node n3 = new Node();
	   n3.setData(3);
	   n2.setNext(n3);
	   
	   Node n4 = new Node();
	   n4.setData(4);
	   n3.setNext(n4);
	    
	   Node p = head.getNext();
	   
	   while(p != null) {
		   System.out.println(p.getData());
		   p = p.getNext();
	   }
	   
	   reverse(head);
	   System.out.println("-----");
	   
       Node p1  = head.getNext();
	   
	   while(p1 != null) {
		   System.out.println(p1.getData());
		   p1 = p1.getNext();
	   }
   }
   
   //反转单链表
   public static void reverse(Node head) {
	   if(head == null || head.getNext() == null) {
		   return;
	   }
	   Node p = head.getNext();
	   Node front = null;
	   Node after = null;
	   while(p != null) {
		   //要记录其after,不然,当p.setNext后,会找不到原来下一位的节点
		   after = p.getNext();
		   p.setNext(front);
		   front = p;
		   p = after;
	   }
	   head.setNext(front);//将头节点只想反转后最前的节点
   }
}

2、双链表的反转和单链表一样,只不过循环中,多了一个设置pre的步骤。在结尾处,出来设置头结点,还有把第一个节点的上一个节点设置为头结点。

package com.lizhi.java8;

public class TestNode2 {
   public static void main(String[] args) {
	   Node2 head = new Node2();
	   
	   Node2 n1 = new Node2();
	   n1.setData(1);
	   n1.setPre(head);
	   head.setNext(n1);
	   
	   Node2 n2 = new Node2();
	   n2.setData(2);
	   n2.setPre(n1);
	   n1.setNext(n2);
	   
	   Node2 n3 = new Node2();
	   n3.setData(3);
	   n3.setPre(n2);
	   n2.setNext(n3);
	   
	   Node2 n4 = new Node2();
	   n4.setData(4);
	   n4.setPre(n3);
	   n3.setNext(n4);
	    
	   Node2 p = head.getNext();
	   
	   while(p != null) {
		   System.out.println(p.getData());
		   p = p.getNext();
	   }
	   
	   reverse(head);
	   System.out.println("-----");
	   
       Node2 p1  = head.getNext();
	   
	   while(p1 != null) {
		   System.out.println(p1.getData());
		   p1 = p1.getNext();
	   }
   }
   
   //反转双链表
   public static void reverse(Node2 head) {
	   if(head == null || head.getNext() == null) {
		   return;
	   }
	   Node2 p = head.getNext();
	   Node2 front = null;
	   Node2 after = null;
	   while(p != null) {
		   //要记录其after,不然,当p.setNext后,会找不到原来下一位的节点
		   after = p.getNext();
		   p.setNext(front);
		   p.setPre(after);//设置上一个节点。
		   front = p;
		   p = after;
	   }
	   head.setNext(front);//将头节点只想反转后最前的节点
	   front.setPre(head);//要设置pre
   }
}

3、判断链表是不是回文链表。

回文数是指正着和反着的顺序都是一样的。

比如12321,就是回文数。1221也是。正着读反着读都是一样的。

第一种方式如果对空间复杂度没有要求的话,可以使用栈来处理,就是遍历链表依次将节点传入压如栈中。

然后再便利一遍,同时将栈中的数据弹出,进行比较。如果全部比较完都一样,那么就是回文链表,否则不是。

时间复杂读O(n),空间复杂读O(n) 

package com.lizhi.java8;

import java.util.Stack;
/**
 * 随便写了一个例子
 * @author Admin
 *
 */
public class CircleNum {
   public static void main(String[] args) {
	   /**
	    * 1->2->2->1->null
	    */
	   Node head = new Node();
	   Node n1 = new Node();
	   n1.setData(1);
	   head.setNext(n1);
	   Node n2 = new Node();
	   n2.setData(2);
	   n1.setNext(n2);
	   Node n3 = new Node();
	   n3.setData(2);
	   n2.setNext(n3);
	   Node n4 = new Node();
	   n4.setData(1);
	   n3.setNext(n4);
	   
	   System.out.println( isCircleNum(head));
   }
   
   public static boolean isCircleNum(Node head) {
	   Stack stack = new Stack<>();
	   Node p = head;
	   //入栈过程
	   while(p.getNext() != null) {
		   stack.push(p.getNext());
		   p = p.getNext();
	   }
	  
	   //出栈比较
	   Node p1 = head;
	   while(p1.getNext() != null) {
		   p1 = p1.getNext();
		   if(p1.getData() != stack.pop().getData()) {
			   //只要有一个不想等,那么就返回false
			   return false;
		   }
	   }
	   return true;
   }
}

//这个是另外一个类,不在同一个文件中,因为同一个文件只能有一个公共类。
public class Node {
	private int data;
	private Node next;

	public int getData() {
		return data;
	}

	public void setData(int data) {
		this.data = data;
	}

	public Node getNext() {
		return next;
	}

	public void setNext(Node next) {
		this.next = next;
	}

}

第二种方式跟第一种的时间差不多,不过是对链表的后半部分入栈而已。举出下面例子。

牛客网修炼之路6(反转单链表,反转双链表,判断链表是不是回文链表)_第2张图片

那么这个是后面的3和2入栈。对于奇数的情况

牛客网修炼之路6(反转单链表,反转双链表,判断链表是不是回文链表)_第3张图片

那么是5,3,2入栈。那么如何才能找到上述的位置呢。

采用快指针和慢指针的方式。就是一个走两步,一个走一步。当快指针走到不能再走的时候,只需将慢指针移动一位便是需要的位置了。

代码如下,会有相应的注释。时间复杂读O(n),空间复杂读O(n),不过常数项都比较小。所以性能好点。

package com.lizhi.java8;

import java.util.Stack;
/**
 * 随便写了一个例子
 * @author Admin
 *
 */
public class CircleNum {
   public static void main(String[] args) {
	   /**
	    * 1->2->3->2->1->null
	    */
	   Node head = new Node();
	   Node n1 = new Node();
	   n1.setData(1);
	   head.setNext(n1);
	   Node n2 = new Node();
	   n2.setData(2);
	   n1.setNext(n2);
	   Node n3 = new Node();
	   n3.setData(3);
	   n2.setNext(n3);
	   Node n4 = new Node();
	   n4.setData(2);
	   n3.setNext(n4);
	   Node n5 = new Node();
	   n5.setData(1);
	   n4.setNext(n5);
	   
	   System.out.println( isCircleNum2(head));
   }
   
   public static boolean isCircleNum2(Node head) {
	   if(null == head.getNext()) {
		   //为空链表时返回false
		   return false;
	   }
	   if(null == head.getNext().getNext()) {
		   //只有一个元素的时候,返回true
		   return true;
	   }
	   //对应的栈
	   Stack stack = new Stack<>();
	   //快指针
	   Node fast = head;
	   //慢指针
	   Node slow = head;
	   //用于对比的指针
	   Node p1 = head;
	   //注意判断条件都是用fast,时间n/2
	   while(fast.getNext() != null && fast.getNext().getNext() != null) {
		   //快指针走两步
		   fast = fast.getNext().getNext();
		   //慢指针走一步
		   slow = slow.getNext();	
	   }
	   //循环结束只需将慢指针走一步便是,时间n/2,空间n/2
	   Node mid = slow.getNext();
	   while(mid != null) {
		  stack.push(mid);
		  mid = mid.getNext();
	   }
	   Node temp = stack.pop();
	   //时间n/2
	   while(temp != null) {
		   if(temp.getData() != p1.getNext().getData()) {
			   //只要有一个不相等,就返回false
			   return false;
		   }
		   p1 = p1.getNext();
		   if(!stack.isEmpty()) {
			   temp = stack.pop();
		   }else {
			   //栈为空的时候,循环条件结束
			   temp = null;
		   }
	   }
	   return true;
   }

第三种方法也是用到快指针和满指针的方式。不过这次是要把后半部分的指针转过来

牛客网修炼之路6(反转单链表,反转双链表,判断链表是不是回文链表)_第4张图片

偶数的情况:

牛客网修炼之路6(反转单链表,反转双链表,判断链表是不是回文链表)_第5张图片

public class CircleNum {
   public static void main(String[] args) {
	   /**
	    * 1->2->3->2->1->null
	    */
	   Node head = new Node();
	   Node n1 = new Node();
	   n1.setData(1);
	   head.setNext(n1);
	   Node n2 = new Node();
	   n2.setData(2);
	   n1.setNext(n2);
	   Node n3 = new Node();
	   n3.setData(1);
	   n2.setNext(n3);
	   Node n4 = new Node();
	   n4.setData(21);
	   n3.setNext(n4);
	   Node n5 = new Node();
	   n5.setData(1);
	   n4.setNext(n5);
	   
	   System.out.println( isCircleNum3(head));
   }
   
   public static boolean isCircleNum3(Node head) {
	   if(null == head.getNext()) {
		   //为空链表时返回false
		   return false;
	   }
	   if(null == head.getNext().getNext()) {
		   //只有一个元素的时候,返回true
		   return true;
	   }
	   Node fast = head;
	   Node slow = head;
	   while(fast.getNext() != null && fast.getNext().getNext() != null) {
		   slow = slow.getNext();
		   fast = fast.getNext().getNext();
	   }
	   
	   slow = slow.getNext();
	   Node temp = null;
	   Node temp2 = null;
	   while(slow != null) {
		   temp2 = slow.getNext();
		   //防止这一部把next的信息丢失,所以上述要先保存下一个的数据。
		   slow.setNext(temp);
		   //保存当前节点,用于下一次设置上述next的结果。
		   temp = slow;
		   slow = temp2;
	   }
	   Node p1 = head;
	   //当上述的循环跳出的时候,temp来到尾部
	   Node rear = temp;
	   boolean flag = true;
	   while(temp != null) {
		   if(temp.getData() != p1.getNext().getData()) {
			  flag = false;
			  break;
		   }
		   temp = temp.getNext();
		   p1 = p1.getNext();
	   }
	   
	   Node temp3 = null;
	   Node temp4 = null;
	   //将链表调整回来
	   while(rear != null) {
		  //也是防止下一个节点的信息丢失
		  temp3 = rear.getNext();
		  rear.setNext(temp4);
		  temp4 = rear;
		  rear = temp3;
	   }
	   
	   return flag;
   }

这个的空间复杂读可以变为O(1),时间复杂读为O(n)

你可能感兴趣的:(牛客网算法学习)