美团网2015校招研发笔试题(2014-9-11,哈尔滨哈工大站)

不足地方还请多多指教,欢迎大家多多分享


2、用O(n)的算法,实现对一组无序的字母进行从小到大排序(区分大小写),相同的字母,小写在大写前

思路:空间换时间,把52个字母映射为52个数字,并记录出现的次数,然后迭代输出


public static void main(String[] args) {
		// A=65,Z=90 a=97,z=122
		char[] src = { 'R', 'B', 'B', 'b', 'W', 'W', 'B', 'R', 'B', 'w' };
		src = sortCharsOn(src);
		for (char c : src) {
			System.out.print(c + " ");
		}
	}

	/**
	 * O(n)的时间复杂度对给定的字符数组进行排序
	 * 
	 * @param src
	 *            原数组
	 * @return 排序后的数组
	 */
	private static char[] sortCharsOn(char[] src) {
		int[] items = new int[54];// 用于保存52个字符
		char[] des = new char[src.length];

		for (int i = 0; i < src.length; i++) {
			if (src[i] < 'z' && src[i] > 'a') { // 小写对应于items中下标为偶数
				items[(src[i] - 'a') * 2]++;
			} else if (src[i] < 'Z' && src[i] > 'A') { // 大写对应于items中下标为奇数
				items[(src[i] - 'A') * 2 + 1]++;
			}
		}

		int index = 0;
		for (int i = 0; i < items.length; i++) {
			if (items[i] != 0) {// items[i],就是该字符出现的次数
				if (i % 2 == 0) {
					for (int j = 0; j < items[i]; j++) {
						des[index++] = (char) (i / 2 + 'a');// 转化成小写
					}
				} else {
					for (int j = 0; j < items[i]; j++) {
						des[index++] = (char) ((i - 1) / 2 + 'A');// 转化成大写
					}
				}
			}
		}
		return des;
	}


3、给定N个磁盘,每个磁盘大小为D[i],i=0...N-1,现在要在这N个磁盘上"顺序分配"M个分区,每个分区大小为P[j],
 j=0....M-1,顺序分配的意思是:分配一个分区P[j]时,如果当前磁盘剩余空间足够,则在当前磁盘分配;如果不够,则
  尝试下一个磁盘,直到找到一个磁盘D[i+k]可以容纳该分区,分配下一个分区P[j+1]时,则从当前磁盘D[i+k]的剩余
  空间开始分配,不在使用D[i+k]之前磁盘末分配的空间,如果这M个分区不能在这N个磁盘完全分配,则认为分配失败,请
  实现函数,is_allocable判断给定N个磁盘(数组D)和M个分区(数组P),是否会出现分配失败的情况。
  举例:磁盘为[120,120,120],分区为[60,60,80,20,80]可分配 ,如果为[60,80,80,20,80]则分配失败


public static void main(String[] args) {
		int[] d = { 120, 120, 120 };// 磁盘
//		int[] p = { 60, 60, 80, 20, 80 };// 分区
		int[] p = { 60, 80, 80, 20, 80 };// 分区

		if (is_allocable(d, p)) {
			System.out.println("分配成功");
		} else {
			System.out.println("分配失败");
		}
	}

	private static boolean is_allocable(int[] d, int[] p) {
		int pindex = 0;//记录已分配的分区
		boolean isAllocable = false;//用来记录是否分配成功
		for (int i = 0; i < d.length; i++) {//对所有磁盘遍历
			while (d[i] > 0) {//如果该磁盘还有剩余空间,就一直迭代
				if (p[pindex] <= d[i]) {//如果磁盘空间足够,就分配,否则,进入下一个磁盘
					d[i] -= p[pindex++];
					if (pindex == p.length) {//如果已分配的分区数跟传入的一值,意味着分配成功
						isAllocable = true;
						break;
					}
				} else {
					break;
				}
			}
			if (isAllocable) {
				break;
			}
		}
		return isAllocable;
	}


4、给定正整数X,定义函数A(n)=1+x+x^2+x^3+...+x^n(n为整数且>=0),已知乘运算的时间远大于加运算,
 输入x,n:如何尽可能快的求出A(n)

这题应该有更好的解决方法吧。。

