小米2014年校园招聘笔试题目(排队问题)

1 篇文章 0 订阅
1 篇文章 0 订阅

2014年9月25日,下午两点,去参加了小米的笔试,在这里分享一下最后一道编程题目。

这道题目的意思大概是:小米有几千位员工,现在要将所有的员工排成一队,但每个人可能会提出特定的要求:要站在某些人的后面,要站在某些人的前面。当然也可以没有要求。现在给出所有员工的要求,问是否存在一种排队方式,能满足所有员工提出的排队要求。若存在,则返回一种排队方式;若不存在,则返回null。

题目给出了两个类:

类Rule的对象是一条规则,targetName是此条规则对应的那个人,isFront代表规则要求站在他的前面还是后面。

class Rule
{
	public String targetName; // 规则中的那个人
	public boolean isFront; // 要求排在这个人前面为true;要求排在这个人后面为false
}

类Rules刻画了一个人提出的一些规则,name是提出规则的那个人的名字,ArrayList中是这个人提出的规则。

class Rules
{
	public String name; // 提出规则的那个人
	ArrayList<Rule> theRules; // 该人提出的规则
}

我将这个问题转化为有向图是否存在有向回路的问题。

首先,构造一个有向图,将每个员工看作图中的一个结点,若员工A要求站在员工B的前面,则有一条有向边由A指向B;若员工A要求站在员工C的后面,则有一条边从C指向A。

然后,对图进行深度优先周游,判断是否存在有向回路。

如果存在,则不可能有满足所有规则的排队方式;

如果不存在有向回路,则有满足所有规则的排队方式,这时只需从“没有要求站在他前面”的那些结点遍历该图,按结点完成遍历的顺序加入到一个栈中,待完成整个图的遍历之后,从栈中取出结点的顺序就是一种可能的排队方式。


我写的代码如下:

package xiaomi;

//2014.9.25小米笔试,排队问题
//小米公司共有N名员工,现在要对这N名员工排序,每个员工可能有一些排序要求,如必须站在某些人后面,或必须站在某些人前面
//给出所有人的要求,问是否有一种排序,能满足所有员工的要求。若有,则返回这种排序;若没有则返回null。

import java.util.ArrayList;
import java.util.HashMap;

//排队的规则
class Rule
{
	public String targetName; // 规则中的那个人
	public boolean isFront; // 要求排在这个人前面为true;要求排在这个人后面为false
}

class Rules
{
	public String name; // 提出规则的那个人
	ArrayList<Rule> theRules; // 该人提出的规则
}

public class XiaoMi
{
	// 内部类,定义结点
	class MemNode
	{
		String memName;
		boolean isFrontNode = true; // 记录该人是否为最前面的人,即是否要求站在某人后面,或被要求站在某人后面
		ArrayList<String> afterMemName; // 记录那些要求站在memName后面的人
		String color = "white"; // 记录结点在图遍历时候的状态

		// int nodeIndex = 0; //记录node在排队中的位置,初始为0

		public MemNode(String memName, ArrayList<String> afterMemName)
		{
			this.memName = memName;
			this.afterMemName = afterMemName;
		}
	}

	// memNodes存储结点的列表
	ArrayList<MemNode> memNodes = new ArrayList<>();

	// nameMap是结点的名字到其在memNodes下标的映射
	HashMap<String, Integer> nameMap = new HashMap<>();

	// doneNode是按照结点遍历顺序存储结点的列表
	ArrayList<MemNode> doneNodes = new ArrayList<>();

	// isQueue代表是否有满足所有规则的结果,默认是存在的,如果在图的遍历中发现有向回路,则该成false
	boolean isQueue = true;

