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.

import java.util.*;
import java.io.*;
public class Solution {
static String input = "3" + "\n"
+ "5 3 6 2 3" + "\n"
+ "EEWNS" + "\n"
+ "4 3 3 1 1" + "\n"
+ "SESE" + "\n"
+ "11 5 8 3 4" + "\n"
+ "NEESSWWNESE" + "\n"; public static void main(String[] args) {
//Scanner sc = new Scanner(System.in);
Scanner sc = new Scanner(new StringReader(input));
int T = sc.nextInt();
int[][] D = new int[128][2];
D['E'] = new int[]{0, 1};
D['W'] = new int[]{0, -1};
D['N'] = new int[]{-1,0};
D['S'] = new int[]{1,0};
for (int i = 0; i < T; i++) {
int N = sc.nextInt();
int R = sc.nextInt();
int C = sc.nextInt();
int Sr = sc.nextInt();
int Sc = sc.nextInt();
sc.nextLine();
String seq = sc.nextLine();
boolean[][] map = new boolean[R + 1][C + 1];
map[Sr][Sc] = true; for (int j = 0; j < N; j++) {
do {
Sr += D[seq.charAt(j)][0];
Sc += D[seq.charAt(j)][1];
} while (map[Sr][Sc] == true);
map[Sr][Sc] = true;
}
System.out.println("Case #" + (i + 1) + ": " + Sr + " " + Sc);
}
}
}

解法2:HashMap优化

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

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

import java.util.*;
import java.io.*;
public class Solution { static class Point {
int x;
int y;
Point() {}
Point(int xx, int yy) { x = xx; y = yy; }
@Override
public boolean equals(Object obj) {
Point that = (Point) obj;
return this.x == that.x && this.y == that.y;
}
@Override
public int hashCode() {
return x * 50000 + y;
}
}
static HashMap<Point, Point>[] neighbors; public static void init() {
neighbors = new HashMap[128];
neighbors['W'] = new HashMap<Point, Point>();
neighbors['E'] = new HashMap<Point, Point>();
neighbors['S'] = new HashMap<Point, Point>();
neighbors['N'] = new HashMap<Point, Point>();
} public static Point getNeighbor(Point cur, char direction) {
if (neighbors[direction].containsKey(cur)) {
return neighbors[direction].get(cur);
}
switch(direction) {
case 'W': return new Point(cur.x - 1, cur.y);
case 'E': return new Point(cur.x + 1, cur.y);
case 'N': return new Point(cur.x, cur.y - 1);
case 'S': return new Point(cur.x, cur.y + 1);
default: return null;
}
} public static void linkNeighbors(Point cur) {
Point west = getNeighbor(cur, 'W');
Point east = getNeighbor(cur, 'E');
Point north = getNeighbor(cur, 'N');
Point south = getNeighbor(cur, 'S');
neighbors['W'].put(east, west);
neighbors['E'].put(west, east);
neighbors['N'].put(south, north);
neighbors['S'].put(north, south);
} public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
for (int i = 0; i < T; i++) {
int N = sc.nextInt();
int R = sc.nextInt();
int C = sc.nextInt();
int Sr = sc.nextInt();
int Sc = sc.nextInt();
sc.nextLine(); // skip \n at end of previous line
String seq = sc.nextLine(); init();
Point cur = new Point(Sc, Sr);
for (int j = 0; j < N; j++) {
linkNeighbors(cur);
cur = getNeighbor(cur, seq.charAt(j));
} System.out.println("Case #" + (i + 1) + ": " + cur.y + " " + cur.x);
}
}
}

解法3: BitSet

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

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

import java.util.*;
import java.io.*;
public class Solution { static BitSet[] rowBitsets; // m horizontal bitset
static BitSet[] colBitsets; // n vertical bitsets public static void init(int rows, int cols) {
// initilize m + n bitsets
rowBitsets = new BitSet[rows + 1];
colBitsets = new BitSet[cols + 1];
for (int i = 1; i <= rows; i++) rowBitsets[i] = new BitSet(cols + 1);
for (int i = 1; i <= cols; i++) colBitsets[i] = new BitSet(rows + 1);
} public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
for (int i = 0; i < T; i++) {
int N = sc.nextInt();
int R = sc.nextInt();
int C = sc.nextInt();
int Sr = sc.nextInt();
int Sc = sc.nextInt();
sc.nextLine(); // skip \n at end of previous line
String seq = sc.nextLine(); init(R, C);
for (int j = 0; j < N; j++) {
rowBitsets[Sr].set(Sc);
colBitsets[Sc].set(Sr); switch(seq.charAt(j)) {
case 'W': Sc = rowBitsets[Sr].previousClearBit(Sc); break;
case 'E': Sc = rowBitsets[Sr].nextClearBit(Sc); break;
case 'N': Sr = colBitsets[Sc].previousClearBit(Sr); break;
case 'S': Sr = colBitsets[Sc].nextClearBit(Sr); break;
default: break;
}
} System.out.println("Case #" + (i + 1) + ": " + Sr + " " + Sc);
}
}
}

解法4:使用并查集

