剑指Offer面试题(第十六天)面试题24、25、26

 * 面试题24:反转链表


     * 题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
     * 链表节点定义:
     * struct ListNode{
     *     int m_nKey;
     *     ListNode* m_pNext;
     * }
     * 
     * 思路:从原链表头部开始转换链表的指向,需要使用三个指针。
     * 分别记录:第二个节点指向第一个节点,那么第二个在原链表时指向的那个将会丢失,所以用地三个指针记录此节点。
     * 并且要保证鲁棒性,完整性  考虑输入数据可能对程序的影响,避免系统崩溃

package Test;

import Test.No22findKthToTail.ListNode;

public class No24reverseList {

	/*
	 * 面试题24:反转链表
	 * 题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
	 * 链表节点定义:
	 * struct ListNode{
	 * 	int m_nKey;
	 * 	ListNode* m_pNext;
	 * }
	 * 
	 * 思路:从原链表头部开始转换链表的指向,需要使用三个指针。
	 * 分别记录:第二个节点指向第一个节点,那么第二个在原链表时指向的那个将会丢失,所以用地三个指针记录此节点。
	 * 并且要保证鲁棒性,完整性  考虑输入数据可能对程序的影响,避免系统崩溃
	 * */
	
	static class ListNode{
		int data;
		ListNode next;
		
		ListNode(int data){
			this.data = data;
		}
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No24reverseList r = new No24reverseList();
		
		ListNode head = new ListNode(1);
		ListNode second = new ListNode(2);
		ListNode three = new ListNode(3);
		ListNode four = new ListNode(4);
		ListNode five = new ListNode(5);
		ListNode six = new ListNode(6);
		ListNode seven = new ListNode(7);
		head.next = second;
		second.next = three;
		three.next = four;
		four.next = five;
		five.next = null;
		six.next = null;
		seven.next = null;
		
		ListNode node = head;
		System.out.println("输出单向链表数据:");
		for(int i=0;i<5;i++) {
			System.out.println(node.data);
			node = node.next;
		}
		
		
		
		ListNode reverse = r.reverseList(head);
		
		System.out.println("输出反转后的链表数据");
		for(int i=0;i<5;i++) {
			System.out.println(reverse.data);
			reverse = reverse.next;
		}
	}

	//反转链表
	public ListNode reverseList(ListNode head) {
		// TODO Auto-generated method stub
		ListNode second = null;
		if(head == null || head.next == null) {
			return head;
		}
		ListNode first = head;
		second = head.next;
		ListNode third = null;
		
		
		
		
		if(head.next.next != null) {
			third = head.next.next;
		}
		
		while(second != first) {
			
			second.next = first;
			//若为原链表的表头  则将其next设置为null
			if(first == head)
				first.next = null; 
			first = second;
			//若第三个部位空,则将其赋值给second
			if(third != null) {
				second = third;
			}
			else 
				continue;
			
			
			if(third.next != null) {
				third = third.next;
			}
			else 
				continue;
			
		}
		
		
//		System.out.println("输出反转后的链表数据");
//		for(int i=0;i<5;i++) {
//			System.out.println(second.data);
//			second = second.next;
//		}
		return second;
		
		
		
	}

}

* 面试题25:合并两个排序的链表


     * 题目:输入两个递增序列的链表,合并这两个链表并是新链表中的节点仍然是递增排序的。
     * 例如: 输入链表1:1->3->5->7和链表2:2->4->6->8,
     * 将二者合并之后的升序链表为:1->2->3->4->5->6->7->8
     * 
     * 
     * 思路:取两个链表的头节点,比较大小,小的作为新的合并的链表的头节点;
     *            然后将剩余的两个链表的头节点在进行比较,小的再作为新的合并的链表的下一个节点,
     *            。。。。。。直到两个链表都到末尾为止。若是一个先到达末尾,则另一个直接将剩余数据连接到新的链表之后即可。
     *           还要注意空指针问题:若是开始一个链表为空,则合并的新链表就是另一个有数据的链表。
     *                      若是两个都为空链表,则新链表为空链表。 
     *           
     *   这是一个递归的过程
     *   递归就是不断直接或间接调用自己的函数;
     *   迭代是不断执行函数中一部分代码的过程。

