25.在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
public class Solution {
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
// Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
// 这里要特别注意~返回任意重复的一个,赋值duplication[0]
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
public boolean duplicate(int numbers[],int length,int [] duplication) {
for(int i=0;i<length;i++){
int index = numbers[i];
if(index>=length){
index-=length;
}
if(numbers[index]>=length){
duplication[0]=index;
return true;
}
numbers[index] = numbers[index]+length;
}
return false;
}
}
解析:本题要利用好题中的条件以减少时间复杂度("在一个长度为n的数组里的所有数字都在0到n-1的范围内")首先取出一个数,以这个数作为角标的位置上的数+length,当遇到某个数比数组长度大时就存入duplication[]
26.给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
import java.util.ArrayList;
public class Solution {
public int[] multiply(int[] A) {
int [] B = new int [A.length];
B[0]=1;
if(A.length!=0){
for(int i=1;i<A.length;i++){
B[i]=B[i-1]*A[i-1];
}
int temp=1;
for(int i=A.length-2;i>=0;i--){
temp*=A[i+1];
B[i]*=temp;
}
}
return B;
/*if(A.length==0){
return null;
}
int [] B = new int [A.length];
for(int i=0;i<B.length;i++){
B[i]=1;
for(int j=0;j<A.length;j++){
if(j==i){
continue;
}else{
B[i]*=A[j];
}
}
}
return B;*/
}
}
解析:如下图,为了减少复杂度,思路是先算正方形的左下半部分,再算右上半部分
27.请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
public class Solution {
public boolean match(char[] str, char[] pattern)
{
if(str==null||pattern==null){
return false;
}
int sindex=0;
int pindex=0;
return Match(str,sindex,pattern,pindex);
}
public boolean Match(char[] str,int sindex,char[] pattern,int pindex){
if(sindex==str.length&&pindex==pattern.length){
return true;
}
if(sindex!=str.length&&pindex==pattern.length){
return false;
}
if(pindex+1<pattern.length&&pattern[pindex+1]=='*'){当前要匹配的pattern中的字符的后面是"*"的情况
//如果当前匹配的字符是‘.’或者两个字符相等的情况,就会分为三种情况,sindex后挪,或者pindex后挪,或者dounuo
if((sindex!=str.length&&str[sindex]==pattern[pindex])||(sindex!=str.length&&pattern[pindex]=='.')){
return Match(str,sindex,pattern,pindex+2)||
Match(str,sindex+1,pattern,pindex+2)||
Match(str,sindex+1,pattern,pindex);
}
//如果不匹配的话就相当于把'*'用掉了,就直接pindex后挪
else{
return Match(str,sindex,pattern,pindex+2);
}
}
//如果当前正在验证的字符后面不是'*',如果当前字符匹配则都后挪,否则直接返回false
if((sindex!=str.length&&str[sindex]==pattern[pindex])||(str.length!=sindex&&pattern[pindex]=='.')){
return Match(str,sindex+1,pattern,pindex+1);
}
return false;
}
}
解析:见代码中的注释。
28.一个链表中包含环,请找出该链表的环的入口结点。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead==null||pHead.next==null){
return null;
}
ListNode p1=pHead;
ListNode p2=pHead;
int pp1=2;
int pp2=1;
p1=p1.next;
p1=p1.next;
p2=p2.next;
while(p1!=p2){
p1=p1.next;
p1=p1.next;
p2=p2.next;
pp1+=2;
pp2++;
}
int n = pp1-pp2;
p1=pHead;
p2=pHead;
for(int i=0;i<n;i++){
p1=p1.next;
}
while(p1!=p2){
p1=p1.next;
p2=p2.next;
}
return p1;
}
}
解析:p1,p2都指向表头,pp1,pp2分别记录两者的步数,p1走两步,p2走一步,当p1,p2相遇时就说明p1,p2都在圈里并且p1已经比p2多走一圈了,这时候pp1-pp2就是一圈的长度,再重新指向表头,这次让p1先走一圈的长度,然后一起一步一步向后走,当到了相同节点是就是要找的节点。
29.请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null){
return true;
}
return test(pRoot.left,pRoot.right);
}
boolean test(TreeNode left,TreeNode right){
if(left==null) return right==null;
if(right==null) return false;
if(left.val!=right.val) return false;
return test(left.right,right.left)&&test(left.left,right.right);
}
}
解析:利用递归,注意test()中的参数就可以30.请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
import java.util.ArrayList;
import java.util.Stack;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> listall=new ArrayList<ArrayList<Integer>>();
if(pRoot==null){
return listall;
}
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> s1 = new Stack<TreeNode>();
Stack<TreeNode> s2 = new Stack<TreeNode>();
int flag=0;//flag=0从左往右输出,从右往左压栈
s1.push(pRoot);
while(s1.size()>0){
TreeNode temp = s1.pop();
list.add(temp.val);
if(flag==1){
if(temp.right!=null){
s2.push(temp.right);
}
if(temp.left!=null){
s2.push(temp.left);
}
}else{
if(temp.left!=null){
s2.push(temp.left);
}
if(temp.right!=null){
s2.push(temp.right);
}
}
if(s1.size()==0){
flag=1-flag;
Stack<TreeNode> t = s1;
s1=s2;
s2=t;
//s1=s2;
//s2.clear();
listall.add(new ArrayList<Integer>(list));
list.clear();
}
}
return listall;
}
}
解析:其实可以用reverse(),但是还是需要考虑复杂度的问题,所以这个用两个栈就可以解决,先把第一层压栈,因为第二层要从右往左输出,所以要先将左子树后右子树压s2栈,当s1空时,s1=s2,继续将s1中结点的字数压栈,通过flag来标记应该从左往右还是从右往左,以此类推。
31.请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[a b c e s f c s a d e e]是3*4矩阵,其包含字符串"bcced"的路径,但是矩阵中不包含“abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
int [] flag = new int[matrix.length];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(Test(matrix,rows,cols,i,j,str,0,flag)){
return true;
}
}
}
return false;
}
//matrix就是题中的[a b c e s f c s a d e e],rows,cols是行和列,str就是题中的"bcced",k是str的角标 ,flag用来标记该点走没走过
public boolean Test(char[] matrix,int rows,int cols,int i,int j,char[] str,int k,int[] flag){
int index = i*cols+j;
//如果走过或者值不相等就返回false
if(i<0||i>=rows||j<0||j>=cols||str[k]!=matrix[index]||flag[index]==1){
return false;
}
if(k==str.length-1){
return true;
}
//标记该点已经走完了
flag[index]=1;
//然后检查四周是否有和下个字符匹配的点
if(Test(matrix,rows,cols,i+1,j,str,k+1,flag)||
Test(matrix,rows,cols,i-1,j,str,k+1,flag)||
Test(matrix,rows,cols,i,j+1,str,k+1,flag)||
Test(matrix,rows,cols,i,j-1,str,k+1,flag)){
return true;
}
//递归结束后,要删除这个点,即标记这个点没有到过,是一种回溯思想,以为这个点并不是想要的点
flag[index]=0;
return false;
}
}
解析:见代码的注释