转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6442734.html
1:正则表达式匹配
如果pattern[curr+1]=='*'时,表示pattern[curr]可能出现0次,1次,或任意多次。那么下一次的匹配就有可能是:
出现0次:pattern[curr+2]与str[curr]比较
出现1次:pattern[curr+2]与str[curr+1]比较
出现多次:pattern[curr]与str[curr+1]比较
这三种情况都可能出现,递归这三种情况取或即可。
而每一位pattern匹配str,当pattern[curr]==str[curr]||(pattern[curr]=='.'&&str[curr]!=' ')时,则匹配当前字符,开始匹配下一个字符;
直到pattern和str都匹配到了末尾,说明字符串是这个正则表达式的句子,否则,只要其中一处不相等或者表达式到末尾而字符串还没匹配完,就不是它的句子。
2:判断字符串是否表示一个数值
形如 +100、5e2,-123之类的都是能表示数字的字符串。而12e、1ab2、+-3之类的则不是。
此题其实就是判断输入的字符串是否匹配 数字 的正则表达式:[sign] digits [[.][digits]] [e|E [sign]digits]
遍历输入的字符串,开头如果有+-号的一个,则匹配sign,匹配下一个;
遍历数字,如果遇到 '.' ,转入匹配小数,小数部分只能是纯数字;如果遇到e|E,则转入匹配科学记数法,后面如果有符号则只能正负号中其中一个1个,符号之后只能是纯数字;
3:字符中第一个不重复的字符
首先遍历一次字符串,对每一个字符,map.get(ch),如果无对象返回的话说明ch第一次出现,则插入map,令值为1;如果有返回,则说明重复了,更新其值为-1;
然后在第二次遍历字符串时,读到都一个value=-1的就是第一个不重复的字符了。
4:找到链表中环的入口结点
链表有环是指:尾结点的next指针指向了链表中的某一个结点形成了环。比如:1-2-3-4-5->3(5是尾结点,指向了3)
我们假设两个指针p1,p2遍历这个链表,p2比p1多遍历了一圈环后到达尾结点。则p2的遍历路程为:1-2-3-4-5-3-4-5 而p1遍历到尾结点:1-2-3-4-5,可以发现p2比p1多走了环的结点数步才到达尾结点。那么p2与p1的步数差刚好为环结点数,那么如果我们令p2先走环结点数步,然后p1在开始移动,之后p1、p2同时移动,当p1指向环的入口时,p2比p1多环结点数步,所以p2刚好走完了一次环,回到环入口,所以此时p1==p2。那么我们就找到了环的入口。
5:删除有序链表中重复的结点:1-2-2-3变成1-3
我们用pre记录当前结点,然后遍历一个结点pnext与pnext->next,如果相同,则令pnext=pnext->next跳过重复结点,循环此步,直到pnext!=pnext->next;那么期间的就是重复的结点,我们令pre->next=pnext->next即可把重复结点从链表中剔除;注意:头结点就开始重复的,找到第一个跟头结点不等的并且不重复的结点设为head即可删除开始就重复的结点。
6:给出一个二叉树和一个结点,找出中序遍历中这个结点的下一个结点。每个结点除了有左右子结点指针外还有一个指向父节点的指针。
解法1:我们可以用一个数组保存中序遍历的结果,然后遍历这个数组找到所给结点,它的下一个元素就是所求;
解法2:按照中序遍历规律来找:
如果所给结点有右子树,说明它是根结点,那么根据中序遍历“左根右”的顺序,它的右子树的最左子节点就是下一个结点,我们只需从右子结点一路左子节点直到找到最左子节点即可;
如果所给结点没有右子树,并且它是父节点的左儿子,那么下一个遍历的就是它的父节点;
如果所给结点既没有右子树,又不是父节点的左儿子,那么它的下一个遍历结点就是 第一个作为左儿子的祖先结点的父节点:我们从当前结点回溯父节点,并判断当前父节点是不是一个左儿子,不是的话继续上溯;直到当前祖先结点是其父的一个左儿子,那么该祖先结点的父节点就是下一个要遍历的结点;如果祖先结点到达树的根了,则说明所给结点是树的最右子节点,是中序遍历的最后遍历的那个结点。
7:判断一颗二叉树是否对称
解法一:对称的二叉树,其左右子树都是一样的。既然左右子树一样,那么我们根据 根左右 顺序遍历与 根右左 顺序遍历得到的序列应该是一样的。那么我们就可以定义一个 根左右 的遍历函数,一个 根右左 的遍历函数,得出两个序列一一进行比较即可。注意:这里有个特殊情况,各个结点的值一样,但是左右子树不对称,所以我们需要把子结点为null也作为一个值进行输出,作为遍历的序列的一个元素。
解法二:递归法,只要找到有一层地方不对称即可:
boolean isSame(MyTreeNode left,MyTreeNode right){ //左右子树都是空,则说明树是对称的 if(left==null && right==null){ return true; } //当前层判断出不相等的就说明树是不对称的 if((left==null&&right!=null)||(left!=null&&right==null)){ return false; } if(left.val!=right.val){ return false; } //否则,需要从下一层去判断 return isSame(left.leftNode, right.rightNode)&&isSame(left.rightNode, right.leftNode); }
8:之 字形打印二叉树
即:按层打印,相邻层打印方向不同:一层从左往右,下一层就从右往左打印,再下层左往右......
这种倒转顺序的情况,我们第一时间就想到——栈。因此打印每一层时,我们把位于下一层的子节点入栈;
由打印规律我们可以推出:当前打印层是奇数层时,则先保存左子结点再保存右子节点到另一个栈;如果是偶数层则先右后左保存子节点到另一个栈;每一个栈为空时“攻防互换”开始打印下一层;
9:序列化二叉树和反序列化二叉树
序列化二叉树是指:按前/中/后顺序遍历二叉树时,遇到null就用一个符号表示,比如 $ 符号。
void Serialize(MyTreeNode root){ if(root==null){ System.out.println("$,"); return; } System.out.println(root.val+','); Serialize(root.leftNode); Serialize(root.rightNode); }
反序列化二叉树是指:给定一个二叉树的序列化表示以及遍历规则,重构出一棵二叉树。
10:BST中第K大的结点
BST的中序遍历是一个增序的数组,该数组第K个元素就是BST中第K大结点。
11:求滑动窗内的最大值
给定一个数组,以k大小的滑动窗来遍历元素,求每个窗的最大值。
第一个窗包含了0~k-1下标的元素,之后窗口逐渐移动,可知总共移动了length-k步。
那么我们就可以这样做了:用一个数组存放元素,用两个间隔为k-1的下标维持一个一个大小为k的窗口:index1~index2刚好包含了k个元素。每次遍历index1~index2找到当前窗口最大值,然后index1++,index2++移动窗口。