剑指offer习题JAVA实现(四)

1. 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
         ArrayList<ArrayList<Integer>> alist=new ArrayList<ArrayList<Integer>>();
	   for(int i=0;i<array.length;i++){
		   ArrayList<Integer> list=new ArrayList<Integer>();
		   for(int j=i+1;j<array.length;j++){ 
			   if(array[i]+array[j]==sum){
				   list.add(array[i]);
				   list.add(array[j]);
				   list.add(array[i]*array[j]);
			   }
			   if(!list.isEmpty())
				   alist.add(list);
		   }
			   
	   }
	   if(alist.size()==0) return new ArrayList<Integer>();
	   Collections.sort(alist, new Comparator<ArrayList<Integer>>(){

		@Override
		public int compare(ArrayList<Integer> a, ArrayList<Integer> b) {
			// TODO Auto-generated method stub
			return a.get(2).compareTo(b.get(2));
		}
		   
	   });
	   ArrayList<Integer> asd=alist.get(0);
	   ArrayList<Integer> tem=new ArrayList<Integer>();  
	   for(int i=0;i<asd.size()-1;i++){
		   tem.add(asd.get(i));
	   }
	   return tem;
    }
}
2. 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
public class Solution {
    public String LeftRotateString(String str,int n) {
       if(str.length()==0) return "";
        ArrayList alist=new ArrayList();
		ArrayList blist=new ArrayList();
		ArrayList clist=new ArrayList();
		char a[]=str.toCharArray();
		n=n%str.length();
		for(int i=0;i<n;i++){
			alist.add(a[i]);
		}
		for(int i=n;i<str.length();i++){
			blist.add(a[i]);
		}
		for(int i=0;i<blist.size();i++){
			clist.add(blist.get(i));
		}
		for(int i=0;i<alist.size();i++){
			clist.add(alist.get(i));
		}
		char pp[]=new char[clist.size()];
		for(int i=0;i<clist.size();i++){
			pp[i]=(char) clist.get(i);
		}
		return String.copyValueOf(pp);
    }
}

3.牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

public class Solution {
    public String ReverseSentence(String str) {
        if(str==null) return null;
		 if(str.trim().equals(""))
			 return str;
		 String []strs=str.split(" ");
		 StringBuilder sb=new StringBuilder();
		 for(int i=strs.length-1;i>=0;i--){
			 if(i==0){
				 sb.append(strs[i]);
				 
			 }else{
				 sb.append(strs[i]);
				 sb.append(" ");
			 }		 
		 }
		 String str2=sb.toString();
		 return str2;
    }
}
4. LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。

public class Solution {
    public boolean isContinuous(int [] numbers) {
		if(numbers==null||numbers.length>5||numbers.length<5) return false;
		 int zero=0;
		 int result=0;
		 Arrays.sort(numbers);
		 for(int i=0;i<numbers.length;i++){
			 if(numbers[i]==0)
				 zero++;
		 }
		 int start=zero;
		 int end=zero+1;
		 while(end<numbers.length){
			if(numbers[start]==numbers[end]){
				return false;
			}
			result +=numbers[end]-numbers[start]-1;			 
			 start++;
			 end++;
		 }
		 if(result<=zero){
			 return true;
		 }else{
		 	return false;
		 }
    }
}
5. 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
public class Solution {
    public int LastRemaining_Solution(int n, int m) {//经典的约瑟夫环问题,数组解法
        int a[]=new int[n];
		int i=-1;
		int step=0;
		int count=n;
		while(count>0){
			i++;
			if(i>=n)i=0;
			if(a[i]==-1) continue;
				step++;
				if(step==m){
					a[i]=-1;
					step=0;
					count--;
				}
			}
			return i;
		}
    }