public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int x = s.nextInt();
		int n = s.nextInt();

		long temp = x+1;
		for(int i=0;i<n-1;i++){
			temp = temp*x+1;
		}
		System.out.println(temp);
	}

5、请实现方法:print_rotate_matrix(int matrix,int n),来将一个n X n二维数组
 * 逆时针旋转45度后打印,例如,下图显示一个3X3的二维数组及其旋转后屏幕输出的效果
 * <br/>
 * 123 旋转45度          3                                 3
 * 456------>           2 6       屏幕输出         2 6
 * 789                       1 5 9       ----->               1 5 9
 *            4 8                                  4 8
 *                                  7                                    7
 * 
 * 思路:从右上角开始打印....

3
26
159
48
7


public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		System.out.println("请输入几维数组:");
		int n = s.nextInt();
		int [][]matrix = new int[n][n];
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				matrix[i][j]=i*n+(j+1);
			}
		}
		print_rotate_matrix(matrix,n);
	}

	private static void print_rotate_matrix(int[][] matrix, int n) {
		//a[0][2]
		//a[0][1] a[1][2]
		//a[0][0] a[1][1] a[2][2]
		//a[1][0] a[2][1]
		//a[2][0]
		int f,s;//第一维,第二维坐标
		for(int i=n-1;i>=0;i--){//打印上半部分
			f=0;
			s=i;
			while(s<n){
				System.out.print(matrix[f++][s++]);
			}
			System.out.println();
		}
		
		for(int i=1;i<n;i++){//打印下半部分
			f=i;
			s=0;
			while(f<n){
				System.out.print(matrix[f++][s++]);
			}
			System.out.println();
		}
	}


6、已知队列支持先进先出的操作(add/remove),而栈则直技先进后出的操作push/pop,请用两个队列实现栈
 先进后出的操作,希望该栈的push/pop时间复杂度尽量小。
  
  请写出push/pop的代码,需要考虑栈溢出(stackoverflow)的情况
  
  思路:顺序不一样,队列1接收的数据,由队列2来反转顺序。队列1只进,队列2只出


public class MyStack<T> {

	Queue<T> q1, q2;

	public MyStack() {
		q1 = new LinkedBlockingQueue<T>();
		q2 = new LinkedBlockingQueue<T>();
	}

	public void push(T value) {
		q1.add(value);
	}

	public T pop() {
		if(!q2.isEmpty())
			return q2.poll();
		while(!q1.isEmpty())
			q2.add(q1.poll());
		return q2.poll();
	}

}

举一反三,由两个栈实现队列:

public class MyQueue<E> {

	private Stack<E> s1, s2;

	public MyQueue() {
		s1 = new Stack<E>();
		s2 = new Stack<E>();
	}

	public int size() {
		return s1.size() + s2.size();
	}

	public void add(E value) {
		s1.push(value);
	}

	public E peek() {
		if (!s2.empty())
			s2.peek();
		while (!s1.empty())
			s2.push(s1.pop());
		return s2.peek();
	}

	public E remove() {
		if (!s2.empty())
			s2.pop();
		while (!s1.empty())
			s2.push(s1.pop());
		return null;
	}

}




7、假设有一个中央调度机,有n个相同的任务需要调度到m台服务器上去执行,由于每台服务器的配置不一样,因此服务器
 执行一个任务所花费的时间也不同。现在假设第i个服务器执行一个任务所花费的时间也不同。现在假设第i个服务器执行 一个任务需要的时间为t[i].
 例如:有2个执行机a,b,执行一个任务分别需要7min,10min,有6个任务待调度。如果平分这6个任务,即a,b各3个
 任务,则最短需要30min执行完所有。如果a分4个任务 ,b分2个任务,则最短28min执行完。 请设计调度算法,使得所有任务完成所需要的时间最短。
 输入m台服务器,每台机器处理一个任务的时间为t[i],完成n个任务,输出n个任务在m台服务器的分布。 int
 estimate_process_time(int[] t,int m,int n)


