近日,某乎上出现了一大部分腾讯还未发表出来的面试题,大多以算法为主,而且这些面试题经证实,确实是腾讯在拟还为发表的面试题目,一时间,某乎上瞬间就炸开了锅。
经查证,是腾讯某技术部的程序员私自泄露给他的一个好友的,然后他好友竟然将其上传到自己的技术博客上来博取关注,虽然事情及时止损,并没有造成严重后果,博主也及时删除了该帖,但是按照腾讯的性格,该程序员被劝退,并且被要求赔偿,具体的事情还在商议。
虽然该帖被删除了,但是有心之人已经将该面试题保存下来了,这也是我费了很大的心里才找到的,下面我也会分享给大家,虽然该面试题已经被公开了,但是知道的人也是相对来说比较少的,也有想当的借鉴意义,起码能够知道腾讯接下来面试所考核的方面。
关于算法方面
关于泄露出来的面试题因为篇幅原因没有全部上传,有需要的可以上Github自行领取哦
题目:
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
分析:
根据题意画了个简单的图,首先我们要确定查找开始的位置,因为它是二维的数组,它的下标变化是两个方向的,根据四个边界点来分析。
a b
c d
A:向下 增 ,向右 增
B:向左 减 ,向下 增
C:向上 减 ,向右 增
D:向左 减 ,向上 减
可以看出从B 或C点开始查找刚好可以构建一个二叉查找树。
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
先确定二维数组的行数和列数,把 查找值 与 二叉查找树的根节点(B或者 C)开始比较,如果相等返回true,小于查找左子树,大于就查找右子树。如果遍历超过数组边界,就返回 false。
以C为根节点查找
public class Solution {
public boolean Find(int [][] array,int target) {
int i = array.length -1;
int m = array[0].length -1;
int j = 0;
while(i>=0 && j<=m){
if(target == array[i][j]){
return true;
}else if(target >array[i][j]){
j++;
}else{
i--;
}
}
return false;
}
}
以B为根节点查找
public class Solution {
public boolean Find(int [][] array,int target) {
int i = array.length -1;
int j = array[0].length -1;
int n = 0;
while(j>=0 && n<=i){
if(target == array[n][j]){
return true;
}else if(target >array[n][j]){
n++;
}else{
j--;
}
}
return false;
}
}
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
题目分析
解法一 运行时间:29m 占用内存:629k
public int NumberOf1(int n) {
String s=Integer.toBinaryString(n);
char[] c=s.toCharArray();
int j=0;
for(int i=0;i<c.length;i++){
if(c[i]=='1'){
j++;
}
}
return j;
}
}
解析:
public static String toBinaryString(int i)
以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。
①先把整数转换成二进制字符串
②把字符串转换成字符数组
③遍历该数组,判断每位是否为1,为1 计数加1。
④遍历完成返回1的个数
解法二 运行时间:30ms 占用内存:629k
public class Solution {
public int NumberOf1(int n) {
int count =0;
while(n!=0){
count++;
n = n&(n-1);
}
return count;
}
}
解析:
如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
举个例子:
①二进制数 1100
② 减1后,得 1011
③1100&1011=1000
对比①和③你会发现,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
import java.util.Stack;
public class Solution {
Stack<Integer> stack = new Stack<Integer>();
Stack<Integer> min = new Stack<Integer>();
public void push(int node) {
stack.push(node);
if(min.isEmpty()){
min.push(node);
}else{
if (node <= min.peek()) {
min.push(node);
}
}
}
public void pop() {
if (stack.peek() == min.peek()) {
min.pop();
}
stack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return min.peek();
}
}
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
输入描述
str 是StringBuffer的对象
输出描述
返回替换后的字符串的String对象
题目分析
首先要对输入参数进行判空和越界判断(任何算法题都要注意)。
解法一 (运行时间:36ms 占用内存:688k)
public class Solution {
public String replaceSpace(StringBuffer str) {
if(str==null){
return null;
}
StringBuffer sb = new StringBuffer();
char [] strChar = str.toString().toCharArray();
for(int i=0;i<strChar.length;i++){
if(strChar[i]==' '){
sb.append("%20");
}else{
sb.append(strChar[i]);
}
}
return sb.toString();
}
}
把传入的StringBuffer 对象 str 转换成字符串 再转换成字符数组,申请一个新的StringBuffer 对象 sb来存最后的结果,遍历整个字符数组,如果当前字符为空格则把 "%20"加入到sb中,否则直接追加当前字符,最后把sb转换成字符串返回。
解法二 (运行时间:34ms 占用内存:503k)
public class Solution {
public String replaceSpace(StringBuffer str) {
if(str == null){
return null;
}
for(int i =0;i<str.length();i++){
char c = str.charAt(i);
if(c==' '){
str.replace(i,i+1,"%20");
}
}
return str.toString();
}
}
public StringBuffer replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。该子字符串从指定的 start 处开始,一直到索引 end - 1 处的字符,如果不存在这种字符,则一直到序列尾部。先将子字符串中的字符移除,然后将指定的 String 插入 start。(如果需要,序列将延长以适应指定的字符串。)参数:start - 起始索引(包含)。end - 结束索引(不包含)。str - 将替换原有内容的字符串。返回:此对象。
源码(可以看出它调用的是父类的方法)
public synchronized StringBuffer More ...replace(int start, int end, String str){
toStringCache = null;
super.replace(start, end, str);
return this;
}
父类AbstractStringBuilder
public AbstractStringBuilder More ...replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end");
if (end > count)
end = count;
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);
System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
count = newCount;
return this;
}
可以看出StringBuffer类 提供了 插入的函数,值得注意的是 StringBuilder 也是继承于AbstractStringBuilder这个抽象类的。所以它也有这个方法,但是String并没有。
解法三(不推荐,运行时间:38ms 占用内存:654k)
public class Solution {
public String replaceSpace(StringBuffer str) {
return str.toString().replaceAll("\\s", "%20");
}
}
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。
输入描述
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
输出描述
顺序输出字符串的所有排列
题目分析
这是一个字符串全排列的问题,把全部序列存在TreeSet中默认可得到字典顺序。
TreeSet 基于TreeMap实现的SortedSet,可以对Set集合中的元素进行排序,排序后按升序排列元素(缺省是按照自然排序),非线程安全。
思路:
固定一个字符串之后,之后再将问题变小,只需求出后面子串的排列个数就可以得出结果,然后依次将后面的字符串与前面的交换,再递归子串的排列结果,最后当所有字符都固定结束递归。
下面这张图很清楚的给出了递归的过程:
解法 运行时间:131ms 占用内存:1477k
import java.util.*;
public class Solution {
//用于最后返回结果
ArrayList<String> list = new ArrayList<>();
//遍历的时候来存储序列实现排序
TreeSet<String> set = new TreeSet<>();
public ArrayList<String> Permutation(String str) {
if(str==null || str.length()==0) return list;
Permutation(str.toCharArray(),0);
//容器转换,TreeSet中的元素已经是按照字母顺序排序,所以这里做了排序
list.addAll(set);
return list;
}
public void Permutation(char[] s,int index){
if(s==null ||s.length==0 || index<0 || index>s.length-1) return ;
if(index==s.length-1){//递归固定到最后一个位置,把该串加入集合
// set不能添加重复元素,所以这里的add()解决了有重复字符的问题
set.add(new String(s));
}else{//固定前index+1个字符,递归后面所有可能的子串
for(int i = index;i<s.length;i++){
swap(s,index,i);//交换一次形成一个子串
Permutation(s,index+1);
swap(s,i,index);//复原使下次循环产生下一个子串
}
}
}
public void swap(char[] s,int i,int j){
char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
其他的面试题我也有收集,最新的技术,类似于Flutter,KT,Jetpack+mvvm.....有需要的小伙伴可以上Github自行领取哦