6. 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0 
public class Solution {
    public int StrToInt(String str) {
       if(str.equals("")||str.length()==0) return 0;
	     int sum=0;
	     int f=0;
	     char []nums=str.toCharArray();
	     if(nums[0]=='-') 
	    	 f=1;
	     for(int i=f;i<str.length();i++){
	    	 if(nums[i]=='+') continue;
	    	 if(nums[i]<48||nums[i]>57) return 0;
	    	 sum=sum*10+nums[i]-48;
	     }
	     return f==0?sum:sum*-1;
	 }
	 
}
7. 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length==0||numbers==null){
            duplication[0]=-1;
            return false;
        }
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<numbers.length;i++){
            if(!map.containsKey(numbers[i])){
                map.put(numbers[i],1);
            }else{
                int count=map.get(numbers[i]);
                map.put(numbers[i],count+1);
            }
        }
        for(int i=0;i<length;i++){
            int a=map.get(numbers[i]);
            if(a>1){
                duplication[0]=numbers[i];;
                return true;
                 
            }
        }
        return false;
    }
}
8. 给定一个数组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]。不能使用除法。
public class Solution {
    int[] multiply(int[] A) {
        int len = A.length;
        int forword[] = new int[len];
        int backword[] = new int[len];
        int B[] = new int[len];
        forword[0] = 1;
        backword[0] = 1;
        for(int i = 1;i < len; i++){
            forword[i] = A[i - 1]*forword[i-1];
            backword[i] = A[len - i]*backword[i - 1];
        }
        for(int i = 0; i < len; i++){
            B[i] = forword[i] * backword[len - i -1];
        }
        return B;
    }
}
9. 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。 
public class Solution {
    int a[]=new int[256];
	StringBuilder str=new StringBuilder();
    public void Insert(char ch)
    {
     str.append(ch);
     if(a[ch]==0)
    	 a[ch]=1;
     else
    	 a[ch]+=1;
    }
    public char FirstAppearingOnce()
    {
    	char ss='#';
    	char[]pp=str.toString().toCharArray();
    	for(char p:pp){
    		if(a[p]==1) 
    			return p;
    	}
    	return ss;
    }
}
10. 一个链表中包含环,请找出该链表的环的入口结点。
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
       if(pHead==null||pHead.next==null) return null;
    	ListNode p1=pHead;
    	ListNode p2=pHead;
    	while(p1!=null&&p2!=null){
    		p1=p1.next;
    		p2=p2.next.next;
    		if(p1==p2){
    			p1=pHead;
    			while(p1!=p2){
    				p1=p1.next;
    				p2=p2.next;
    			}
    			return p1;
    		}
    	}
    	return null;
    }
}
11. 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
		ListNode prepHead;
		ListNode index=new ListNode(1);
		ListNode temp=pHead;
		index.next=pHead;
		prepHead=index;
		while(temp!=null){
			if(temp.next!=null&&temp.next.val==temp.val){
				while(temp.next!=null&&temp.next.val==temp.val){
					temp=temp.next;
				}
				temp=temp.next;
				index.next=temp;
			}else{
				temp=temp.next;
				index=index.next;
			}
		}
		return prepHead.next;
	}
}

12.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

思路:这道题目只有三种情况:

(1)二叉树为空,返回为空

(2)节点的右孩子存在,从该节点的右孩子出发,沿左子节点一直找到其叶子节点

(3)节点不是根节点,节点是父节点的左孩子,则返回父节点;

节点是父节点的右孩子,则向上遍历父节点的父节点

public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
         if(pNode==null) return null;
        if(pNode.right!=null){
        	TreeLinkNode dd=pNode.right;
        	while(dd.left!=null){
        		dd=dd.left;
        	}
        	return dd;
        }
        while(pNode.next!=null){
        	if(pNode.next.left==pNode) return pNode.next;
        	pNode=pNode.next;
        }
        return null;
    }
}

13.请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

public class Solution {
   boolean isSymmetrical(TreeNode pRoot)
    {
       return fff(pRoot,pRoot);
    }
    boolean fff(TreeNode n1,TreeNode n2){
    	if(n1==null&&n2==null) 
            return true;
        if(n1==null||n2==null)
            return false;
        if(n1.val!=n2.val)
            return false;
        return fff(n1.left,n2.right)&&fff(n1.right,n2.left);
    }
}
14. 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
      
		ArrayList<ArrayList<Integer>> alist=new ArrayList<ArrayList<Integer> >();  if(pRoot==null) return alist;
    	Stack <TreeNode>a1=new Stack<TreeNode>();
    	a1.add(pRoot);
    	Stack <TreeNode>a2=new Stack<TreeNode>();
    	while(!a1.isEmpty()||!a2.isEmpty()){
    		if(!a1.isEmpty()){
    			ArrayList <Integer>list=new ArrayList<Integer>();
    			while(!a1.isEmpty()){
    				TreeNode p1=(TreeNode) a1.pop();
    				list.add(p1.val);
    				if(p1.left!=null)
    					a2.add(p1.left);
    				if(p1.right!=null)
    					a2.add(p1.right);
    			
    			}
    			alist.add(list);
    		}else{
    			ArrayList <Integer>list=new ArrayList<Integer>();
    			while(!a2.isEmpty()){
    				TreeNode p1=(TreeNode) a2.pop();
    				list.add(p1.val);
    				if(p1.right!=null)
    					a1.add(p1.right);
    				if(p1.left!=null)
    					a1.add(p1.left);
    		}
    		alist.add(list);
    	}
    	
    }
		return alist;
    }

}
15. 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
    	ArrayList<ArrayList<Integer>> alist=new  ArrayList<ArrayList<Integer>>();
        if(pRoot==null) return alist;
    	 ArrayList<Integer> list=new ArrayList<Integer>();
    	 Deque<TreeNode> deque=new LinkedList<TreeNode>();
    	 deque.add(pRoot);
    	 int start=0;int end=1;
    	 while(!deque.isEmpty()){
    		 TreeNode current=deque.remove();
    		 list.add(current.val);
    		 start++;
    		 if(current.left!=null){
    			 deque.add(current.left);
    		 }
    		 if(current.right!=null){
    			 deque.add(current.right);
    		 }
    		 if(start==end){
    			 start=0;
    			 end=deque.size();
    			 alist.add(list);
    			 list=new ArrayList<Integer>();
    		 }
    	 }	
    	 return alist;
    }
    
}
16. 请实现两个函数,分别用来序列化和反序列化二叉树

