多益的笔试题中只有一道编程题,难度中等,是《剑指offer》中的题目的变形,只要稍微认真读一下题目和看过题目的原型的话,做出来应该不会太难.
不过它给的时间有点少,我记得我当时做到编程的时候大概还有20分钟左右剩下,然后看了一下题目,一下子想不出来,就回去做了前面的题目,再回来做,就忽然记起来的,但是没有剩下多少时间了,只能写个解题思路就交了。当时没想到能过笔试,毕竟编程题都没有做出来。然后迷迷糊糊就进了面试。
面试前查了一下多益网络的面试流程之类的,发现只会有一次面试(当时看到时真不敢相信),而且是视频面试,当晚就有点紧张和兴奋了,毕竟这是第三次做笔试,才进面试了。面试面经就不说了,网上很多,而且自己应该没有过(面试中算法题答不上)
接下来进入正题吧,就想记录一下多益网络的笔试编程题和面试时遇到算法题,觉得出得挺好的。
找出数字字符串中指定位数的最小值。组合在原来字符串中的前后顺序不能变。
例如:有字符串"1230451",要求找出两位最小的顺序组合,则结果是1(是01的组合).
有字符串"123451",要求找出两位最小的顺序组合,则结果是11.
原型应该是《剑指offer》中的面试题28:字符串的排序中的拓展:
如果输入n个字符,则这n个字符能构成长度为1的组合、长度为2的组合、。。、长度为n的组合。求n个字符的所有的组合(所有长度)。答案
多益的这道题本质上跟《剑指offer》中的没有太大区别,只是加了一下字符串转整数之类的过程。
核心解题思路还是字符串的m位组合数,就是将字符串组合分为两部分:
第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在所剩余的n-1个字符里选取m个字符。如果组合里不包含第一个字符,则下一步在剩余的n-1个字符里选取m个字符。也就是说,我们可以把n个字符组成长度为m的组合问题分解为两个子问题,分别求n-1个字符串中长度为m-1的组合,以及求n-1个字符的长度为m的组合。这两个子问题都可以用递归的方式解决。
具体见下方代码:
不用比较,找出两数中的较大值和较小值。(后来面试官有提示使用加减乘除,但是我还是想不出来,因为之前没有做过这道题,虽然这道题看起来很熟悉,有时候真的需要多做算法题,没看过的题目,硬想是很难在短时间内想到)
面试完之后,我百度了一下解答,原来是要自己定义sign函数(即利用>>>31位获取得到某个数是正数还是负数),然后可以利用sign(a-b)就可以知道,如果a大于b,则运算结果是1。如果是b大,则运算结果是0。然后还可以利用异否^1,定义flip函数,得到1的否定0,0的否定1。
这样就可以通过上面的结果乘以两数本身然后相加,如果一个的系数为0,则另一个数的为1,和则系数为1的那个数。这样可以决定返回大小值了。
其中尤其值得注意的是,还需要考虑a-b的值可能会溢出,这时候就不单单至以上说得那么简单了,还需要考虑a和b的两个数之间的正负值
参考:https://blog.csdn.net/jeanphorn/article/details/42264537
https://blog.csdn.net/u010456903/article/details/48953429
具体见下方代码:
import java.util.Stack;
/**
* 多益的编程题和面试时的编程题
*
* @author zhangcanlong
* @date 2019年1月12日
*/
public class DuoyiTest {
public static void main(String[] args) {
DuoyiTest test = new DuoyiTest();
// 测试1
System.out.println("测试1都是正数");
test.findTwoNumMinAndMax(1, 100);
// 测试2
System.out.println("测试2,a负,b正");
test.findTwoNumMinAndMax(-13, 100);
// 测试3
System.out.println("测试3");
test.findTwoNumMinAndMax(-13, -48);
// 测试4(溢出情况)
System.out.println("测试4(溢出情况)");
test.findTwoNumMinAndMax(-2147483647, 2000000);
// 找出数字字符串中指定位数的最小值测试1
System.out.println("找出数字字符串中指定位数的最小值测试1:" + test.findMinNum("123450231", 2));
// 找出数字字符串中指定位数的最小值测试2
System.out.println("找出数字字符串中指定位数的最小值测试2:" + test.findMinNum("234523", 2));
// 找出数字字符串中指定位数的最小值测试3
System.out.println("找出数字字符串中指定位数的最小值测试3:" + test.findMinNum("12345231", 5));
// 找出数字字符串中指定位数的最小值测试4
System.out.println("找出数字字符串中指定位数的最小值测试4:" + test.findMinNum("12345231", 6));
}
/**
* 找出数字字符串中指定位数的最小值,例如:有字符串"1230451",要求找出两位最小的顺序组合,则结果是01,即1.
*
* 解题思路:将其转化为从长度为n的数字数组中找出m位组合即可
*
* @param str
* 要寻找的字符串
* @param m
* 指定的位数
*/
public Integer findMinNum(String str, int m) {
if (str == null || str.length() <= 1 || m >= str.length()) {
if (str == null) {
throw new RuntimeException("字符串不能为空");
}
return Integer.parseInt(str);
}
int[] ints = new int[str.length()];
for (int i = 0; i < str.length(); i++) {
ints[i] = Integer.parseInt(String.valueOf(str.charAt(i)));
}
Stack stack = new Stack<>();
Integer[] mins = new Integer[1];
combinateNum(ints, 0, m, stack, mins);
return mins[0];
}
/**
* 求数组的m位组合,递归方法
*
* @param ints 要求的数组
* @param start 开始求组合的元素下标
* @param combinateDigit 要求的组合数
* @param stack 存放一次组合的结果
* @param mins 存放m个字符值的最小值,即最终结果
*/
private void combinateNum(int[] ints, int start, int combinateDigit, Stack stack, Integer[] mins) {
if (combinateDigit <= 0) {
// 遍历获取栈,求得拼接的值的大小(这里不考虑大数范围)
int tempMin = 0;
for (int i = 0; i < stack.size(); i++) {
tempMin = tempMin + ((int) Math.pow(10, stack.size() - i - 1)) * stack.get(i);
// System.out.print(stack.get(i) + " ");
}
// System.out.println();
// 重新赋值最小值
if (mins[0] == null || mins[0] > tempMin) {
mins[0] = tempMin;
}
return;
}
if (start > ints.length - 1) {
return;
}
stack.push(ints[start]);
combinateNum(ints, start + 1, combinateDigit - 1, stack, mins);
stack.pop();
combinateNum(ints, start + 1, combinateDigit, stack, mins);
}
/**
* 不用比较,找出两个数中最大的和最小的(不考虑溢出情况)
*/
public void findTwoNumMinAndMax(int a, int b) {
int signA = sign(a - b);
int signB = flip(signA);
System.out.println("较大的数为:" + (signA * a + signB * b));
System.out.println("较小的数为:" + (signB * a + signA * b));
}
/**
* 取相反的数,如果是1,则返回0,如果是0,则返回1
*/
private int flip(int n) {
return n ^ 1;
}
/**
* 判断某个数的符号
*
* @param n
* 要判断的数
* @return 如果是正数,返回1,如果是负数返回0
*/
private int sign(int n) {
return (n >>> 31) ^ 1;
}
}