package Test;

import Test.No24reverseList.ListNode;

public class No25mergeList {

	/*
	 * 面试题25:合并两个排序的链表
	 * 题目:输入两个递增序列的链表,合并这两个链表并是新链表中的节点仍然是递增排序的。
	 * 例如: 输入链表1:1->3->5->7和链表2:2->4->6->8,
	 * 将二者合并之后的升序链表为:1->2->3->4->5->6->7->8
	 * 
	 * 
	 * 思路:取两个链表的头节点,比较大小,小的作为新的合并的链表的头节点;
	 *            然后将剩余的两个链表的头节点在进行比较,小的再作为新的合并的链表的下一个节点,
	 *            。。。。。。直到两个链表都到末尾为止。若是一个先到达末尾,则另一个直接将剩余数据连接到新的链表之后即可。
	 *           还要注意空指针问题:若是开始一个链表为空,则合并的新链表就是另一个有数据的链表。
	 *           	       若是两个都为空链表,则新链表为空链表。 
	 *           
	 *   这是一个递归的过程
	 *   递归就是不断直接或间接调用自己的函数;
	 *   迭代是不断执行函数中一部分代码的过程。
	 * */
	
	static class ListNode{
		int data;
		ListNode next;
		
		ListNode(int data){
			this.data = data;
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No25mergeList m = new No25mergeList();
		
		ListNode head1 = new ListNode(1);
		ListNode head2 = new ListNode(2);
		ListNode three = new ListNode(3);
		ListNode four = new ListNode(4);
		ListNode five = new ListNode(5);
		ListNode six = new ListNode(6);
		ListNode seven = new ListNode(7);
		ListNode eight = new ListNode(8);
		//链表1
		head1.next = three;
		three.next = five;
		five.next = seven;
		seven.next = null;
		//链表2
		head2.next = four;
		four.next = six;
		six.next = eight;
		eight.next = null;
		
		ListNode node1 = head1;
		System.out.println("输出链表1数据:");
		for(int i=0;i<4;i++) {
			System.out.println(node1.data);
			node1 = node1.next;
		}
		ListNode node2 = head2;
		System.out.println("输出链表2数据:");
		for(int i=0;i<4;i++) {
			System.out.println(node2.data);
			node2 = node2.next;
		}
		
		System.out.println("输出合并后的链表:");
		ListNode mergeList = m.mergeList(head1,head2);
		for(int i = 0;i < 8;i++) {
			System.out.print(mergeList.data+"  ");
			mergeList = mergeList.next;
		}
		System.out.println();
		System.out.println("****************************"+"完成合并"+"****************************");
	}
	
	//合并两个链表
	public ListNode mergeList(ListNode head1, ListNode head2) {
		// TODO Auto-generated method stub
		ListNode newList = null;
		
		if(head1 == null) 
			return head2;
		if(head2 == null)
			return head1;
		
		if(head1.data < head2.data) {
			newList = head1;
			newList.next = mergeList(head1.next,head2);
		}
		else {
			newList = head2;
			newList.next = mergeList(head1,head2.next);
		}
		
		
		return newList;
			
		
	}

}

 * 面试题26:树的子结构


     * 题目:输入两颗二叉树A和B,判断B是不是A的子结构。
     * 二叉树节点定义:
     * struct BinaryTreeNode{
     *     double m_dbValue;
     *     BinaryTreeNode m_pLeft;
     *     BinaryTreeNode m_pRight;
     * }
     * 
     * 第一个链表记为A  第二个链表记为B,  方便说明
     * 思路:第一步:首先判断在A中是否有和B的根节点一样的值,递归方式遍历二叉树,若根节点不是,看左节点、右节点
     * 第二步:根据第一步找到的节点,判断其子树是否和B的一样,否则,返回到第一步判断其他节点是否有相等的

package Test;

public class No26isSubStruct {

