算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)

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,起始位置如图:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

  • A每次向右走,走到最右边的时候往下走;
  • B每次往下走,走到最下边的时候往右走;

A、B的运动方式可确定对角线的两个端点,如图:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

接着,只要根据每次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++]+" ");
			}
		}
	}
}

运行结果:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

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 方法一:从右上角点开始

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

若K>当前节点,往下;

若K<当前节点,往左;

若越界了都没找到,则返回false。

比如找4:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

2.1.2 方法二:从左下角开始

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

若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;
	}
}

运行结果:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

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();
	}
}

运行结果:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

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();
	}
}

运行结果:

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

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 方法三:不用辅助空间

两个指针:

  • 快指针每次走两步;
  • 慢指针每次走一步。

当快指针走到末尾的时候,慢指针基本走到了中间。

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

然后将后半部分进行逆序。

《算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)》

然后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();
	}
}

 

 

 

点赞