kick start c轮第一题Wiggle Walk,受此处的启发,发现用可4个并查集来解,注意两点:
1,我是用map而非数组来实现并查集的,因为担心上次内存溢出的问题重现;
2,普通并查集不强调根的位置,此处不相同,根的位置代表了此段的极限,合并时应注意。
ac的代码在Attempt 36 Jul 28 2019, 01:09
private Point findRoot(Map<Point, Point> tree, Point p) {//union set
Point nextp = tree.get(p);
if (p.equals(nextp))
return p;
Point root = findRoot(tree, nextp);
tree.put(p, root);
return root;
}
全部代码:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
class Point {
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + "]";
}
}
public class Solution {
boolean systemIO = true;
public void solve() {
int T = in.nextInt();
for (int t = 1; t <= T; ++t) {
int N = in.nextInt();
int R = in.nextInt();
int C = in.nextInt();
int x = in.nextInt();
int y = in.nextInt();
Point p = new Point(x, y);
int[] dy = { 0, 1, 0, -1 };
int[] dx = { -1, 0, 1, 0 }; // N E S W
// 4 union sets
Map<Point, Point>[] dirTrees = new Map[4];
for (int i = 0; i < 4; ++i) {
dirTrees[i] = new HashMap<Point, Point>();
dirTrees[i].put(p, p);
}
String instr = in.next();
Point newp = null;
for (int command = 0; command < N; ++command) {
char ins = instr.charAt(command);
int dir = 0;
if (ins == 'E') {
dir = 1;
}else if(ins=='S')
dir = 2;
else if(ins=='W')
dir = 3;
Map<Point, Point> dirTree = dirTrees[dir];
Map<Point, Point> antidirTree = dirTrees[(dir + 2) % 4];
Point root = findRoot(dirTree, p);
newp = new Point(root.x + dx[dir], root.y + dy[dir]);
for (int i = 0; i < 4; ++i) {
dirTrees[i].put(newp, newp);
}
Point neighbor = new Point(root.x + 2*dx[dir], root.y + 2*dy[dir]);
if (dirTree.containsKey(neighbor)) {// merge
Point neighboroot = findRoot(dirTree, neighbor);
dirTree.put(root, neighboroot);
dirTree.put(newp, neighboroot);
antidirTree.put(neighbor, root);
antidirTree.put(newp, root);
} else { // expand
dirTree.put(root, newp);
antidirTree.put(newp, root);
}
Point upNewp = new Point(newp.x + dx[(dir + 3) % 4], newp.y + dy[(dir + 3) % 4]);
Point dowNewp = new Point(newp.x + dx[(dir + 1) % 4], newp.y + dy[(dir + 1) % 4]);
Map<Point, Point> clock90Tree = dirTrees[(dir + 1) % 4];
Map<Point, Point> anticlock90Tree = dirTrees[(dir + 3) % 4];
if (!clock90Tree.containsKey(upNewp) && !clock90Tree.containsKey(dowNewp)) {// new 1
clock90Tree.put(newp, newp);
anticlock90Tree.put(newp, newp);
} else if (clock90Tree.containsKey(upNewp) && clock90Tree.containsKey(dowNewp)) {// merge
Point southroot = findRoot(clock90Tree, dowNewp);
Point northroot = findRoot(anticlock90Tree, upNewp);
clock90Tree.put(newp, southroot);
anticlock90Tree.put(newp, northroot);
clock90Tree.put(upNewp, southroot);
anticlock90Tree.put(dowNewp, northroot);
} else if (clock90Tree.containsKey(upNewp)) { // expand up
Point northroot = findRoot(anticlock90Tree, upNewp);
anticlock90Tree.put(newp, northroot);
clock90Tree.put(upNewp, newp);
} else { // expand down
Point southroot = findRoot(clock90Tree, dowNewp);
clock90Tree.put(newp, southroot);
anticlock90Tree.put(dowNewp, newp);
}
p = newp;
}
out.println("Case #" + t + ": " + newp.x + " " + newp.y);
}
}
private Point findRoot(Map<Point, Point> tree, Point p) {//union set
Point nextp = tree.get(p);
if (p.equals(nextp))
return p;
Point root = findRoot(tree, nextp);
tree.put(p, root);
return root;
}
public void run() {
try {
if (systemIO) {
in = new FastScanner(System.in);
out = new PrintWriter(System.out);
} else {
in = new FastScanner(new File("C:\\Users\\sdh\\Desktop/input.txt"));
out = new PrintWriter(new File("C:/Users/sdh/Desktop/output.txt"));
}
solve();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class FastScanner {
BufferedReader br;
StringTokenizer st;
FastScanner(File f) {
try {
br = new BufferedReader(new FileReader(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
FastScanner(InputStream f) {
br = new BufferedReader(new InputStreamReader(f));
}
String nextLine() {
try {
return br.readLine();
} catch (IOException e) {
return null;
}
}
String next() {
while (st == null || !st.hasMoreTokens()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
double nextDouble() {
return Double.parseDouble(next());
}
}
FastScanner in;
PrintWriter out;
public static void main(String[] arg) {
new Solution().run();
}
}
此题应该是leetcode上longest-consecutive-sequence的强化版。附上leetcode题我的ac代码:
class Solution {
Map<Integer,Integer> startTree = new HashMap<Integer,Integer>();
Map<Integer,Integer> endTree = new HashMap<Integer,Integer>();
public int longestConsecutive(int[] nums) {
int max = 0;
for(int num : nums){
if(startTree.containsKey(num))
continue;
startTree.put(num,num);
endTree.put(num,num);
boolean linkleft = startTree.containsKey(num-1);
boolean linkr = startTree.containsKey(num+1);
max = Math.max(max,1);
if(linkleft){
int region = union(num-1,num);
max = Math.max(max,region);
}
if(linkr){
int region = union(num,num+1);
max = Math.max(max,region);
}
}
return max;
}
int getRoot(Map<Integer,Integer> tree, int from){
Integer key = tree.get(from);
if(key==from)
return key;
else{
Integer root = getRoot(tree,key);
tree.put(from,root);
return root;
}
}
int union(int left,int r){
int leftmost = getRoot(startTree,left);
int rmost = getRoot(endTree,r);
startTree.put(r,leftmost);
endTree.put(left,rmost);
return rmost-leftmost+1;
}
}
leetcode此题也可参考这种解法:https://leetcode.com/problems/longest-consecutive-sequence/discuss/41062/My-Java-Solution-using-UnionFound。 作者没有用hashmap,而是值的索引来建立tree
kickstart E轮第一题Cherries Mesh 更是典型的并查集题。Attempt3为我最终全部ac的代码。其中关键处的可复用代码是
int r1 = findroot(tree,p1);
int r2 = findroot(tree,p2);
if(r1!=r2)
tree[r1] = r2;
合并,以及带压缩路径的找根:
int findroot(int[] tree ,int x) {
if(tree[x]==-1)
return x;
int tmp = findroot(tree,tree[x]);
tree[x] = tmp;
return tmp;
}