您的位置:首页 > 编程语言 > Go语言

Google-APAC2015-Addition (1)

2014-10-23 07:52 344 查看
一个在求职道路上的伪·程序猿之独白:

已经毕业快半年了,每每找工作面试的时候总会收到好人卡,现在很怕这种以"Thank you"开头的email。

之前会觉得说,自己已经把leetcode题目刷完了几遍了,cc的主要章节也刷了两遍了,为什么总是过不了on site这一面呢。后来才深刻明白Parker大神所说:并非过了test case就表明你的算法正确。现在终于明白这么一点,哪怕算法是bug free的,可能思路是不好的,过于臃肿;也可能是数据结构定义得不好,导致算法很复杂。无论怎么说,都是”缺乏经验,或者太弱“的表现。

之前还会觉得说,明明自己花了很多时间在coding上面,又是学Andrew Ng的machine learning,又是学developing a scalable app,又是学computer graphics,总之每天都很忙很累,却不见自己在找工作方面有收获。最后被鸡K、G神、天天等众位大神指出:好钢用在刀刃上。我是太过于分散自己的精力,学东西只是学皮毛学得泛,因此什么都学不好。

于是我决定先把 “ 找工作这个第一要务 ” 完成,为此,我决定认真完成两件事情:算法 + java基础知识(上次Yahoo! on site的时候就被三哥问了serialization的问题没有答上来,觉得是java的基础知识储备不足)。算法关注三件事情:leetcode + cc + google_apac ; java基础知识目前关注:马士兵老师的java视频 + 面试网站的题库。

为了克服自己的惰性,决定开始写blog来记录学习过程,不知道能够坚持多久呢。大神们求轻拍,求传授经验,要是有北美的refer也跪求,鄙人邮箱:sssjtuhuang@gmail.com。

========================================================================

先来看第一题,这道题目我先说第一次解small的test case的思路,这个思路有bug,但可以应付小的test case。

原题:google-APAC-2015-addition

Step 1 : 题目理解

直接看test case:

test case的输入有两部分,一部分是题库,比如:

a+b=3

b+c=3

c+d=3

另一部分是问题,比如:

a+c

a+d

b+c

b+d

要求用题库用来求问题。如果有解就要输出,如果无法求解就不输出,比如上面的test case输出就是:

a+d=3

b+c=3

========================================================================

Step 2: 算法

题目是一道传统数学题,可以用高斯消元来解,但是从程序角度而言,要构建一个矩阵的类感觉比较麻烦。

题目的思想是“深搜”,比如想求解a+d,可以通过(a+b)+(c+d),然后转换为b+c来求解,而b+c是已知的,所以可以知道a+d的答案。

曾经想过使用stack来维持这种“搜索”,后来发现逻辑太过混乱。Parker大神一语道破:实质上a+b可以看作一条以a, b为端点的边,边的weight就是a+b的值,要求解a + d只要找到一条从a开始从d结束的路径就可以了。但是还要满足另外一个条件就是,路径所包含的边的数目要为奇数条。

Parker大神指出这么一个test case:

如果已知题目是这样:

a+b=1

b+c=1

c+a=1

d+e=1

e+f=1

f+e=1

要求解a+f,这是找到一条从a到f的路径,但是a,b,c,d,e,f都是可以分别求解出来的。所以上面这个算法还要多增加一个逻辑判断,就是如果a到f没有路径,就转化为求a+a和f+f,然后除以2,如果a+a,和f+f两个都有解,a+f才有解,如果其中一个无解都不行。

========================================================================

Step 3: 数据结构

Edge类,包括String p1, String p2, int weight

一个Set用来存所有已知的edge,这是一个global variable

dfs的时候使用一个Set来存visited的edge(防止形成死循环),另外一个ArrayList用来存path。

========================================================================

Step 4: 细节

#1 @Override equals(Object obj) 

#2 写Edge的hashCode的时候一开始使用了:

    hash = 31 * hash + p1.hashCode();

    hash = 31 * hash + p2.hashCode();

    这个hashCode和equals方法不一致,在equals方法里面,判断是(this.p1==obj.p1 && this.p2==obj.p2) || (this.p1==obj.p2 && this.p2 == obj.p1) [这里语法不谨慎,理解意思就好]。这样如果两个对象equals了,反而得到的hashCode不一样!因此把hashCode方法写成这样就好:

   hash = p1.hashCode() + p2.hashCode(); 

   这样可以保证对称性。

