剑指Offer面试题(第十三天)面试题18(1)、18(2)、19

 * 面试题18:删除链表的节点


     * 题目一:在O(1)时间内删除链表节点


     *给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。链表节点与函数的定义如下:
     *struct ListNode{
     *    int m_nValue;
     *    ListNode* m_pNext;
     *};
     *
     *void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted); 
     *
     *思路:删除链表节点有三种情况:
     *1、只有一个节点,删除头节点即是尾节点,直接head.next = null即可
     *2、删除的节点不是尾节点,找到要删除的下一个节点将其数据赋值给要删除的节点,并且将下一个节点的next赋值给要删除的节点的next即可
     *3、删除的节点是尾节点,但是前面有很多个节点,则需要从头节点遍历到要删除的前一个节点,然后将这个节点的next置空null即可。

package Test;

public class No18First_deleteNode {

	/*
	 * 面试题18:删除链表的节点
	 * 题目一:在O(1)时间内删除链表节点
	 *给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。链表节点与函数的定义如下:
	 *struct ListNode{
	 *	int m_nValue;
	 *	ListNode* m_pNext;
	 *};
	 *
	 *void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted); 
	 *
	 *思路:删除链表节点有三种情况:
	 *1、只有一个节点,删除头节点即是尾节点,直接head.next = null即可
	 *2、删除的节点不是尾节点,找到要删除的下一个节点将其数据赋值给要删除的节点,并且将下一个节点的next赋值给要删除的节点的next即可
	 *3、删除的节点是尾节点,但是前面有很多个节点,则需要从头节点遍历到要删除的前一个节点,然后将这个节点的next置空null即可。
	 * */
	
	//定义ListNode节点  静态 
	static class ListNode{
		int data;
		ListNode next;
		
		ListNode(int data) {
			this.data = data;
		}
	};
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No18First_deleteNode d = new No18First_deleteNode();
		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 = six;
		six.next = seven;
		seven.next = null;
		
		ListNode node = head;
		System.out.println("输出单向链表数据:");
		for(int i=0;i<7;i++) {
			System.out.println(node.data);
			node = node.next;
		}
		d.deleteNode(head,second);
		
	
	}

	//删除节点
	public void deleteNode(ListNode head, ListNode deletenode) {
		// TODO Auto-generated method stub
		if(head==null || deletenode==null) {
			return;
		}
		
		//要删除的节点不是尾节点
		if(deletenode.next != null) {
			ListNode temp = deletenode.next;
			deletenode.data = temp.data;
			deletenode.next = temp.next;
			
			
 		}
		//链表中只有一个节点,删除头节点,也是尾节点
		else if(head == deletenode) {
			head.next = null;
		}
		
		//链表中有多个节点,删除尾节点
		else {
			ListNode temp = head;
			//找到deletenode的前一个节点
			while(temp.next != deletenode) {
				temp = temp.next;
			}
			temp.next = null;
			
		}
		
		
		System.out.println("输出删除节点后的单向链表数据:");
		ListNode node = head;
		for(int i=0;i<6;i++) {
			System.out.println(node.data);
			node = node.next;
		}
		
	}

}

 * 题目二:删除链表中重复的节点


     * 在一个排序的链表中,如何删除重复的节点?
     * 例如:1->2->2->3->3,删除重复的节点后为:1->2->3
     * 
     * 思路:就是从头节点开始,两两进行比较,相等的next指针移动,并改变前一个的指向,
     *     不想等的将所有指针的只想向后移即可。直到到达链表的结尾结束。

package Test;

import Test.No18First_deleteNode.ListNode;

public class No18Second_deleteDuplication {

	/*
	 * 面试题18:删除链表的节点
	 * 题目二:删除链表中重复的节点
	 * 在一个排序的链表中,如何删除重复的节点?
	 * 例如:1->2->2->3->3,删除重复的节点后为:1->2->3
	 * 
	 * 思路:就是从头节点开始,两两进行比较,相等的next指针移动,并改变前一个的指向,
	 *     不想等的将所有指针的只想向后移即可。直到到达链表的结尾结束。
	 * 
	 * */
	static class ListNode{
		int data;
		ListNode next;
		