public class Solution {
  String Serialize(TreeNode root) {
        if(root == null)
            return "";
        StringBuilder sb = new StringBuilder();
        Serialize2(root, sb);
        return sb.toString();
    }
     
    void Serialize2(TreeNode root, StringBuilder sb) {
        if(root == null) {
            sb.append("#,");
            return;
        }
        sb.append(root.val);
        sb.append(',');
        Serialize2(root.left, sb);
        Serialize2(root.right, sb);
    }
     
    int index = -1;
     
    TreeNode Deserialize(String str) {
        if(str.length() == 0)
            return null;
        String[] strs = str.split(",");
        return Deserialize2(strs);
    }  
     
    TreeNode Deserialize2(String[] strs) {
        index++;
        if(!strs[index].equals("#")) {
            TreeNode root = new TreeNode(0);     
            root.val = Integer.parseInt(strs[index]);
            root.left = Deserialize2(strs);
            root.right = Deserialize2(strs);
            return root;
        }
        return null;
    }
}
17. 给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4

public class Solution {
    LinkedList list=new LinkedList();
	void mid(TreeNode root){
		if(root==null)
			return ;
		mid(root.left);
		list.add(root);
		mid(root.right);
	}
   TreeNode KthNode(TreeNode pRoot, int k)
    {
		if(k<=0||pRoot==null)
			return null;
        mid(pRoot);
       if(k>list.size())
           return null;
        for(int i=0;i<=list.size();i++){
        	if((i+1)==k)
        		return (TreeNode) list.get(k-1);
        }
		return null;   
    }
}
18. 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
public class Solution {
    ArrayList<Integer> list=new ArrayList<Integer>();
	public void Insert(Integer num) {		
		list.add(num);
		Collections.sort(list);
    }
    public Double GetMedian() {
        double mid;
        int midindex=list.size()/2;
        if(list.size()%2==0){
        	mid=(double)(list.get(midindex)+list.get(midindex-1))/2;
        }else{
        	mid=list.get(midindex);
        }
        return mid;
    }
}
19. 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> list=new ArrayList<Integer>();
              if(size==0) return list;
       for(int i=0;i<num.length-size+1;i++){
    	   ArrayList<Integer> temp=new ArrayList<Integer>();
    	   for(int j=0;j<size;j++){
    		   temp.add(num[i+j]);
    	   }
    	   int tt=max(temp);
    	   list.add(tt);
       }
       return list;
    }
	public int max(ArrayList list){
		int max=-1;
		for(int i=0;i<list.size();i++){
			int mm=(Integer)list.get(i);
			if(mm>max){
				max=mm;
			}
		}
		return max;
	}
}
20. 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[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(helper(matrix,rows,cols,i,j,str,0,flag))
					return true;
			}
		}
		return false;
	}
	public boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag){
		int index=i*cols+j;
		if(i<0||i>=rows||j<0||j>=cols||matrix[index]!=str[k]||flag[index]==1){
			return false;
		}
		flag[index]=1;
        if(k==str.length-1) return true;
		if(helper(matrix, rows,cols,  i+1,  j, str,k+1, flag)||
				helper(matrix, rows,cols,  i-1,  j, str,k+1, flag)||
				helper(matrix, rows,cols,  i,  j+1, str,k+1, flag)||
				helper(matrix, rows,cols,  i,  j-1, str,k+1, flag)
		)return true;
		
		flag[index]=0;
		return false;

	}
}
21. 地上有一个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 static void main(String[]args){
		System.out.println(movingCount(5,10,10));
	}
	public static int movingCount(int threshold, int rows, int cols)
	{
		boolean flag[]=new boolean[rows*cols];
		for(int i=0;i<flag.length;i++){
			flag[i]=false;
		}
		return movingcount(threshold, rows, cols, 0, 0, flag);

	}
	public static int movingcount(int threshold,int rows,int cols,int row,int col,boolean flag[]){
		if(rows<=0||cols<=0||row>rows||col>cols)
			return 0;
		if(row<0||row>=rows||col<0||col>=cols) return 0;
        int i=row*cols+col;
        if(flag[i]||!checksum(threshold,row,col)) return 0;
        flag[i]=true;
		return 1+movingcount(threshold,rows,cols, row-1, col, flag)+movingcount(threshold,rows,cols, row+1, col, flag)+
		movingcount(threshold,rows,cols, row, col-1, flag)+movingcount(threshold,rows,cols, row, col+1, flag);

	}
	public static boolean checksum(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;
	}
}
20,21题目利用的方法是“回溯法”,利用其递归特性,路径被当做是一个栈。当在矩阵中定位了路径中的前n个字符位置之后,在与第n个字符对应的格子周围没有找到n+1的字符,这时候就回到第n-1个字符,重新定位第n个字符。

回溯法经典问题:八皇后问题

(其他问题思考)

正则表达式源码写法;位运算;大数的加法和乘法;寻找二叉树最近公共祖先;各类查找算法


笔试面试要求的综合素质包括:编程能力,沟通能力,学习能力,发散思维能力,抽象建模能力,知识迁移能力等等。


















猜你喜欢

转载自blog.csdn.net/qq_31278903/article/details/71324995