Google Kick Start 2019 C轮 第一题 Wiggle Walk 题解

题目地址:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050ff2/0000000000150aac

四个解法:

  1. 暴力模拟
  2. 使用HashMap优化,理论时间复杂度最小(好像也是并查集)
  3. (推荐)使用BitSet,实际占用空间特别小,仅仅是 2mn 个比特大小
  4. 使用HashMap实现的并查集方法,在东南西北4个方向上用并查集处理

解法1:暴力模拟

下面的代码是我写的暴力模拟办法,只能过样例,提交上去会 Runtime Error.

  1. import java.util.*;
  2. import java.io.*;
  3. public class Solution {
  4. static String input = "3" + "\n"
  5. + "5 3 6 2 3" + "\n"
  6. + "EEWNS" + "\n"
  7. + "4 3 3 1 1" + "\n"
  8. + "SESE" + "\n"
  9. + "11 5 8 3 4" + "\n"
  10. + "NEESSWWNESE" + "\n";
  11. public static void main(String[] args) {
  12. //Scanner sc = new Scanner(System.in);
  13. Scanner sc = new Scanner(new StringReader(input));
  14. int T = sc.nextInt();
  15. int[][] D = new int[128][2];
  16. D['E'] = new int[]{0, 1};
  17. D['W'] = new int[]{0, -1};
  18. D['N'] = new int[]{-1,0};
  19. D['S'] = new int[]{1,0};
  20. for (int i = 0; i < T; i++) {
  21. int N = sc.nextInt();
  22. int R = sc.nextInt();
  23. int C = sc.nextInt();
  24. int Sr = sc.nextInt();
  25. int Sc = sc.nextInt();
  26. sc.nextLine();
  27. String seq = sc.nextLine();
  28. boolean[][] map = new boolean[R + 1][C + 1];
  29. map[Sr][Sc] = true;
  30. for (int j = 0; j < N; j++) {
  31. do {
  32. Sr += D[seq.charAt(j)][0];
  33. Sc += D[seq.charAt(j)][1];
  34. } while (map[Sr][Sc] == true);
  35. map[Sr][Sc] = true;
  36. }
  37. System.out.println("Case #" + (i + 1) + ": " + Sr + " " + Sc);
  38. }
  39. }
  40. }

解法2:HashMap优化

下面是使用HashMap能过的版本,原答案来自StackExchange上的Python解法.

注意静态内部类 Point,我重写了对象的equals()方法和hashCode()方法,以便 HashMap 能正确查找对象。hashCode()方法用于计算哈希值,不重写的会采用对象内存地址作为哈希值,这是我们不希望看到的。equals()方法用于解决哈希冲突后的对象实际内容比对。

  1. import java.util.*;
  2. import java.io.*;
  3. public class Solution {
  4. static class Point {
  5. int x;
  6. int y;
  7. Point() {}
  8. Point(int xx, int yy) { x = xx; y = yy; }
  9. @Override
  10. public boolean equals(Object obj) {
  11. Point that = (Point) obj;
  12. return this.x == that.x && this.y == that.y;
  13. }
  14. @Override
  15. public int hashCode() {
  16. return x * 50000 + y;
  17. }
  18. }
  19. static HashMap<Point, Point>[] neighbors;
  20. public static void init() {
  21. neighbors = new HashMap[128];
  22. neighbors['W'] = new HashMap<Point, Point>();
  23. neighbors['E'] = new HashMap<Point, Point>();
  24. neighbors['S'] = new HashMap<Point, Point>();
  25. neighbors['N'] = new HashMap<Point, Point>();
  26. }
  27. public static Point getNeighbor(Point cur, char direction) {
  28. if (neighbors[direction].containsKey(cur)) {
  29. return neighbors[direction].get(cur);
  30. }
  31. switch(direction) {
  32. case 'W': return new Point(cur.x - 1, cur.y);
  33. case 'E': return new Point(cur.x + 1, cur.y);
  34. case 'N': return new Point(cur.x, cur.y - 1);
  35. case 'S': return new Point(cur.x, cur.y + 1);
  36. default: return null;
  37. }
  38. }
  39. public static void linkNeighbors(Point cur) {
  40. Point west = getNeighbor(cur, 'W');
  41. Point east = getNeighbor(cur, 'E');
  42. Point north = getNeighbor(cur, 'N');
  43. Point south = getNeighbor(cur, 'S');
  44. neighbors['W'].put(east, west);
  45. neighbors['E'].put(west, east);
  46. neighbors['N'].put(south, north);
  47. neighbors['S'].put(north, south);
  48. }
  49. public static void main(String[] args) {
  50. Scanner sc = new Scanner(System.in);
  51. int T = sc.nextInt();
  52. for (int i = 0; i < T; i++) {
  53. int N = sc.nextInt();
  54. int R = sc.nextInt();
  55. int C = sc.nextInt();
  56. int Sr = sc.nextInt();
  57. int Sc = sc.nextInt();
  58. sc.nextLine(); // skip \n at end of previous line
  59. String seq = sc.nextLine();
  60. init();
  61. Point cur = new Point(Sc, Sr);
  62. for (int j = 0; j < N; j++) {
  63. linkNeighbors(cur);
  64. cur = getNeighbor(cur, seq.charAt(j));
  65. }
  66. System.out.println("Case #" + (i + 1) + ": " + cur.y + " " + cur.x);
  67. }
  68. }
  69. }

