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)。
1.1 分析
1.设置两个点A,B,起始位置如图:
- A每次向右走,走到最右边的时候往下走;
- B每次往下走,走到最下边的时候往右走;
A、B的运动方式可确定对角线的两个端点,如图:
接着,只要根据每次A、B的座标,打印这条对角线即可。
同时需要设置一个boolean值,表示打印对角线时是否是根据从右上往左下打印。
1.2 代码实现
package Solution;
public class ZhiPrintMatrix {
public static void main(String[] args) {
int[][] matrix= {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
PointCom(matrix);
}
public static void PointCom(int[][] m) {
int ax=0;//Ax
int ay=0;//Ay
int bx=0;//Bx
int by=0;//By
int x=m.length-1;//行
int y=m[0].length-1;//列
boolean fromUp=false;
while(ax<=x) {
//ay=y说明A到了最后一行,即走完了横也走完了竖
EdgePrint(m,ax,ay,bx,by,fromUp);
//行号的变化:当a的列数来到最后一列,它才往下走,即+1;否则不变
ax=ay==y?ax+1:ax;
//列号的变化:当a的列号来到最后一列之前,一直+1,到最后一列之后就不变
ay=ay==y?ay:ay+1;
by=bx==x?by+1:by;
bx=bx==x?bx:bx+1;
fromUp=!fromUp;
}
}
public static void EdgePrint(int[][] m,int ax,int ay,int bx,int by,boolean flag) {
if(flag) {
//从上到下
while(ax<=bx) {
System.out.print(m[ax++][ay--]+" ");
}
}
else {
while(bx>=ax) {
System.out.print(m[bx--][by++]+" ");
}
}
}
}
运行结果:
2.在行列都排好序的矩阵中找数
【题目】 给定一个有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)。
2.1 分析
2.1.1 方法一:从右上角点开始
若K>当前节点,往下;
若K<当前节点,往左;
若越界了都没找到,则返回false。
比如找4:
2.1.2 方法二:从左下角开始
若K>当前节点,则往右;
若K<当前节点,则往上;
2.2 代码实现
package Solution;
public class FindValue {
public static void main(String[] args) {
int[][] matrix= {{0, 1, 2, 5},{ 2, 3, 4, 7}, {4, 4, 4, 8}, {5, 7, 7, 9}};
System.out.println("6:"+findValue(matrix,6));
System.out.println("7:"+findValue(matrix,7));
}
public static boolean findValue(int[][] m,int k) {
int x=m.length-1;
int y=m[0].length-1;
//从右上角的点开始
int i=0;
int j=y;
while(i<=x&&j>=0) {
if(k==m[i][j])
return true;
else if(k>m[i][j])
//k>当前值,往下
i++;
else
j--;
}
return false;
}
}
运行结果:
3.打印两个有序链表的公共部分
【题目】 给定两个有序链表的头指针head1和head2, 打印两个链表的公共部分。
3.1 分析
Merge的过程中相等的打印即可。
3.2 代码实现
package Solution;
public class PrintSameValue {
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);
printValue(node1, node2);
}
public static void printValue(Node head1,Node head2) {
while(head1!=null&&head2!=null) {
if(head1.value==head2.value) {
System.out.print(head1.value+" ");
head1=head1.next;
head2=head2.next;
}
else if(head1.value>head2.value)
head2=head2.next;
else
head1=head1.next;
}
}
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();
}
}
运行结果:
4. 判断一个链表是否为回文结构
【题目】 给定一个链表的头节点head, 请判断该链表是否为回文结构。
例如: 1->2->1, 返回true。 1->2->2->1, 返回true。15->6->15, 返回true。 1->2->3, 返回false。
进阶: 如果链表长度为N, 时间复杂度达到O(N), 额外空间复杂度达到O(1)。
链表问题的最优解:往往在乎的是最小的空间复杂度(和其他题目有所不同)。
4.1 方法一
将链表遍历一遍,值放入栈中。
进行第二次遍历,同时将遍历到的节点值与弹出的栈顶元素相比较,若每一次都相等,则返回true;否则返回false。
4.1.1 代码实现
package Solution;
import java.util.List;
import java.util.Stack;
public class IsPalindrome {
public static void main(String[] args) {
Node head = null;
printLinkedList(head);
System.out.println(isPalindrome(head) );
printLinkedList(head);
System.out.println("=========================");
head = new Node(1);
printLinkedList(head);
System.out.println(isPalindrome(head) );
printLinkedList(head);
System.out.println("=========================");
head = new Node(1);
head.next = new Node(2);
printLinkedList(head);
System.out.println(isPalindrome(head) );
printLinkedList(head);
System.out.println("=========================");
head = new Node(1);
head.next = new Node(1);
printLinkedList(head);
System.out.println(isPalindrome(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.println(isPalindrome(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.println(isPalindrome(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.println(isPalindrome(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.println(isPalindrome(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.println(isPalindrome(head) );
printLinkedList(head);
System.out.println("=========================");
}
public static boolean isPalindrome(Node head) {
if (head == null || head.next == null) {
return true;
}
Stack<Integer> help=new Stack<Integer>();
Node newhead=head;
while(head!=null) {
help.push(head.value);
head=head.next;
}
while(newhead!=null) {
if(newhead.value==help.pop())
newhead=newhead.next;
else
return false;
}
return true;
}
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();
}
}
运行结果:
4.2 方法二
两个指针:
- 快指针每次走两步;
- 慢指针每次走一步。
当快指针走到末尾的时候,慢指针基本走到了中间。
然后慢指针继续往后走,并将走过的节点值压栈。后续过程同方法一。
4.2.1 代码实现
package Solution;
import java.util.List;
import java.util.Stack;
public class IsPalindrome {
public static boolean isPalindrome(Node head) {
//方法二
if (head == null || head.next == null) {
return true;
}
Node quick=head;
Node slow=head;
Stack<Integer> help=new Stack<Integer>();
while(quick.next!=null&&quick.next.next!=null) {
//可做到元素个数为奇数的时候来到重点,偶数个数的时候来到中间两个的前者
quick=quick.next.next;
slow=slow.next;
}
while(slow!=null) {
help.push(slow.value);
slow=slow.next;
}
while(!help.isEmpty()) {
if(head.value==help.pop())
head=head.next;
else
return false;
}
return true;
}
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();
}
}
4.3 方法三:不用辅助空间
两个指针:
- 快指针每次走两步;
- 慢指针每次走一步。
当快指针走到末尾的时候,慢指针基本走到了中间。
然后将后半部分进行逆序。
然后head和slow从各自的头开始往后比较。
最后返回之前再将后半部分逆序回来。
4.3.1 代码实现
package Solution;
import java.util.List;
import java.util.Stack;
public class IsPalindrome {
public static boolean isPalindrome(Node head) {
//方法三
if (head == null || head.next == null) {
return true;
}
Node quick=head;
Node slow=head;
while(quick.next!=null&&quick.next.next!=null) {
quick=quick.next.next;
slow=slow.next;
}
//此时quick指向的是末尾节点;slow指向的是中点
quick=slow.next;//quick变为右半部分的第一个节点,实例中的节点3后面的节点2
slow.next=null;//中间节点的next为空
Node newhead=null;
while(quick!=null) {
newhead=quick.next;
quick.next=slow;
slow=quick;
quick=newhead;
}
newhead=slow;
quick=head;//quick是左半边的头结点
boolean result=true;
while(quick!=null&&slow!=null) {
if(quick.value==slow.value) {
quick=quick.next;
slow=slow.next;
}
else {
//不能返回,右半部分还未还原
result=false;
break;
}
}
slow=newhead.next;//slow指向倒数第二个节点
newhead.next=null;
while (slow != null) { // recover list
//slow=head;quick=next;newhead=pre
quick = slow.next;
slow.next = newhead;
newhead = slow;
slow = quick;
}
return result;
}
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();
}
}