2019多益笔试编程和面试的算法题

多益的笔试题中只有一道编程题,难度中等,是《剑指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.
	 * <p>
	 * 解题思路:将其转化为从长度为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<Integer> 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<Integer> 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;
	}
}


  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值