解法3: BitSet

思路来源: http://codeforces.com/blog/entry/67224?#comment-513594

核心就是利用 BitSet 提供的 previousSetBit()nextSetBit() 方法,虽然这两个方法理论上是 O(n) 时间复杂度,但由于是位操作,且Java肯定做了某些特殊优化,所有不仅占用内存特别小,运行速度也快。

  1. import java.util.*;
  2. import java.io.*;
  3. public class Solution {
  4. static BitSet[] rowBitsets; // m horizontal bitset
  5. static BitSet[] colBitsets; // n vertical bitsets
  6. public static void init(int rows, int cols) {
  7. // initilize m + n bitsets
  8. rowBitsets = new BitSet[rows + 1];
  9. colBitsets = new BitSet[cols + 1];
  10. for (int i = 1; i <= rows; i++) rowBitsets[i] = new BitSet(cols + 1);
  11. for (int i = 1; i <= cols; i++) colBitsets[i] = new BitSet(rows + 1);
  12. }
  13. public static void main(String[] args) {
  14. Scanner sc = new Scanner(System.in);
  15. int T = sc.nextInt();
  16. for (int i = 0; i < T; i++) {
  17. int N = sc.nextInt();
  18. int R = sc.nextInt();
  19. int C = sc.nextInt();
  20. int Sr = sc.nextInt();
  21. int Sc = sc.nextInt();
  22. sc.nextLine(); // skip \n at end of previous line
  23. String seq = sc.nextLine();
  24. init(R, C);
  25. for (int j = 0; j < N; j++) {
  26. rowBitsets[Sr].set(Sc);
  27. colBitsets[Sc].set(Sr);
  28. switch(seq.charAt(j)) {
  29. case 'W': Sc = rowBitsets[Sr].previousClearBit(Sc); break;
  30. case 'E': Sc = rowBitsets[Sr].nextClearBit(Sc); break;
  31. case 'N': Sr = colBitsets[Sc].previousClearBit(Sr); break;
  32. case 'S': Sr = colBitsets[Sc].nextClearBit(Sr); break;
  33. default: break;
  34. }
  35. }
  36. System.out.println("Case #" + (i + 1) + ": " + Sr + " " + Sc);
  37. }
  38. }
  39. }

