实现栈:栈是先进后出;准备一个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 StackstackData;
private StackstackMin;
public MyStack1(){
this.stackData=new Stack();
this.stackMin=new Stack();
}
public void push(int newNums){
if(stackMin.isEmpty()){//栈为空,压入
this.stackMin.push(newNums);
}else if(newNums
分析:
1.队列--栈:
图的深度优先遍历必须使用栈,那么怎么用队列来实现优先遍历呢,就需要用队列实现栈结构,可以用两个队列来实现栈,再去实现优先遍历,栈结构先进后出:让1234进到另外一个队列中,留着最后一个,把最后一个返回给用户;进的时候都进data栈,出的时候就除了最后一个都进到help栈中,然后换一下data和help的引用
package zuoshen;
import java.util.LinkedList;
import java.util.Queue;
public class StackAndQueueConvert {
public static class TwoQueueStack{
private Queuequeue;
private Queuehelp;
public TwoQueueStack(){
queue=new LinkedList();
help=new LinkedList();
}
// 使用两个队列来回倒,每次倒的时候留队列尾部最后一个元素,然后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 tmp = help;
help = queue;
queue = tmp;
}
}
}
2.栈--队列:
两个栈实现一个队列 ,用户要数的时候都是从pop栈里拿,压入都是压入push栈,
导的行为有两个限制:
1)如果push栈要往pop栈里边倒,一次必须倒完,
2)如果pop栈里边有东西,那push栈不要倒
这时候不能倒:pop中有数据的时候,不能倒,
public static class TwoStackQueue{
private Stack push;
private Stack pop;
public TwoStackQueue() {
push = new Stack();
pop = new Stack();
}
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 dogQ;
private Queue catQ;
private long count;
public DogCatQueue1() {
this.dogQ = new LinkedList();
this.catQ = new LinkedList();
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-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.valuehead2.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 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;
}
// 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 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;
}
// 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){
Mapmap=new HashMap();
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,无环
相遇时候,快指针回到开头,然后快指针由一次走两步变成一次走一步,这样快慢指针一定会在第一个入环出相遇