	/*
	 * 面试题26:树的子结构
	 * 题目:输入两颗二叉树A和B,判断B是不是A的子结构。
	 * 二叉树节点定义:
	 * struct BinaryTreeNode{
	 * 	double m_dbValue;
	 * 	BinaryTreeNode m_pLeft;
	 * 	BinaryTreeNode m_pRight;
	 * }
	 * 
	 * 第一个链表记为A  第二个链表记为B,  方便说明
	 * 思路:第一步:首先判断在A中是否有和B的根节点一样的值,递归方式遍历二叉树,若根节点不是,看左节点、右节点
	 * 第二步:根据第一步找到的节点,判断其子树是否和B的一样,否则,返回到第一步判断其他节点是否有相等的
	 * 
	 * */
	
	static class BinaryTreeNode{
		//int val;
		double val;
		BinaryTreeNode left;
		BinaryTreeNode right;
		
		BinaryTreeNode(int val){
			this.val = val;
		}
	}
	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		No26isSubStruct s = new No26isSubStruct();
		
		BinaryTreeNode root1 = new BinaryTreeNode(8);
		BinaryTreeNode one = new BinaryTreeNode(8);
		BinaryTreeNode two = new BinaryTreeNode(7);
		BinaryTreeNode three = new BinaryTreeNode(9);
		BinaryTreeNode four = new BinaryTreeNode(2);
		BinaryTreeNode five = new BinaryTreeNode(4);
		BinaryTreeNode six = new BinaryTreeNode(7);
		
		root1.left = one;
		root1.right = two;
		one.left = three;
		one.right = four;
		two.left = null;
		two.right = null;
		three.left = null;
		three.right = null;
		four.left = five;
		four.right = six;
		five.left = null;
		five.right = null;
		six.left = null;
		six.right = null;
				
		BinaryTreeNode root2 = new BinaryTreeNode(5);
		BinaryTreeNode first = new BinaryTreeNode(9);
		BinaryTreeNode second = new BinaryTreeNode(2);
		
		root2.left = first;
		root2.right = second;
		first.left = null;
		first.right =null;
		second.left = null;
		second.right = null;
				
		if(s.isSubStruct(root1,root2) == true) {
			System.out.println("第二个二叉树是第一个二叉树的子结构!");
		}
		else {
			System.out.println("第二个二叉树不是第一个二叉树的子结构!!!!");
		}
	}


	//判断第二个二叉树是否为第一个二叉树的子结构
	//首先判断是否在第一个二叉树中能找到第二个二叉树的根节点一样的节点
	//相等的话再判断是否在第一步中中找到的这个节点包含的子树,与第二个二叉树结构相同
	public boolean isSubStruct(BinaryTreeNode root1, BinaryTreeNode root2) {
		// TODO Auto-generated method stub
		Boolean result = false;
		
		if(root2 != null && root1 != null) {
			//首先判断是否能找到第二个二叉树的根节点一样的值
			if(equal(root2.val,root2.val)) {
				//若找到了,则看它的子树是否与第二个完全重合
				result = hasSubTree(root1,root2);
			}
			
			if(!result) {
				result = hasSubTree(root1.left,root2);
			}
			if(!result) {
				result = hasSubTree(root1.right,root2);
			}
		}
		
		
		return result;
	}


	


	//判断子树是否与第二个的重合,不重合,则返回isSubStruct()中继续找和第二个二叉树根节点一样的
	public Boolean hasSubTree(BinaryTreeNode root1, BinaryTreeNode root2) {
		// TODO Auto-generated method stub
		if(root2 == null)
			return true;
		//因为有上一步,所以root2!=null,所以此处是判断
		//root1==null && root2!=null的情况
		if(root1 == null)
			return false;
		
		if(equal(root1.val,root2.val)) {
			return false;
		}
		
		return hasSubTree(root1.left,root2.left)&&hasSubTree(root1.right,root2.right);
	}

	
	//判断两个值是否相等:因为节点中值的类型是double,
	//计算机在判断小数(包括float和double类型)都有误差,不能使用 ==
	//所以判断两个小数是否相等,只能判断他们之间的绝对值是不是在一个很小的范围内。
	//若是两个数相差很小,就可以认为他们想等
	public boolean equal(double val1, double val2) {
		// TODO Auto-generated method stub
		if((val1 - val2 > -0.0000001)&&(val1 - val2 < 0.0000001)) {
			return true;
		}
		return false;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43137176/article/details/89139851