51.请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
public class Solution {
public boolean match(char[] str, char[] pattern) {
if (str == null || pattern == null) {
return false;
}
int strIndex = 0;
int patternIndex = 0;
return matchCore(str, strIndex, pattern, patternIndex);
}
public boolean matchCore(char[] str, int strIndex, char[] pattern, int patternIndex) {
//有效性检验:str到尾,pattern到尾,匹配成功
if (strIndex == str.length && patternIndex == pattern.length) {
return true;
}
//pattern先到尾,匹配失败
if (strIndex != str.length && patternIndex == pattern.length) {
return false;
}
//模式第2个是*,且字符串第1个跟模式第1个匹配,分3种匹配模式;如不匹配,模式后移2位
if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') {
if ((strIndex != str.length && pattern[patternIndex] == str[strIndex]) || (pattern[patternIndex] == '.' && strIndex != str.length)) {
return matchCore(str, strIndex, pattern, patternIndex + 2)//模式后移2,视为x*匹配0个字符
|| matchCore(str, strIndex + 1, pattern, patternIndex + 2)//视为模式匹配1个字符
|| matchCore(str, strIndex + 1, pattern, patternIndex);//*匹配1个,再匹配str中的下一个
} else {
return matchCore(str, strIndex, pattern, patternIndex + 2);
}
}
//模式第2个不是*,且字符串第1个跟模式第1个匹配,则都后移1位,否则直接返回false
if ((strIndex != str.length && pattern[patternIndex] == str[strIndex]) || (pattern[patternIndex] == '.' && strIndex != str.length)) {
return matchCore(str, strIndex + 1, pattern, patternIndex + 1);
}
return false;
}
}
52.请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
public class Solution {
public boolean isNumeric(char[] str) {
String regex = "([+-]?[\\d]+)?([+-]?[\\d]*[\\.][\\d]+)?([+-]?[\\d]+[Ee][+-]?[\\d]+)?";
return String.valueOf(str).matches(regex);
}
}
53.请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
public class Solution {
//Insert one char from stringstream
int [] temp = new int [256];
int index = 1;
public void Insert(char ch)
{
if(temp[ch] == 0){
temp[ch]=index++;
} else{
temp[ch]=-1;
}
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
char c = '#';
int max = Integer.MAX_VALUE;
for(int i = 0;i<256;i++){
if(temp[i]!=0&&temp[i]!=-1&&temp[i]<max){
max = temp[i];
c =(char)i;
}
}
return c;
}
}
54.给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null) return pHead;
ListNode p = pHead;
ListNode q = pHead;
while(p.next!=null){
p= p.next.next;
q= q.next;
if(p == q){
p = pHead;
while(p!=q){
p = p.next;
q = q.next;
}
return p;
}
}
return null;
}
}
55.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead == null || pHead.next == null) return pHead;
ListNode n = new ListNode(0);
ListNode p = pHead;
ListNode pre = n;
n.next = p;
boolean flag = true;
while(p!=null){
ListNode q = p.next;
if(q == null) break;
if(p.val == q.val){
while(q!=null&&q.val == p.val){
q = q.next;
}
pre.next = q;
p = q;
}else{
if(flag){
n.next = p;
flag = false;
}
pre = p;
p = q;
}
}
return n.next;
}
}
56.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode == null) return pNode;
if(pNode.right!=null){
pNode = pNode.right;
while(pNode.left!=null)
pNode = pNode.left;
return pNode;
}
while(pNode.next!=null){
if(pNode.next.left ==pNode) return pNode.next;
pNode = pNode.next;
}
return null;
}
}
57.请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{ if(pRoot == null)return true;
TreeNode node = mirror(pRoot);
return isSymmetrical( pRoot, node) ;
}
boolean isSymmetrical(TreeNode pRoot,TreeNode node){
if(pRoot==null&&node==null)return true;
if((pRoot==null&&node!=null)||(pRoot!=null&&node==null)) return false;
if(pRoot.val != node.val) return false;
return isSymmetrical(pRoot.left,node.left)&&isSymmetrical(pRoot.right,node.right);
}
TreeNode mirror(TreeNode pRoot){
if(pRoot == null) return null;
TreeNode node = new TreeNode(pRoot.val);
node.left = mirror(pRoot.right);
node.right = mirror(pRoot.left);
return node;
}
}
58.请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list2 = new ArrayList();
if(pRoot == null) return list;
Deque<TreeNode> que = new LinkedList();
boolean flag = true;
que.add(pRoot);
int size = 1;
int count = 0;
while(!que.isEmpty()){
if(flag){
TreeNode p = que.poll();
count++;
list2.add(p.val);
if(p.left!=null){
que.add(p.left);
}
if(p.right!=null){
que.add(p.right);
}
}else{
TreeNode p = que.pollLast();
count++;
list2.add(p.val);
if(p.right!=null){
que.addFirst(p.right);
}
if(p.left!=null){
que.addFirst(p.left);
}
}
if(count == size){
list.add(list2);
list2 = new ArrayList();
flag = (flag == true)?false:true;
count = 0;
size = que.size();
}
}
return list;
}
}
59.从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot){
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list2 = new ArrayList();
if(pRoot == null) return list;
Deque<TreeNode> que = new LinkedList();
int count =0;
int size = 1;
que.add(pRoot);
while(!que.isEmpty()){
TreeNode p = que.poll();
list2.add(p.val);
count++;
if(p.left!=null){
que.add(p.left);
}
if(p.right!=null){
que.add(p.right);
}
if(count == size){
list.add(list2);
list2 = new ArrayList();
size = que.size();
count = 0;
}
}
return list;
}
}
60.请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
public class Solution {
String Serialize(TreeNode root) {
if(root == null) return "";
StringBuilder sb = new StringBuilder();
Serialize2(root,sb);
return sb.toString();
}
public void Serialize2(TreeNode root,StringBuilder sb){
if(root == null) {
sb.append("#,");
return;
}
sb.append(root.val).append(",");
Serialize2(root.left,sb);
Serialize2(root.right,sb);
}
int index = -1;
TreeNode Deserialize(String str) {
if(str =="" || str.length()==0) return null;
String [] strs = str.split(",");
return Deserialize2(strs);
}
public TreeNode Deserialize2(String [] strs){
index++;
if(!strs[index].equals("#")){
TreeNode node = new TreeNode(Integer.parseInt(strs[index]));
node.left = Deserialize2(strs);
node.right = Deserialize2(strs);
return node;
}
return null;
}
}
61.给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4
public class Solution {
TreeNode KthNode(TreeNode pRoot, int k)
{
if(pRoot == null ||k<=0) return null;
TreeNode[] result = new TreeNode[1];
KthNode(pRoot,k,new int[1],result);
return result[0];
}
void KthNode(TreeNode pRoot,int k,int []count,TreeNode[] result){
if(result[0]!=null || pRoot == null) return ;
KthNode(pRoot.left,k,count,result);
count[0]++;
if(count[0]==k){
result[0] = pRoot;
}
KthNode(pRoot.right,k,count,result);
}
}
62.如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
import java.util.*;
public class Solution {
private int count = 0;
private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
public void Insert(Integer num) {
if (count %2 == 0) {//当数据总数为偶数时,新加入的元素,应当进入小根堆
//(注意不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆)
//1.新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素
maxHeap.offer(num);
int filteredMaxNum = maxHeap.poll();
//2.筛选后的【大根堆中的最大元素】进入小根堆
minHeap.offer(filteredMaxNum);
} else {//当数据总数为奇数时,新加入的元素,应当进入大根堆
//(注意不是直接进入大根堆,而是经小根堆筛选后取小根堆中最大元素进入大根堆)
//1.新加入的元素先入到小根堆,由小根堆筛选出堆中最小的元素
minHeap.offer(num);
int filteredMinNum = minHeap.poll();
//2.筛选后的【小根堆中的最小元素】进入大根堆
maxHeap.offer(filteredMinNum);
}
count++;
}
public Double GetMedian() {
if (count %2 == 0) {
return new Double((minHeap.peek() + maxHeap.peek())) / 2;
} else {
return new Double(minHeap.peek());
}
}
}
63.给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> list = new ArrayList<Integer>();
if(num ==null || num.length == 0 || size<=0) return list;
ArrayDeque<Integer> deque = new ArrayDeque();
int begin;
for(int i = 0;i<num.length;i++){
begin = i - size +1;
if(deque.isEmpty()){
deque.add(i);
}else if(begin > deque.getFirst()){
deque.pollFirst();
}
while(!deque.isEmpty()&& num[deque.getLast()]<=num[i]){
deque.pollLast();
}
deque.add(i);
if(begin>=0){
list.add(num[deque.peekFirst()]);
}
}
return list;
}
}
64.请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
if(matrix == null || matrix.length == 0|| rows<=0|| cols<=0|| str == null ||str.length == 0) return false;
boolean [] visited = new boolean[rows*cols];
int [] pathLength = new int[1];
for(int i=0;i<rows;i++){
for(int j = 0;j<cols;j++){
if(hasPath(matrix,rows,cols,str,i,j,visited,pathLength)) return true;
}
}
return false;
}
public boolean hasPath(char[] matrix,int rows,int cols,char[] str,int row,int col,boolean[] visited,int [] pathLength){
if(pathLength[0] == str.length) return true;
boolean flag = false;
if(row>=0&&row<rows&&col>=0&&col<cols&&!visited[row*cols+col]&&matrix[row*cols+col]==str[pathLength[0]]){
pathLength[0]++;
visited[row*cols+col] = true;
flag = hasPath(matrix,rows,cols,str,row+1,col,visited,pathLength)||
hasPath(matrix,rows,cols,str,row-1,col,visited,pathLength)||
hasPath(matrix,rows,cols,str,row,col+1,visited,pathLength)||
hasPath(matrix,rows,cols,str,row,col-1,visited,pathLength);
if(!flag){
pathLength[0]--;
visited[row*cols+col] = false;
}
}
return flag;
}
}
65.地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
if(threshold<0|| rows<= 0||cols<=0) return 0;
boolean [] visited = new boolean[rows*cols];
int count = 0;
return movingCount(threshold,rows,cols,0,0,visited);
}
public int movingCount(int threshold,int rows,int cols,int row,int col,boolean [] visited){
if(row>=0&&row<rows&&col>=0&&col<cols&&!visited[row*cols+col]&&checked(threshold,row,col)){
visited[row*cols+col] = true;
return 1+movingCount(threshold,rows,cols,row+1,col,visited)+
movingCount(threshold,rows,cols,row-1,col,visited)+
movingCount(threshold,rows,cols,row,col+1,visited)+
movingCount(threshold,rows,cols,row,col-1,visited);
}
return 0;
}
public boolean checked(int threshold,int row,int col){
int sum = 0;
while(row!=0){
sum+= row%10;
row = row/10;
}
while(col!=0){
sum+=col%10;
col=col/10;
}
if(sum>threshold) return false;
return true;
}
}
66.给你一根长度为n的绳子,请把绳子剪成m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入描述:
输入一个数n,意义见题面。(2 <= n <= 60)
输出答案。
示例1
输入
8
输出
18
class Solution {
public:
int cutRope(int number) {
if(number==2)
return 1;
if(number==3)
return 2;
int x=number%3;
int y=number/3;
if(x==0)
return pow(3,y);
else if(x==1)
return 2*2*(int)pow(3,y-1);
else
return 2*pow(3,y);
}
};