转圈打印矩阵:
【题目】 给定一个整型矩阵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)。
【思路】
模拟剥洋葱式输出,将矩阵从外围一圈一圈往里逼近。
设定两个标记位置,一个为矩阵的左上角边界,一个为矩阵的右下角边界,第一圈,从左上角的点开始按顺时针横坐标++打印元素,一直到右下角边界点的横坐标则停,然后纵坐标++往下打印元素,一直到右下角边界点的纵坐标则停,然后横坐标减减打印元素,一直到左上角边界点的横坐标则停,然后纵坐标减减输出打印,一直到与左上角边界点的纵坐标相等时不打印。此时即将外面一圈按转圈的方式打印完毕,然后更新左右边界,将左上角边界横纵坐标都++,右下角边界点横纵坐标都--,重复上述转圈打印,即可。
【Code】
public static void spiralOrderPrint(int[][] matrix) {int tR = 0;//左上角坐标int tC = 0;int dR = matrix.length - 1;//右下角坐标int dC = matrix[0].length - 1;while (tR <= dR && tC <=dC) {
printEdge(matrix, tR++, tC++, dR--, dC--);
}
}public static void printEdge(int[][] m, int tR, int tC, int dR, intdC) {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 curC =tC;int curR =tR;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][tC]+ " ");
curR--;
}
}
}public static voidmain(String[] args) {int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12},
{13, 14, 15, 16} };
spiralOrderPrint(matrix);
}
“之”字形打印矩阵:
【题目】 给定一个矩阵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)。
【思路】
设定两个点,初始位置都为(0,0),打印第一个元素后,a点往右移一步,b点往下移一步,两点之间形成一条对角线,打印对角线上的元素,规定方向,一开始为右上往左下,随后为左下往右上打印,打印完毕后两点继续右移和下移,当a点右移到边界时下移,b点下移到边界时右移,ab两点总能形成一条对角线,交替方向打印对角线上的数据即可。
【Code】
public static void printMatrixZigZag(int[][] matrix) {int tR = 0;int tC = 0;int dR = 0;int dC = 0;int endR = matrix.length - 1;int endC = matrix[0].length - 1;boolean fromUp = false;while (tR != endR + 1) {
printLevel(matrix, tR, tC, dR, dC, fromUp);
tR= tC == endC ? tR + 1: tR;
tC= tC == endC ? tC : tC + 1;
dC= dR == endR ? dC + 1: dC;
dR= dR == endR ? dR : dR + 1;
fromUp= !fromUp;
}
System.out.println();
}public static void printLevel(int[][] m, int tR, int tC, int dR, intdC,booleanf) {if(f) {while (tR != dR + 1) {
System.out.print(m[tR++][tC--] + " ");
}
}else{while (dR != tR - 1) {
System.out.print(m[dR--][dC++] + " ");
}
}
}
在行列都排好序的矩阵中找数:
【题目】
给定一个有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)。
【思路】
依题意,起始先从矩阵的右上角开始查找,如果比K大,证明此点下方所有元素都比K大,不用再看,将位置左移,比较,若还是比K大,则证明此点下方所有元素也都比K大,不用再看,将位置左移,比较,若此时该位置比K小,但不等于K,则往下查,如又比K大,则左移,如比K小,则下移,直至查到,或到达矩阵边界,程序结束。
【Code】
public static boolean isContains(int[][] matrix, intK) {int row = 0;int col = matrix[0].length - 1;while (row < matrix.length && col > -1) {if (matrix[row][col] ==K) {return true;
}else if (matrix[row][col] >K) {
col--;
}else{
row++;
}
}return false;
}
判断一个链表是否为回文结构:
【题目】
给定一个链表的头节点head,请判断该链表是否为回文结构。
例如:
1->2->1,返回true。
1->2->2->1,返回true。
15->6->15,返回true。
1->2->3,返回false。
附:查找链表中点位置,需要一个快指针和一个慢指针,快指针一次走两步,慢指针一次走1步,当快指针到达终点时慢指针即在链表的中点位置。
【基本思路】
使用一个栈结构,将数据都压入栈内,然后一一出栈与数组从头开始比较即可判别。
public static booleanisPalindrome1(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;
}
进阶:
如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。
【思路1】(省一半空间复杂度)
使用附中技术,找到链表中点,将中点后的元素都压入栈中,再依次从表头开始对出栈元素进行比较。
public static booleanisPalindrome2(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 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;
}
【思路2】(空间复杂度为O(1)但实现较繁琐复杂,适合面试讲述)
还是用附的技术找到链表中点,此时将中点往后的元素进行逆序。然后从两头开始进行比对。
比如1->2->3->2->1,找到中点3,将3后的链表逆序,改成1->2->3
逆序操作:例将3->2->1逆序,将2的next指针1记下,将2指向3,然后下顺,将1的next指针记下,再将next指向2。具体实现看Code。
【Code】
//need O(1) extra space
public static booleanisPalindrome3(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;
}returnres;
}