*给定单向链表的头指针和一个节点指针,定义一个函数在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;
}
}
}
* 题目:请实现一个函数用来匹配包含‘.’和‘*’的正则表达式。
* 模式中的字符‘.’表示任意一个字符,而‘*’表示它前面的字符可以出现任意次(包含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;
}
}