解法4:使用并查集

  1. import java.util.*;
  2. import java.io.*;
  3. public class Solution {
  4. static class Point {
  5. int x, y;
  6. Point(int xx, int yy) { x = xx; y = yy; }
  7. @Override
  8. public boolean equals(Object obj) {
  9. Point that = (Point) obj;
  10. return this.x == that.x && this.y == that.y;
  11. }
  12. @Override
  13. public int hashCode() {
  14. return x * 50001 + y;
  15. }
  16. }
  17. public static Point findNeighbor(HashMap<Point, Point> map, Point cur) {
  18. // 向某个方向查找
  19. if (!map.containsKey(cur) || map.get(cur).equals(cur)) {
  20. // 当前结点cur在目标方向上没有已知的邻居,返回当前结点
  21. return cur;
  22. } else {
  23. // 当前结点cur在目标方向上有个邻居,在目标方向上查找邻居的邻居,直到找到最远的邻居
  24. // 并将当前结点在目标方向上的邻居更新为最远邻居,返回最远邻居
  25. Point res = findNeighbor(map, map.get(cur));
  26. map.put(cur, res);
  27. return res;
  28. }
  29. }
  30. public static void main(String[] args) {
  31. Scanner sc = new Scanner(System.in);
  32. int T = sc.nextInt();
  33. for (int i = 0; i < T; i++) {
  34. int N = sc.nextInt();
  35. int R = sc.nextInt();
  36. int C = sc.nextInt();
  37. int Sr = sc.nextInt();
  38. int Sc = sc.nextInt();
  39. sc.nextLine(); // skip \n at end of previous line
  40. String seq = sc.nextLine();
  41. HashMap<Point, Point> mapN = new HashMap<>();
  42. HashMap<Point, Point> mapS = new HashMap<>();
  43. HashMap<Point, Point> mapW = new HashMap<>();
  44. HashMap<Point, Point> mapE = new HashMap<>();
  45. Point cur = new Point(Sr, Sc);
  46. for (int j = 0; j < N; j++) {
  47. // 实在是搞不懂这句
  48. mapN.put(new Point(cur.x + 1, cur.y), cur);
  49. mapS.put(new Point(cur.x - 1, cur.y), cur);
  50. mapW.put(new Point(cur.x, cur.y + 1), cur);
  51. mapE.put(new Point(cur.x, cur.y - 1), cur);
  52. // 更新4个点
  53. switch(seq.charAt(j)) {
  54. case 'N':
  55. Point t1 = findNeighbor(mapN, cur); // 找到当前结点的最远邻居
  56. cur = new Point(t1.x - 1, t1.y);
  57. break;
  58. case 'S':
  59. Point t2 = findNeighbor(mapS, cur); // 找到当前结点的最远邻居
  60. cur = new Point(t2.x + 1, t2.y);
  61. break;
  62. case 'E':
  63. Point t3 = findNeighbor(mapE, cur); // 找到当前结点的最远邻居
  64. cur = new Point(t3.x, t3.y + 1);
  65. break;
  66. case 'W':
  67. Point t4 = findNeighbor(mapW, cur); // 找到当前结点的最远邻居
  68. cur = new Point(t4.x, t4.y - 1);
  69. break;
  70. default: break;
  71. }
  72. System.out.println(seq.charAt(j) + " " + cur.x + " " + cur.y);
  73. }
  74. System.out.println("Case #" + (i + 1) + ": " + cur.x + " " + cur.y);
  75. }
  76. }
  77. }

