Google Kick Start 2019 C轮 第一题 Wiggle Walk 题解
Google Kick Start 2019 C轮 第一题 Wiggle Walk 题解
题目地址:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050ff2/0000000000150aac
四个解法:
- 暴力模拟
 - 使用HashMap优化,理论时间复杂度最小(好像也是并查集)
 - (推荐)使用BitSet,实际占用空间特别小,仅仅是 2mn 个比特大小
 - 使用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 题解的更多相关文章
- Google Kick Start Round G 2019
		
Google Kick Start Round G 2019 Book Reading 暴力,没啥好说的 #include<bits/stdc++.h> using namespace s ...
 - Google Code Jam 第一题
		
通过的第一题,留做纪念,呵呵,非常简单,Africa 2010, Qualification Round: Store Credit. #include <stdio.h> #includ ...
 - 2019阿里校招测评题,光明小学完全图最短路径问题(python实现)
		
题目:光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?光明小学可以抽象成一张有N个节点的图,每两点间都有一条道路相连.光 ...
 - May Challenge 2019 Division 2 水题讲解
		
Reduce to One 这题其实蛮水的? 题意就是说: 给定一个 1~n 的序列,每次挑两个数 x y 合并,合并值为 \(x+y+xy\) ,然后求不断合并最后剩下的一个的最大值 随便搞搞发现答 ...
 - hdu6578 2019湖南省赛D题Modulo Nine 经典dp
		
目录 题目 解析 AC_Code @ 题目 第一题题意是一共有{0,1,2,3}四种数字供选择,问有多少个长度为n的序列满足所有m个条件,每个条件是说区间[L,R]内必须有恰好x个不同的数字. 第二题 ...
 - Good Bye 2019(前五题题解)
		
这套也是后来补得. 我太菜了,第三题就卡着了.想了好久才做出来,要是参加了绝对掉分. D题是人生中做完的第一道交互题,不容易. 比赛传送门 A.Card Game 题目大意:一共有n张互不相同的牌,玩 ...
 - [算法 笔记]2014年去哪儿网 开发笔试(续)第一题BUG修正
		
上一篇的blog地址为:http://www.cnblogs.com/life91/p/3313868.html 这几天又参加了一个家公司的笔试题,在最后的编程题中竟然出现了去哪儿网开发的第一题,也就 ...
 - 《学习OpenCV》练习题第五章第一题ab
		
这道题是载入一幅带有有趣纹理的图像并用不同的模板(窗口,核)大小做高斯模糊(高斯平滑),然后比较用5*5大小的窗口平滑图像两次和用11*11大小的窗口平滑图像一次是否接近相同. 先说下我的做法,a部分 ...
 - 《学习OpenCV》练习题第四章第一题b&c
		
#include <highgui.h> #include <cv.h> #pragma comment (lib,"opencv_calib3d231d.lib&q ...
 
随机推荐
- spark任务运行完成后在driver端的处理逻辑
			
回顾 上一篇,我们分析了了任务在executor端的运行流程,任务运行结束后,在Executor.launchTask方法最后,通过调用execBackend.statusUpdate方法将任务结果以 ...
 - grid网格布局——色子布局
			
一.基本概念 样式 含义 grid-area 定义名称 grid-auto-columns 定义列数 grid-auto-flow 定义单元格流动方向(想象水流的样子) grid-auto-rows ...
 - 面试题:什么叫2B树
			
在B树的基础上,每个节点有两个域,且他们是有顺序的,在层次上的又满足二叉排序树的性质
 - vimplus基本操作
			
1. YouCompleteMe按tab键,自动补全 2. vim-commentary添加注释,以及取消注释gcc 注释当前行(普通模式)gc 可视模式下,注释当前选中的部分gcu 撤销上一次注释的 ...
 - Git 冲突:Your local changes would be overwritten by merge. Commit, stash or revert them to proceed.
			
解决方案有三种: 1,无视,直接commit自己的代码. git commit -m "your msg" 2,stash stash翻译为“隐藏”,如下操作: git stash ...
 - kuangbin专题专题四 MPI Maelstrom POJ - 1502
			
题目链接:https://vjudge.net/problem/POJ-1502 dijkstra板子题,题目提供下三角情况,不包含正对角线,因为有题意都为0,处理好输入,就是一个很水的题. #inc ...
 - position 的absolute会使display变成inline-block
			
position:absolute和float会隐式地改变display类型,不论之前什么类型的元素(display:none除外), 只要设置了position:absolute. float中任意 ...
 - js创建对象的三种方式
			
<script> //创建对象的三种方式 // 1.利用对象字面量(传说中的大括号)创建对象 var obj1 = { uname: 'ash', age: 18, sex: " ...
 - ORM概述(对象关系映射)
			
ORM概述: ORM(Object-Relational Mapping)表示对象关系映射.在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中.只要有一套程序能够做到加你对象与数据库 ...
 - alpha冲刺事后诸葛亮(团队)
			
alpha冲刺事后诸葛亮(团队) 课程名称:软件工程1916|W(福州大学) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标:完成Alpha冲刺的事后诸葛亮 团队队员 队员学号 ...