《牛客网 剑指Offer前20题》

牛客网 前20道题

前言知识

  1. 优秀的程序员首先要有良好的基本功,基本功在面试编程环境体现在编程语言、数据结构和算法
      编程语言:以C语言为例,例如把const加在指针不同位置有什么区别。主要考察对编程语言掌握程度。
      数据结构:要熟练掌握链表、树、栈、队列和哈希表等数据结构,对链表的插入和删除节点了如指掌,对二叉树的各种遍历方法和递归写法烂熟于心。
      算法:基本的查找、排序算法,重点掌握二分查找、归并排序、快速排序。

  2. 要注重代码的鲁棒性,可靠性,编写的任何函数要格外关注边界条件、特殊输入等看书细枝末节实则至关重要地方

  3. 要有清晰的思路,在解决复杂问题时,可以举举例子,试着用图像分析过程等。

  4. 要注重算法的复杂度,有提高优化效率的能力,例如求斐波那契数列数列,很多人喜欢用递归,但是递归的时间复杂度是以n的指数增加的,如果先求f(1)和f(2),复杂度是O(n)。只要熟知各种数据结构的优缺点,才能选择合适的数据结构解决问题。

    剑指Offer中采用C++和C#来编程,我只能用C、java语言实现。
    https://www.nowcoder.com/ta/coding-interviews

面试题1:二维数组中的查找

题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:由于每行从左到右递增,每列从上到下递增,所以选取数组右上角的数字,如果该数字等于要查找的数字,结束查找过程。如果大于要查找的数字,剔除这个数字所在的列。如果小于要查找的数字,剔除这个数字所在的行。
我犯的错误:
1、二维数组赋值方式未掌握

	 int array[][] = new int[][]{
   {
   1,2,8,9},{
   2,4,9,12},{
   4,7,10,13},{
   6,8,11,15}};
	 int array[][] = {
   {
   1,2,8,9},{
   2,4,9,12},{
   4,7,10,13},{
   6,8,11,15}};

2、循环边界的判定
  
3、如何判断一个二维数组不为空,首先二维数组指针不能为空,其次若指针不为空,行长度不能为空,若行长度也不为空,那么列的长度也不能为空。array == null ||array.length == 0||(array.length == 1&&array[0].length == 0)
代码

public class Solution {
   
      public boolean Find(int target, int [][] array) {
   
	        boolean result = false;
	        if(array == null ||array.length == 0||(array.length == 1&&array[0].length == 0))
	        	return false;
	            int row = array.length ;
	            int column = array[0].length;
	            int i = 0,j = column-1;

	            while(i<row&&j>=0)
	            {
   
	                if(array[i][j] >target)
	                {
   
	                   j  --;
	                }
	                else if(array[i][j] <target)
	                {
   
	                    i ++;
	                }
	                else if(array[i][j] == target)
	                {
   
	                    result = true;
	                    break;
	                }
	            }	   
	        return result;        
	    }
}

面试题2:二维数组中的查找

题目:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 public String replaceSpace(StringBuffer str)
思路:1、最简单的方式,创建新的字符串,在新的字符串上,遇到空格就替换成“%20”。从前到后。
2、然而,面试官往往如果说在原来的字符串上替换,并且保证原来的字符串有足够的长度,此时就要先计算原有字符串的长度和空格的长度,则可以计算扩充后的字符串长度,那么从后往前遍历,遇到空格就替换成“%20”。

遇到的问题
1、对StringBuffer类的api不熟,传入的参数是StringBuffer str,傻傻的用str[i]来遍历,StringBuffer的类变量长度是length(),而不是像数组array.length。
2、charAt、deleteCharAt、函数不熟
3、初始化一个char[]字符数组:char[] insertChars = {’%’,‘2’,‘0’};
代码

public class Solution {
   
    	public String replaceSpace(StringBuffer str) {
   
    	if(str.length() == 0) return "";
    	int length = str.length();
    	int i = length - 1;
    	char[] insertChars = {
   '%','2','0'};
    	while(i>=0)
    	{
   
    		if(str.charAt(i) == ' '){
   
    			str.deleteCharAt(i);
    			str.insert(i, insertChars);
    			i --;
    		}
    		else
    		{
   
    			i--;
    		}
    	}
    	return str.toString();
    }
}

面试题3:从头到尾打印链表

题目:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
思路:如果我们遍历链表的话,只能从头到尾遍历,但是需要输出的是从尾到头。因此我们可以用栈来实现这种顺序,每经过一个结点时,把这个结点放到栈中,遍历完整个链表后,从栈顶开始输出,此时链表中的数据相当于反转了。

遇到的问题
1、根本没用过java中的Stack类,使用时要导入java.util.Stack;
2、对特殊的测试用例没有做出很好的处理,当传入的是链表结点时,判断结点是否存在相当于该链表是否存在
3、case通过率为9.09%,用例:{67,0,24,58},对应输出应该为:[58,24,0,67],你的输出为:[24,0,67],原因在于遍历链表时用while(listNode.next !=null){stack.push(listNode.val);}会将最后一个值忘记装入栈中,所以后面要补充。
代码

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
   
 public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
   
		ArrayList<Integer> arrayList = new ArrayList<>();
		if(listNode == null){
   
			return arrayList;
		}
        Stack<Integer> stack = new Stack<>();
        while(listNode.next != null)
        {
   
        	stack.push(listNode.val);
        	listNode = listNode.next;
        }
        stack.push(listNode.val);
        while(!stack.isEmpty())
        {
   
        	arrayList.add(stack.pop());
        }
        return arrayList;    
    }
}

面试题4:重建二叉树 *****

题目:输入某二叉树的前序遍历和中序遍历的结果int [] pre,int [] in,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路前序遍历的第一个数字就是根结点值,根据中序遍历的特点在根结点1前面的3个数字都是根结点左子树的值,位于1后面的都是根结点右子树的值。二叉树的构建是由很多个形如 /\ 的3个结点组成的最小二叉树从根结点开始由上往下构成,每次构建这样的最小二叉树getRootNode,关键在于根结点怎么确定?左子树结点、右子树结点如何确定?根结点为每次得到的前序遍历序列的第一个值TreeNode root= new TreeNode(preList[0])。得到根结点后开始构建左子树结点、右子树结点,显然左子树结点、右子树结点可以视为再下一层的子树新的根结点,root.left = getRootNode(左子树结点前序遍历序列,左子树中序遍历序列);root.left = getRootNode(右子树结点前序遍历序列,右子树中序遍历序列);
  如何去确定root.left = getRootNode(左子树结点前序遍历序列,左子树中序遍历序列);root.left = getRootNode(右子树结点前序遍历序列,右子树中序遍历序列);中的参数是最难之处。每次都是取前序遍历的第一个值作为最小二叉树的根结点,因此每次遍历只需判断传入的前序二叉树是否有效即可。左子树结点中序遍历序列 = inList.subList(0,index); 右子树结点的中序遍历序列 = inList.subList(index+1,inList.size()); 左子树结点前序遍历序列 = preList.subList(1,左子树结点遍历序列的长度)
右子树结点前序遍历序列 = preList.subList();
              在这里插入图片描述
        在这里插入图片描述
遇到的问题
1、数组如何用while遍历,原来想用while(array[i] != null)并不行,报错he operator != is undefined for the argument type(s) int, null,应该while(index<array.length) index++;用for遍历代码更简洁。
2、基本不能独立编完

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.ArrayList;
import java.util.List;
public class Solution {
   
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
   
        if(pre == null||in == null||pre.length == 0||in.length == 0)
        	return null;
        ArrayList<Integer> preList = new 
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值