Google Kick Start 2019 C轮 第一题 Wiggle Walk 题解的更多相关文章

  1. Google Kick Start Round G 2019

    Google Kick Start Round G 2019 Book Reading 暴力,没啥好说的 #include<bits/stdc++.h> using namespace s ...

  2. Google Code Jam 第一题

    通过的第一题,留做纪念,呵呵,非常简单,Africa 2010, Qualification Round: Store Credit. #include <stdio.h> #includ ...

  3. 2019阿里校招测评题,光明小学完全图最短路径问题(python实现)

    题目:光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?光明小学可以抽象成一张有N个节点的图,每两点间都有一条道路相连.光 ...

  4. May Challenge 2019 Division 2 水题讲解

    Reduce to One 这题其实蛮水的? 题意就是说: 给定一个 1~n 的序列,每次挑两个数 x y 合并,合并值为 \(x+y+xy\) ,然后求不断合并最后剩下的一个的最大值 随便搞搞发现答 ...

  5. hdu6578 2019湖南省赛D题Modulo Nine 经典dp

    目录 题目 解析 AC_Code @ 题目 第一题题意是一共有{0,1,2,3}四种数字供选择,问有多少个长度为n的序列满足所有m个条件,每个条件是说区间[L,R]内必须有恰好x个不同的数字. 第二题 ...

  6. Good Bye 2019(前五题题解)

    这套也是后来补得. 我太菜了,第三题就卡着了.想了好久才做出来,要是参加了绝对掉分. D题是人生中做完的第一道交互题,不容易. 比赛传送门 A.Card Game 题目大意:一共有n张互不相同的牌,玩 ...

  7. [算法 笔记]2014年去哪儿网 开发笔试(续)第一题BUG修正

    上一篇的blog地址为:http://www.cnblogs.com/life91/p/3313868.html 这几天又参加了一个家公司的笔试题,在最后的编程题中竟然出现了去哪儿网开发的第一题,也就 ...

  8. 《学习OpenCV》练习题第五章第一题ab

    这道题是载入一幅带有有趣纹理的图像并用不同的模板(窗口,核)大小做高斯模糊(高斯平滑),然后比较用5*5大小的窗口平滑图像两次和用11*11大小的窗口平滑图像一次是否接近相同. 先说下我的做法,a部分 ...

  9. 《学习OpenCV》练习题第四章第一题b&c

    #include <highgui.h> #include <cv.h> #pragma comment (lib,"opencv_calib3d231d.lib&q ...

随机推荐

  1. redis AbortOnConnectFail

    AbortOnConnectFail =true 服务器上停止redis service,即便后来redis服务端修好能够接通时,也不会自动连接. 所以建议设为false

  2. 地产propretie单词propretie财产

    中文名:房产财产地产 外文名:property.propretie 释义:财产.所有物等 用法:作名词. 词汇搭配动词+-等 目录 1 英文释义 2 释义例句 3 词汇搭配 4 衍生 英文释义 1. ...

  3. python基础之对象之间的交互

    面对对象编程之对象之间的交互 这是一个猫狗大战的例子 # 猫类 class Cat: def __init__(self, name, hp, attack): self.name = name # ...

  4. MongoDB(NoSQL) 非关系型数据库

    目录 简单了解 mongoDB 简单使用mongoDB 简单了解 mongoDB # NoSQL 泛指非关系型的数据库 NoSQL(NoSQL = Not Only SQL ),意即"不仅仅 ...

  5. golang代理使用proxy.cn

    golang代理使用proxy.cn,参考:https://github.com/goproxy/goproxy.cn/blob/master/README.zh-CN.md 使用方法: $ expo ...

  6. linux定时任务crontab怎样执行root命令

    在/var/spool/cron/文件夹下放置了所有定时任务文件, 1.运行crontab -u $用户名 -e会显示$用户的所有定时任务: 2.运行sudo crontab -e会显示root用户所 ...

  7. Spring Cloud Sleuth 知识点

    Spring应用在监测到Java依赖包中有sleuth和zipkin后,会自动在RestTemplate的调用过程中向HTTP请求注入追踪信息,并向Zipkin Server发送这些信息. 出处:ht ...

  8. For 32-bit BOOL is a signed char, whereas under 64-bit it is a bool.

    https://stackoverflow.com/questions/31267325/bool-with-64-bit-on-ios/31270249#31270249 Definition of ...

  9. spring:过滤器和拦截器

    过滤器:网络通信模型的会话层控制: 拦截器:事务处理的aop注入(生命周期监控). 对于Servlet Filter,官方文档中说的很好, 并且给出了常见的应用场景. A filter is an o ...

  10. 2019湖南省赛H题——概率转移&&逆矩阵

    题意 题目链接 Bobo有一个 $n+m$ 个节点的有向图,编号分别为 $1 \sim n$,他还有一个 $n$ 行 $n+m$ 列的矩阵 $P$. 如果在 $t$ 时刻他位于节点 $u(1 \leq ...