	// 建图
	void buildGraph(ArrayList<String> allMember, ArrayList<Rules> allRules)
	{
		for (int i = 0; i < allMember.size(); i++)
		{
			MemNode memNode = new MemNode(allMember.get(i), new ArrayList<String>());
			memNodes.add(memNode);
			nameMap.put(allMember.get(i), i);
		}

		for (int j = 0; j < allRules.size(); j++)
		{
			for (int k = 0; k < allRules.get(j).theRules.size(); k++)
			{
				if (allRules.get(j).theRules.get(k).isFront == true)
				{
					// 说明该人要站在某人的前面
					memNodes.get(nameMap.get(allRules.get(j).name)).afterMemName
							.add(allRules.get(j).theRules.get(k).targetName);
					memNodes.get(nameMap.get(allRules.get(j).theRules.get(k).targetName)).isFrontNode = false;

				} else if (allRules.get(j).theRules.get(k).isFront == false)
				{
					// 说明该人要站在某人后面
					memNodes.get(nameMap.get(allRules.get(j).name)).isFrontNode = false;
					memNodes.get(nameMap.get(allRules.get(j).theRules.get(k).targetName)).afterMemName
							.add(allRules.get(j).name);
				}
			}
		}
	}

	// 图的深度优先遍历
	void dfs(ArrayList<MemNode> nodes, MemNode cur)
	{
		// nodes是所有的结点数组,cur是当前结点
		cur.color = "gray";
		for (int i = 0; i < cur.afterMemName.size(); i++)
		{
			if (nodes.get(nameMap.get(cur.afterMemName.get(i))).color
					.equals("gray"))
			{
				isQueue = false;
			} else if (nodes.get(nameMap.get(cur.afterMemName.get(i))).color
					.equals("white"))
			{
				dfs(nodes, nodes.get(nameMap.get(cur.afterMemName.get(i))));
			}
		}
		cur.color = "black";
		doneNodes.add(cur);
	}

	String findQueue(ArrayList<String> allMember, ArrayList<Rules> allRules)
	{
		buildGraph(allMember, allRules);
		for (int i = 0; i < allMember.size(); i++)
		{
			if (memNodes.get(i).color == "white"
					&& memNodes.get(i).isFrontNode == true)
			{
				dfs(memNodes, memNodes.get(i));
			}
		}
		if (isQueue == true)
		{
			String res = " ";
			for (int i = doneNodes.size() - 1; i >= 0; i--)
			{
				res = res + doneNodes.get(i).memName + " ";
			}
			return res;
		} else
		{
			return null;
		}
	}

	public static void main(String[] args)
	{
		ArrayList<String> allmember = new ArrayList<>();
		allmember.add("Node-1");
		allmember.add("Node-2");
		allmember.add("Node-3");
		allmember.add("Node-4");

		Rule rule11 = new Rule();
		rule11.targetName = "Node-1";
		rule11.isFront = true;

		Rule rule12 = new Rule();
		rule12.targetName = "Node-3";
		rule12.isFront = true;

		Rule rule13 = new Rule();
		rule13.targetName = "Node-4";
		rule13.isFront = true;

		Rule rule21 = new Rule();
		rule21.targetName = "Node-1";
		rule21.isFront = true;

		Rule rule22 = new Rule();
		rule22.targetName = "Node-4";
		rule22.isFront = false;

		Rules rules1 = new Rules();
		ArrayList<Rule> therules1 = new ArrayList<>();
		rules1.theRules = therules1;

		rules1.name = "Node-2";
		rules1.theRules.add(rule11);
		rules1.theRules.add(rule12);
		rules1.theRules.add(rule13);

		Rules rules2 = new Rules();
		ArrayList<Rule> therules2 = new ArrayList<>();
		rules2.theRules = therules2;

		rules2.name = "Node-3";
		rules2.theRules.add(rule21);
		rules2.theRules.add(rule22);

		ArrayList<Rules> allrules = new ArrayList<>();
		allrules.add(rules1);
		allrules.add(rules2);
		XiaoMi xiaoMi = new XiaoMi();
		System.out.println(xiaoMi.findQueue(allmember, allrules));
		
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值