		public ListNode(int data) {
			this.data = data;
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		No18Second_deleteDuplication d = new No18Second_deleteDuplication();
		
		ListNode head = new ListNode(1);
		ListNode second = new ListNode(1);
		ListNode three = new ListNode(1);
		ListNode four = new ListNode(1);
		ListNode five = new ListNode(2);
		ListNode six = new ListNode(2);
		ListNode seven = new ListNode(2);
		head.next = second;
		second.next = three;
		three.next = four;
		four.next = five;
		five.next = six;
		six.next = seven;
		seven.next = null;
		
		ListNode node = head;
		System.out.println("输出单向链表数据:");
		for(int i=0;i<7;i++) {
			System.out.println(node.data);
			node = node.next;
		}
		d.deleteDuplication(head);
	}

	//删除链表中重复的节点
	public void deleteDuplication(ListNode head) {
		// TODO Auto-generated method stub
		if(head == null || head.next == null) {
			return ;
		}
		
		ListNode preNode = head;
		ListNode curNode = head;
		ListNode nextNode = curNode.next;
		while(curNode.next != null) {
			//只要当前节点不为空就执行循环体
			System.out.println("运行");
			
			
			if(curNode.data != nextNode.data) {
				//若是两个值不想等,则三个标识位都向后移动一个位置
				preNode = curNode;
				curNode = preNode.next;
				nextNode = curNode.next;
				
			}
			else {
				//若两个值相等有几种情况:
				//1、若不是尾节点部分重复,则直接将当前节点的next指向nextNode的next
				//   并且改变nextNode的next指针即可
				if(nextNode.next != null) {
					curNode.next = nextNode.next;
					
					nextNode = curNode.next;
					
				}
				//2、若是尾节点部分重复,则直接将当前节点的next置为空即可。
				else {
					//表示是1,2,3,6,6的情况最后两个节点重复
					curNode.next = null;
				}
			}	
		}
		System.out.println("输出删除重复节点后的单向链表数据:");
		ListNode node = head;
		for(int i=0;i<2;i++) {
			System.out.println(node.data);
			node = node.next;
		}
 		
	}

}

 * 面试题19:正则表达式匹配


     * 题目:请实现一个函数用来匹配包含‘.’和‘*’的正则表达式。
     * 模式中的字符‘.’表示任意一个字符,而‘*’表示它前面的字符可以出现任意次(包含0次)
     * 在本题中,匹配是指字符串的所有字符匹配整个模式
     * 例如:字符串“aaa”与模式“a.a”和“ab*ac*a”匹配(在ab*ac*a中表示b出现任意次,c出现任意次),但与“aa.a”和“ab*a”均不匹配
     * 
     * 
     * 模式中的字符可以为:普通字符 \'.'\'*'三种情况
     * 思路:使用递归的思想,首先判断字符串和模式是否到达了末尾,到达了,则表示匹配成功.
     *            若字符串未到达末尾,但模式到达了末尾,则匹配失败
     *            若模式第二个字符是'*',字符串为达到末尾,并且模式中的第一个字符与字符串中第一个字符相匹配(或是普通字符相等,或是'.'),
     *         则字符串和模式有三种移动情况
     *         1>字符串移动一个,模式移动两个,都进入下一状态(执行1次x*操作)
     *      2>字符串移动一个,模式不移动(可以执行任意次)
     *      3>字符串不移动,模式移动两个(相当于执行0次x*操作)
     *            若模式第二个字符不是'*',那么就是'.'或者普通字符
     *         若是'.'或者与普通字符相匹配,则该字符匹配,字符串和模式都后移一位
     * 
     *        否则返回false

package Test;

import java.util.Scanner;

public class No19match {

	
	/**
	 * 面试题19:正则表达式匹配
	 * 题目:请实现一个函数用来匹配包含‘.’和‘*’的正则表达式。
	 * 模式中的字符‘.’表示任意一个字符,而‘*’表示它前面的字符可以出现任意次(包含0次)
	 * 在本题中,匹配是指字符串的所有字符匹配整个模式
	 * 例如:字符串“aaa”与模式“a.a”和“ab*ac*a”匹配(在ab*ac*a中表示b出现任意次,c出现任意次),但与“aa.a”和“ab*a”均不匹配
	 * 
	 * 
	 * 模式中的字符可以为:普通字符 \'.'\'*'三种情况
	 * 思路:使用递归的思想,首先判断字符串和模式是否到达了末尾,到达了,则表示匹配成功.
	 * 	       若字符串未到达末尾,但模式到达了末尾,则匹配失败
	 * 	       若模式第二个字符是'*',字符串为达到末尾,并且模式中的第一个字符与字符串中第一个字符相匹配(或是普通字符相等,或是'.'),
	 * 		则字符串和模式有三种移动情况
	 * 		1>字符串移动一个,模式移动两个,都进入下一状态(执行1次x*操作)
	 *      2>字符串移动一个,模式不移动(可以执行任意次)
	 *      3>字符串不移动,模式移动两个(相当于执行0次x*操作)
	 * 	       若模式第二个字符不是'*',那么就是'.'或者普通字符
	 * 		若是'.'或者与普通字符相匹配,则该字符匹配,字符串和模式都后移一位
	 * 
	 * 	   否则返回false
	 */
	 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		No19match m = new No19match();
		
