用并查集解 kick start的Wiggle Walk

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_23204557

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值