import java.util.*;
import java.io.*;
public class Solution { static class Point {
int x, y;
Point(int xx, int yy) { x = xx; y = yy; }
@Override
public boolean equals(Object obj) {
Point that = (Point) obj;
return this.x == that.x && this.y == that.y;
}
@Override
public int hashCode() {
return x * 50001 + y;
}
} public static Point findNeighbor(HashMap<Point, Point> map, Point cur) {
// 向某个方向查找
if (!map.containsKey(cur) || map.get(cur).equals(cur)) {
// 当前结点cur在目标方向上没有已知的邻居,返回当前结点
return cur;
} else {
// 当前结点cur在目标方向上有个邻居,在目标方向上查找邻居的邻居,直到找到最远的邻居
// 并将当前结点在目标方向上的邻居更新为最远邻居,返回最远邻居
Point res = findNeighbor(map, map.get(cur));
map.put(cur, res);
return res;
}
} public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
for (int i = 0; i < T; i++) {
int N = sc.nextInt();
int R = sc.nextInt();
int C = sc.nextInt();
int Sr = sc.nextInt();
int Sc = sc.nextInt();
sc.nextLine(); // skip \n at end of previous line
String seq = sc.nextLine(); HashMap<Point, Point> mapN = new HashMap<>();
HashMap<Point, Point> mapS = new HashMap<>();
HashMap<Point, Point> mapW = new HashMap<>();
HashMap<Point, Point> mapE = new HashMap<>();
Point cur = new Point(Sr, Sc);
for (int j = 0; j < N; j++) {
// 实在是搞不懂这句
mapN.put(new Point(cur.x + 1, cur.y), cur);
mapS.put(new Point(cur.x - 1, cur.y), cur);
mapW.put(new Point(cur.x, cur.y + 1), cur);
mapE.put(new Point(cur.x, cur.y - 1), cur);
// 更新4个点
switch(seq.charAt(j)) {
case 'N':
Point t1 = findNeighbor(mapN, cur); // 找到当前结点的最远邻居
cur = new Point(t1.x - 1, t1.y);
break;
case 'S':
Point t2 = findNeighbor(mapS, cur); // 找到当前结点的最远邻居
cur = new Point(t2.x + 1, t2.y);
break;
case 'E':
Point t3 = findNeighbor(mapE, cur); // 找到当前结点的最远邻居
cur = new Point(t3.x, t3.y + 1);
break;
case 'W':
Point t4 = findNeighbor(mapW, cur); // 找到当前结点的最远邻居
cur = new Point(t4.x, t4.y - 1);
break;
default: break;
}
System.out.println(seq.charAt(j) + " " + cur.x + " " + cur.y);
} System.out.println("Case #" + (i + 1) + ": " + cur.x + " " + cur.y);
}
}
}

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. spark源码阅读--shuffle读过程源码分析

    shuffle读过程源码分析 上一篇中,我们分析了shuffle在map阶段的写过程.简单回顾一下,主要是将ShuffleMapTask计算的结果数据在内存中按照分区和key进行排序,过程中由于内存限 ...

  2. .Net Core 遇到 “'windows-1252' is not a supported encoding name.”

    最近用 iTextSharp 拆分 Pdf 文档 加水印的时候遇到错误: 'windows-1252' is not a supported encoding name. For informatio ...

  3. Delphi - ShellExecute资料

    Windows官方资料: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea#p ...

  4. BBC评出的100本最具影响力经典书籍

    今年,英国广播公司(BBC)邀请全球35个国家共108名文化人士,参与其发起的“影响思维和历史的100部虚构故事”的推荐,要求每人最多提名 5 部作品,这些作品最终将根据提名总量排名. 该活动经过一个 ...

  5. python实现系统调用cmd命令的模块---subprocess模块

    如果要python实现系统命令或者调用脚本,python中可以利用os或者subprocess模块实现: 一.os模块: # coding:utf-8 command = os.system('net ...

  6. Oracle数据库中 =:和 :=

    =:应该相当于 a = :b 表明b是个绑定变量,需要执行时进行变量绑定. 变量绑定:变量绑定是指在sql语句的条件中使用变量而不是常量.比如shared pool里有两条sql语句,select * ...

  7. 《linux就该这么学》课堂笔记11 LVM、防火墙初识

    1.常用的LVM部署命令 功能/命令 物理卷管理 卷组管理 逻辑卷管理 扫描 pvscan vgscan lvscan 建立 pvcreate vgcreate lvcreate 显示 pvdispl ...

  8. 业精于勤荒于嬉---Go的GORM查询

    查询 //通过主键查询第一条记录 db.First(&user) //// SELECT * FROM users ORDER BY id LIMIT 1; // 随机取一条记录 db.Tak ...

  9. C程序回顾

    1.字符串操作 C中,字符串以一维数组的方式存储.字符串结束标志\0,可用scanf("%s",c);输入,以空格作为输入字符串之间的分隔符. 字符串处理函数:puts(str); ...

  10. 《快活帮》第九次团队作业:Beta冲刺与验收准备

    项目 内容 这个作业属于哪个课程 2016计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 实验十三 团队作业9:BETA冲刺与团队项目验收 团队名称 快活帮 作业学习目标 (1)掌 ...