========================================================================
Step 5: 代码

import java.util.*;
import java.io.*;

public class Solution {
// global variable to store the answer to questions and visited edges
private static Set<Edge> dict = new HashSet<Edge>();

public static void main(String[] args) {
File inFile = new File ("C-small-practice.in");
File outFile = new File ("C-small-practice.out");
try {
BufferedReader br = new BufferedReader(new FileReader(inFile));
BufferedWriter bw = new BufferedWriter(new FileWriter(outFile));
int T = Integer.parseInt(br.readLine());
for (int i = 1; i <= T; i++) {
dict.clear();
int N = Integer.parseInt(br.readLine());
for (int j = 0; j < N; j++) {
String s = br.readLine();
String[] parts = s.split("[\\+\\=]");
String p1 = parts[0];
String p2 = parts[1];
int wt = Integer.parseInt(parts[2]);
Edge e = new Edge(p1, p2, wt);
dict.add(e);
}
int Q = Integer.parseInt(br.readLine());
bw.write("Case #" + i + ":\n");
for (int j = 0; j < Q; j++) {
String s = br.readLine();
String[] parts = s.split("[\\+]");
String src = parts[0];
String dst = parts[1];
// begin searching the path
ArrayList<Edge> path = new ArrayList<Edge>();
HashSet<Edge> visited = new HashSet<Edge>();
if (dfs(src, dst, path, visited)) {
// create new edge and put it in the dictionary
int v = val(path);
Edge e = new Edge(src, dst, v);
dict.add(e);
bw.write(src + "+" + dst + "=" + v + "\n");
}
else {
ArrayList<Edge> path1 = new ArrayList<Edge>();
ArrayList<Edge> path2 = new ArrayList<Edge>();
HashSet<Edge> visited1 = new HashSet<Edge>();
HashSet<Edge> visited2 = new HashSet<Edge>();
boolean b1 = dfs(src, src, path1, visited1);
boolean b2 = dfs(dst, dst, path2, visited2);
if (b1 && b2) {
int v1 = val(path1);
int v2 = val(path2);
// create new edge and put it in the dictionary
Edge e1 = new Edge(src, src, v1);
dict.add(e1);
Edge e2 = new Edge(dst, dst, v2);
dict.add(e2);
Edge e = new Edge(src, dst, (v1+v2)/2);
dict.add(e);
bw.write(src + "+" + dst + "=" + (v1+v2)/2 + "\n");
}
}
}
}
bw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

/* find a path from source(src) to destination(dst) */
/* edge case: e+e, src==dst */
public static boolean dfs (String src, String dst, ArrayList<Edge> path, Set<Edge> visited) {
if (src.equals(dst) && path.size() % 2 == 1) return true; // find the path
for (Edge e : dict) {
if (visited.contains(e)) continue; // skip the duplicate edge
String p = e.contains(src);
if (p != null) {
path.add(e);
visited.add(e);
if (dfs(p, dst, path, visited)) return true;
path.remove(path.size()-1); // undo the edge
visited.remove(e);
}
}
return false;
}

/* calculate the value from source to destination */
public static int val (ArrayList<Edge> path) {
int value = 0;
for (int i = 0; i < path.size(); i++) {
int wt = path.get(i).wt;
if (i % 2 == 0) value += wt;
else value -= wt;
}
return value;
}
}

/* Edge class */
class Edge {
String p1;
String p2;
int wt;

// cons
9f35
tructor
public Edge (String p1, String p2, int wt) {
this.p1 = p1;
this.p2 = p2;
this.wt = wt;
}

// equals method
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
final Edge e = (Edge) obj;
return (p1.equals(e.p1) && p2.equals(e.p2))
|| (p2.equals(e.p1) && p1.equals(e.p2));
}

// hash code
@Override
public int hashCode() {
return p1.hashCode() + p2.hashCode();
}

// toString method
@Override
public String toString() {
return p1 + " -> " + p2 + " : " + wt;
}

// if the edge contains one point, return the other one, else return null
public String contains(String p) {
if (p1.equals(p)) return p2;
else if (p2.equals(p)) return p1;
else return null;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 google-apac