阅读该文章需要60分钟
文章目录
一:旋转正方形矩阵
1.1:题目描述
旋转正方形矩阵
【题目】 给定一个整型正方形矩阵matrix,请把该矩阵调整成顺时针旋转90度的样子。
【要求】 额外空间复杂度为O(1)。
1.2:详细思路
/**
* 左上角
* ↓
* 1 2 3 4
*
* 5 6 7 8
*
* 9 10 11 12
*
* 13 14 15 16
* ↑
* 右下角
*/
如上图所示这是一个正方形矩阵
很直观的可以想到,正方形里里外外有几圈,我们需要把这几圈的值都旋转
拿最外圈来说,我们只需要 1、2、3 旋转到 4、8、12的位置,
同理4、8、12旋转到16、15、14的位置,以此类推
我们扣边界,就可以写出1->4、2->8、3->12
转完最外圈,我们让圈缩小,也就是,左上角向右下角移动一格位置,右下角向左上角移动一个位置
让我们看下code即可
1.3:Java代码
package xyz.fudongyang.basic.class_03.my;
public class Code_06_RotateMatrix {
public static void rotate(int[][] matrix) {
int tR = 0;
int tC = 0;
int dR = matrix.length - 1;
int dC = matrix[0].length - 1;
while (tR <= dR && tC <= dC){
// 转一圈
rotateEdge(tR++,tC++,dR--,dC--,matrix);
}
}
private static void rotateEdge(int tR,int tC,int dR,int dC,int[][] matrix){
// 转几次 n-1 次
int times = dR - tR;
for (int i = 0; i < times; i++) {
// 先把这个第一个位置记录下来
int temp = matrix[tR][tC+i];
// 左下 替代 左上
matrix[tR][tC+i] = matrix[dR-i][tC];
// 右下 替代 左下
matrix[dR-i][tC] = matrix[dR][dC-i];
// 右上 替代 右下
matrix[dR][dC-i] = matrix[tR+i][dC];
// 左上 替代 右上
matrix[tR+i][dC] = temp;
}
}
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);
}
}
二:反转单向链表、反转双向链表
2.1:题目描述
反转单向和双向链表
【题目】 分别实现反转单向链表和反转双向链表的函数。
【要求】 如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度要求为O(1)
说实话,不要认为这个题目比较简单就不去做,我花了3个小时才做出来。
2.2:思路讲解
反转单向链表
反转单向链表
拿一个链表
1->2->3->4
反转链表的每个节点分为几步?
拿1节点开说
首先我们全局定义一个Node,作为反转后链表的头节点,那么初始化应该为null
我们需要把 链表中1的位置断开,也就是这样 1 2->3->4
我们拿到1这个节点,1这个节点的需要放到反转链表的头节点之前,也就是 1->null
我们的反转链表的头节点就是1了,然后遍历后续的2->3->4
我们再反转下2节点,把链表的头节点(现在是2节点)位置断开 2 3->4
我们拿到2这个节点,2这个节点的需要放到反转链表的头节点之前,也就是 2->1->null
我们的反转链表的头节点就是2了,然后遍历后续的3->4
以此类推
反转双向链表
反转双向链表
拿一个链表
1->2->3->4
反转链表的每个节点分为几步?
拿1节点开说
首先我们全局定义一个Node,作为反转后链表的头节点,那么初始化应该为null
我们需要把 链表中1的位置断开,也就是这样 1 2->3->4
1的父节点为null,1的后续节点应该为反转链表的头节点,也就是null
反转链表的头节点的父节点应该是1,这里反转链表的头节点为null就不用设置了
此时,反转链表的结构如下 1->null,继续遍历后续的2->3->4
我们需要把 链表中2的位置断开,也就是这样 2 3->4
2的父节点为null,2的后续节点应该为反转链表的头节点,也就是1
反转链表的头节点的父节点应该是2
此时,反转链表的结构如下 2<->1->null,继续遍历后续的 3->4
以此类推
2.3:Java代码
package xyz.fudongyang.basic.class_03.my;
import java.util.zip.CRC32;
public class Code_07_ReverseList {
public static class Node {
private int value;
private Node next;
public Node(int value) {
this.value = value;
}
}
private static Node reverseList(Node node) {
// 新链表
Node pre = null;
// 临时变量
Node next = null;
while (node != null){
// 记录一下我的 原来链后面的值,不能破坏我的循环规则
next = node.next;
// 我要放到新链表的第一个位置
node.next = pre;
// 我就代表新链表了
pre = node;
// 行了,继续循环吧
node = next;
}
return pre;
}
private static Node reverser(Node node){
Node newNode = null;
while (node != null){
Node next = node.next;
node.next = newNode;
newNode = node;
node = next;
}
return newNode;
}
public static class DoubleNode{
private int value;
private DoubleNode pre;
private DoubleNode next;
public DoubleNode(int value){
this.value = value;
}
}
public static DoubleNode reverseList(DoubleNode doubleNode){
DoubleNode newNode = null;
DoubleNode allNext;
while (doubleNode != null){
// 拿出当前节点
allNext = doubleNode.next;
// 当前节点的下一个指向新链表
doubleNode.next = newNode;
if (newNode != null){
// 新链表的头节点指向当前节点
newNode.pre = doubleNode;
}
// 当前节点就是新节点
doubleNode.pre = null;
newNode = doubleNode;
// 遍历后续节点
doubleNode = allNext;
}
return newNode;
}
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.pre;
}
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.pre = head2;
head2.next.next = new DoubleNode(3);
head2.next.next.pre = head2.next;
head2.next.next.next = new DoubleNode(4);
head2.next.next.next.pre = head2.next.next;
printDoubleLinkedList(head2);
printDoubleLinkedList(reverseList(head2));
}
}
三: 之字形打印矩阵
3.1:题目描述
“之”字形打印矩阵
【题目】 给定一个矩阵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)。
3.2:思路讲解
大体观
不要被题目吓到,也就是求边界的问题,仔细debug一下边界值就行了
我可以讲讲我的思路吗?
上图↘
/**
* 左上角 右上角
* ↓ ↓
* 1 2 3 4
*
* 5 6 7 8
*
* 9 10 11 12
* ↑ ↑
* 左下角 右下角
*/
也就是打印对角线呗,(1)、(2、5)、(9、6、3)、(4、7、10)、(11、8)、(12)
那行,我只需要分为两步就行了
第一步;打印对角线
第二布:调整对角线
举个例子,我们打印(1)、(2、5)、(9、6、3)这三个说明一下
第一步:打印对角线
两点确定一条直线,那我们确认对角线需要两个点,右上角的点的坐标,左下角点的坐标。
还有箭头的方向,我们仔细观察可以得知方向如下:左下->右上 右上->左下 左下->右上 ····
我们打印对角线可以做到,只要给我们对角线两端的的坐标,和打印方向即可。
第二步:调整对角线
右上角的对角线的坐标一直向右移动,如果移动到最后一列,那就向下移动
左下角的对角线的坐标一直向下移动,如果移动到最后一行,那就向左移动
一直移动到最后一个位置为止。
看code
3.3:Java代码
package xyz.fudongyang.basic.class_03.my;
public class Code_08_ZigZagPrintMatrix {
public static void printMatrixZigZag(int[][] matrix) {
/**
* 左上角
* ↓
* 1 2 3 4
*
* 5 6 7 8
*
* 9 10 11 12
* ↑
* 右下角
*/
int tR = 0;
int tC = 0;
int dR = 0;
int dC = 0;
int endR = matrix.length-1;
int endC = matrix[0].length-1;
boolean flag = false;
// 如果右上角还没越界,就继续走
while (tR != endR +1){
// 打印对角线的值
printLevel(matrix,tR,tC,dR,dC,flag);
// 改变 tR,tC,dR,dC边界值
tR = tC == endC ? tR+1 : tR;
tC = tC == endC ? tC : tC+1;
dC = dR == endR ? dC+1 : dC;
dR = dR == endR ? dR : dR+1;
// 反过来继续循环,为了下次反过来打印对角线的值
flag = !flag;
}
System.out.println();
}
private static void printLevel(int[][] matrix,int tR,int tC,int dR,int dC,boolean flag){
// 从右上到左下
if (flag){
while (tR != dR +1){
System.out.print(matrix[tR++][tC--]+" ");
}
}else {
while ((dR != tR -1)){
System.out.print(matrix[dR--][dC++]+" ");
}
}
}
public static void main(String[] args) {
int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
printMatrixZigZag(matrix);
}
}
四:行和列都排好序,找数
4.1:题目描述
在行列都排好序的矩阵中找数
【题目】 给定一个有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)。
4.2:思路讲解
哈哈哈 这个题 我没刷算法之前就会 可简单
举个例子:
第一个判断的数
↓
1 2 3
4 5 6
7 8 9
↑
最后一个判断的数
我们先从最后一列判断,最后一列是改行的最大值,如果比最后一列的第一行大,
那么就和下一行比较,如果比最后一列的该行小,那就向该行的左移动。
直到向左向下移动不了,那就是不存在该数。
看code
4.3:Java代码
package xyz.fudongyang.basic.class_03.my;
public class Code_09_FindNumInSortedMatrix {
public static boolean isContains(int[][] matrix, int K) {
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;
}
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(isContains(matrix, K));
}
}
五:打印两个有序链表的公共部分
5.1:题目描述
【题目】 给定两个有序链表的头指针head1和head2,打印两个链表的公共部分。
5.2:思路讲解
不难,如果感觉没思路,可能题意没看懂
其实让你求的是这两个有序链表中的值,有哪些相同的
很简单
同时遍历两个链表,如果哪个链表的当前值小,哪个链表向后移动一下
如果两个链表的当前值一样大,则打印,并两个链表同时向后移动一下
看code
5.3:Java代码
package xyz.fudongyang.basic.class_03.my;
public class Code_10_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);
}
}
六:判断链表是否为回文结构
6.1:题目描述
判断一个链表是否为回文结构
【题目】 给定一个链表的头节点head,请判断该链表是否为回文结构。
例如: 1->2->1,返回true。 1->2->2->1,返回true。15->6->15,返回true。 1->2->3,返回false。
进阶: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。
6.2:思路如下
空间复杂度O(N)
将链表中的值压到栈
那么出栈循序则是链表的逆序
那么链表的逆序和链表的正序对比
如果相等,则是回文结构,你品品这个道理吧,一会让你看代码
空间复杂度O(N/2)
找到链表的中间位置
将链表中间位置之后的数压倒栈中
这样我们只压入一半的数据,也就是2/N的数据
然后将栈弹出的数和链表的数做对比
空间复杂度O(1)
找到链表的中间位置
反转链表后面的位置
对比链表前面的数据,和中间以后反转链表的数据
得出对比结果后,还原源数据(Java值传递,我们不能改变原始数据)
6.3:Java代码
package xyz.fudongyang.basic.class_03.my;
import java.util.Stack;
public class Code_11_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) {
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; // is mid
Node n2 = head;
while (n2.next != null && n2.next.next != null){
n1 = n1.next;
n2 = n2.next.next;
}
// reverse mid->last
n2 = n1.next;
n1.next = null;
// temp Node
Node n3;
while (n2 != null){
n3 = n2.next;
n2.next = n1;
n1 = n2;
n2 = n3;
}
// verified value
// save n1 node
n3 = n1;
n2 = head;
boolean res = true;
while (n1 != null && n2 != null){
if (n1.value != n2.value){
res = false;
break;
}
n1 = n1.next;
n2 = n2.next;
}
// recover data
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();
}
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("=========================");
}
}
七:放到最后
一群lsp,赶紧学习去