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; } }解析:见代码的注释