		//比较字符串与模式(正则表达式)之间是否匹配
		char[] str = {'a','a'};
		char[] pattern = {'.','b','*','a'};
		
		if(match(str,pattern) == true) {
			System.out.println("字符串与模式匹配!");
		}
		else {
			System.out.println("字符串与模式不匹配!");
		}
		
	}

	public static boolean match(char[] str, char[] pattern) {
		// TODO Auto-generated method stub
		if(str == null || pattern == null) {
			return false;
		}
		 
		//若字符串长度为1
		if(str.length== 1) {
			if(pattern.length == 1) {
				if(str[0] == pattern[0] || pattern[0] == '.') {
					return true;
				}
				else return false;
			}
			
		}
		int sindex = 0;
		int pindex = 0;
		
		return matchCore(str,sindex,pattern,pindex);
		
	
	}

	private static boolean matchCore(char[] str, int sindex, char[] pattern, int pindex) {
		// TODO Auto-generated method stub
		
		//有效性检查:str和pattern都到达末尾,匹配成功
		if(sindex == str.length && pindex == pattern.length) {
			return true;
		}
		
		//pattern先到达尾部,则匹配失败
		if(sindex != str.length && pindex == pattern.length) {
			return false;
		}
		
		//str字符串未达到尾部
		//若pattern模式第二个是*,且字符串第一个与模式的第一个匹配(或是与普通字符匹配,或是与'.'匹配),
		//则字符串和模式移动情况为:字符串移动一个字符,模式可以移动两个字符或者不移动
		//如不匹配,则模式后移两个字符,字符串不移动
		if(pindex + 1 < pattern.length && pattern[pindex+1] == '*') {
			if((sindex != str.length && pattern[pindex] == str[sindex])
					||(sindex != str.length && pattern[pindex] == '.')) {
				return matchCore(str,sindex+1,pattern,pindex+2)
				||matchCore(str,sindex+1,pattern,pindex)
				||matchCore(str,sindex,pattern,pindex+2); //就算匹配上了也可以将其忽略,将字符串中的这个字符与后移两位后的字符进行匹配
			}
			else {
				return matchCore(str,sindex,pattern,pindex+2);
			}
			
		}
		
		//str字符串未达到尾部
		//若pattern模式第二个不为'*'
		if((sindex != str.length && str[sindex] == pattern[pindex])||(sindex != str.length && pattern[pindex] == '.')) {
			return matchCore(str,sindex+1,pattern,pindex+1);
		}
	
		return false;
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值