思路:用一个数组记录每台机器已执行的时间(初始为0),在调度每一个任务的时候,对每一台机器需要执行的时间进行对比(已执行的时间加上需要执行该任务的时间


public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int t[] = new int[100];
		System.out.println("请输入几台机子:");
		int m = s.nextInt();
		int i = 0;
		System.out.println("输入每台机子的时间:");
		while (m-- > 0) {
			t[i++] = s.nextInt();
		}
		System.out.println("请输入多少任务:");
		int n = s.nextInt();
		int total = estimate_process_time(t, i, n);
		System.out.println("最小需要" + total);
	}

	/**
	 * @param t 每个服务器处理的时间
	 * @param m 多少台服务器
	 * @param n 多少个任务
	 * @return
	 */
	private static int estimate_process_time(int[] t, int m, int n) {
		int total = 0;
		int k;
		int apply[] = new int[m];// 记录m个机器已执行的时间,初始全为0
		for (int i = 0; i < n; i++) {// 遍历n个任务
			int tmp = apply[0] + t[0];//用来记录分配该任务给第j个机器所需要的时间(已执行的时间加需要执行的时间)
			k = 0;
			for (int j = 1; j < m; j++) {// 遍历m个机器
				if (tmp > apply[j] + t[j]) {//遍历所有机器,选择时间最短的
					tmp = apply[j] + t[j];
					k = j;// 把该任务分配给第j个机器
				}
			}
			apply[k] += t[k];
			total = tmp;
		}
		for (int i = 0; i < m; i++) {
			System.out.println("第"+(i+1)+"台服务器有"+apply[i]/t[i]+"个任务,运行了"+apply[i]);
		}
		return total;
	}



8、n(1,2,3.....n)个元素有N!个不同的排列,将这n!个数按字典序排列,并编号0,1...n!-1,每个排号为其字典序的值,如n=3时,字典排序为123,132,213,231,312,321,这6个数的字典序分别为0,1,2,3,4,5.,现给定n,请输出字典序为k 的排列(0<=k<n!)

public static void main(String[] args) {
		long l1 = System.currentTimeMillis();
		System.out.println("请输入要对前n个数字进行排列:");
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
		System.out.println("请输入需要的第K个:");
		int k = s.nextInt();
		int[] arry = new int[n];
		for (int i = 0; i < arry.length; i++) {
			arry[i] = i + 1;
		}
//		System.out.println(Arrays.toString(getInt(arry)));
		do {
			if (k == 0){
				System.out.println(Arrays.toString(getInt(arry)));
				break;
			}
			k--;
		} while (next(arry));
		long l2 = System.currentTimeMillis();
		System.out.print("共耗时" + (l2 - l1) + "耗秒");
	}

	private static int[] getInt(int[] arry) {
		int[] arry1 = new int[arry.length];
		System.arraycopy(arry, 0, arry1, 0, arry.length);
		return arry1;
	}

	private static boolean next(int[] arry) {
		int pos1 = -1;
		int pos2 = -1;
		// 从右到左,找到第一个比右边小的数,记录位置pos1
		for (int i = arry.length - 1; i > 0; i--) {
			if (arry[i - 1] < arry[i]) {
				pos1 = i - 1;
				break;
			}
		}
		if (pos1 < 0) {
			return false;
		}
		// 在pos1位置后的数字中找出比它大的数中最小的一个,然后交换位置,在逆转
		for (int i = arry.length - 1; i > pos1; i--) {
			if (arry[i] > arry[pos1]) {
				pos2 = i;
				swap(arry, pos2, pos1);
				reserve(arry, pos1 + 1, arry.length - 1);
				break;
			}
		}
		if (pos2 < 0) {
			return false;
		}
		return true;
	}

	/**
	 * 
	 * 逆转数组中第i个到第j个的数,比如数组为123,i=0,j=2,则逆转为321
	 * 
	 * @param arry
	 * @param i
	 * @param j
	 */
	private static void reserve(int[] arry, int i, int j) {
		for (; i <= j; i++, j--) {
			swap(arry, i, j);
		}
	}

	/**
	 * 交换一个数组中第i个和第j个数的值
	 * 
	 * @param array
	 * @param i
	 * @param j
	 */
	private static void swap(int[] array, int i, int j) {
		int temp = array[j];
		array[j] = array[i];
		array[i] = temp;
	}





评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值